Ejemplo n.º 1
0
    def __init__(self):
        tester.GASPRICE = 0
        tester.STARTGAS = long(6.7 * 10**7)
        config_metropolis['GASLIMIT_ADJMAX_FACTOR'] = .000000000001
        config_metropolis['GENESIS_GAS_LIMIT'] = 2**60
        config_metropolis['MIN_GAS_LIMIT'] = 2**60
        config_metropolis['BLOCK_GAS_LIMIT'] = 2**60

        for a in range(10):
            tester.base_alloc[getattr(tester, 'a%i' % a)] = {'balance': 10**24}

        self.chain = Chain(env=Env(config=config_metropolis))
        self.contracts = {}
        self.testerAddress = self.generateTesterMap('a')
        self.testerKey = self.generateTesterMap('k')
        self.testerAddressToKey = dict(zip(self.testerAddress.values(), self.testerKey.values()))
        if path.isfile('./allFiredEvents'):
            remove_file('./allFiredEvents')
        self.relativeContractsPath = '../source/contracts'
        self.relativeTestContractsPath = 'solidity_test_helpers'
        self.externalContractsPath = '../source/contracts/external'
        self.coverageMode = pytest.config.option.cover
        self.subFork = pytest.config.option.subFork
        if self.coverageMode:
            self.chain.head_state.log_listeners.append(self.writeLogToFile)
            self.relativeContractsPath = '../coverageEnv/contracts'
            self.relativeTestContractsPath = '../coverageEnv/solidity_test_helpers'
            self.externalContractsPath = '../coverageEnv/contracts/external'
Ejemplo n.º 2
0
 def resetToSnapshot(self, snapshot):
     if not 'state' in snapshot: raise "snapshot is missing 'state'"
     if not 'contracts' in snapshot: raise "snapshot is missing 'contracts'"
     self.chain = Chain(genesis=snapshot['state'], env=Env(config=config_metropolis))
     self.contracts = {}
     for contractName in snapshot['contracts']:
         contract = snapshot['contracts'][contractName]
         self.contracts[contractName] = ABIContract(self.chain, contract['translator'], contract['address'])
Ejemplo n.º 3
0
 def resetToSnapshot(self, snapshot):
     if not 'state' in snapshot: raise "snapshot is missing 'state'"
     if not 'contracts' in snapshot: raise "snapshot is missing 'contracts'"
     self.chain = Chain(genesis=snapshot['state'], env=Env(config=config_metropolis))
     if self.coverageMode:
         self.chain.head_state.log_listeners.append(self.writeLogToFile)
     self.contracts = {}
     for contractName in snapshot['contracts']:
         contract = snapshot['contracts'][contractName]
         self.contracts[contractName] = ABIContract(self.chain, contract['translator'], contract['address'])
Ejemplo n.º 4
0
    def __init__(self):
        tester.GASPRICE = 0
        config_metropolis['GASLIMIT_ADJMAX_FACTOR'] = .000000000001
        config_metropolis['GENESIS_GAS_LIMIT'] = 2**60
        config_metropolis['MIN_GAS_LIMIT'] = 2**60
        config_metropolis['BLOCK_GAS_LIMIT'] = 2**60

        for a in range(10):
            tester.base_alloc[getattr(tester, 'a%i' % a)] = {'balance': 10**24}

        self.chain = Chain(env=Env(config=config_metropolis))
        self.contracts = {}
        self.testerAddress = self.generateTesterMap('a')
        self.testerKey = self.generateTesterMap('k')
Ejemplo n.º 5
0
    def __init__(self):
        tester.GASPRICE = 0
        tester.STARTGAS = long(6.7 * 10**7)
        config_metropolis['GASLIMIT_ADJMAX_FACTOR'] = .000000000001
        config_metropolis['GENESIS_GAS_LIMIT'] = 2**60
        config_metropolis['MIN_GAS_LIMIT'] = 2**60
        config_metropolis['BLOCK_GAS_LIMIT'] = 2**60

        for a in range(10):
            tester.base_alloc[getattr(tester, 'a%i' % a)] = {'balance': 10**24}

        self.chain = Chain(env=Env(config=config_metropolis))
        self.contracts = {}
        self.testerAddress = self.generateTesterMap('a')
        self.testerKey = self.generateTesterMap('k')
        self.testerAddressToKey = dict(zip(self.testerAddress.values(), self.testerKey.values()))
        if path.isfile('./allFiredEvents'):
            remove_file('./allFiredEvents')
        self.relativeContractsPath = '../source/contracts'
        self.relativeTestContractsPath = 'solidity_test_helpers'
        self.coverageMode = pytest.config.option.cover
        if self.coverageMode:
            self.chain.head_state.log_listeners.append(self.writeLogToFile)
            self.relativeContractsPath = '../coverageEnv/contracts'
            self.relativeTestContractsPath = '../coverageEnv/solidity_test_helpers'
Ejemplo n.º 6
0
 def resetToSnapshot(self, snapshot):
     if not 'state' in snapshot: raise "snapshot is missing 'state'"
     if not 'contracts' in snapshot: raise "snapshot is missing 'contracts'"
     self.chain = Chain(genesis=snapshot['state'], env=Env(config=config_metropolis))
     if self.coverageMode:
         self.chain.head_state.log_listeners.append(self.writeLogToFile)
     self.contracts = {}
     for contractName in snapshot['contracts']:
         contract = snapshot['contracts'][contractName]
         self.contracts[contractName] = ABIContract(self.chain, contract['translator'], contract['address'])
Ejemplo n.º 7
0
def init_contracts(nodes):
    result = dict()
    tester_state = Chain()
    for address, contract in CONTRACTS.iteritems():
        contract_path = path.join(CONTRACTS_DIR, contract['file'])
        simple_compiled = compile_file(contract_path)
        simple_data = solidity_get_contract_data(
            simple_compiled,
            contract_path,
            contract['name'],
        )

        ct = ContractTranslator(simple_data['abi'])
        if (address == '0x00000000000000000000000000000000013241a3'):
            extra = (ct.encode_constructor_arguments([nodes[address]]) if nodes[address] else b'')
        else:
            extra = (ct.encode_constructor_arguments([nodes[address][0], nodes[address][1]]) if nodes[address] else b'')
        print(binascii.hexlify(simple_data['bin'] + extra))
        abi_address = tester_state.contract(simple_data['bin'] + extra)
        tester_state.mine()
        account = tester_state.chain.state.account_to_dict(abi_address)
        result[address] = {'code': account['code'], 'storage': account['storage'], 'nonce': account['nonce']}
    return result
Ejemplo n.º 8
0
def test_abicontract_interface():
    """ Test for issue #370. """
    tester_state = Chain()

    contract_path = path.join(CONTRACTS_DIR, 'simple_contract.sol')
    contract_name = 'Simple'
    simple_compiled = compile_file(contract_path)
    simple_data = solidity_get_contract_data(
        simple_compiled,
        contract_path,
        contract_name,
    )
    simple_address = tester_state.contract(simple_data['bin'])

    # ABIContract class must accept json_abi
    abi_json = json.dumps(simple_data['abi']).encode('utf-8')

    abi = ABIContract(
        _chain=tester_state,
        _abi=abi_json,
        address=simple_address,
    )

    assert abi.test() == 1  # pylint: disable=no-member
Ejemplo n.º 9
0
class ContractsFixture:
    signatures = {}
    compiledCode = {}

    ####
    #### Static Methods
    ####

    @staticmethod
    def ensureCacheDirectoryExists():
        if not path.exists(COMPILATION_CACHE):
            makedirs(COMPILATION_CACHE)

    def generateSignature(self, relativeFilePath):
        ContractsFixture.ensureCacheDirectoryExists()
        filename = path.basename(relativeFilePath)
        name = path.splitext(filename)[0]
        outputPath = path.join(COMPILATION_CACHE,  name + 'Signature')
        lastCompilationTime = path.getmtime(outputPath) if path.isfile(outputPath) else 0
        if path.getmtime(relativeFilePath) > lastCompilationTime:
            print('generating signature for ' + name)
            extension = path.splitext(filename)[1]
            signature = None
            if extension == '.sol':
                signature = self.compileSolidity(relativeFilePath)['abi']
            else:
                raise
            with open(outputPath, mode='w') as file:
                json_dump(signature, file)
        else:
            pass#print('using cached signature for ' + name)
        with open(outputPath, 'r') as file:
            signature = json_load(file)
        return(signature)

    def getCompiledCode(self, relativeFilePath):
        filename = path.basename(relativeFilePath)
        name = path.splitext(filename)[0]
        if name in ContractsFixture.compiledCode:
            return ContractsFixture.compiledCode[name]
        dependencySet = set()
        self.getAllDependencies(relativeFilePath, dependencySet)
        ContractsFixture.ensureCacheDirectoryExists()
        compiledOutputPath = path.join(COMPILATION_CACHE, name)
        lastCompilationTime = path.getmtime(compiledOutputPath) if path.isfile(compiledOutputPath) else 0
        needsRecompile = False
        for dependencyPath in dependencySet:
            if (path.getmtime(dependencyPath) > lastCompilationTime):
                needsRecompile = True
                break
        if (needsRecompile):
            print('compiling ' + name + '...')
            extension = path.splitext(filename)[1]
            compiledCode = None
            if extension == '.sol':
                compiledCode = bytearray.fromhex(self.compileSolidity(relativeFilePath)['evm']['bytecode']['object'])
            else:
                raise
            with io_open(compiledOutputPath, mode='wb') as file:
                file.write(compiledCode)
        else:
            pass#print('using cached compilation for ' + name)
        with io_open(compiledOutputPath, mode='rb') as file:
            compiledCode = file.read()
            contractSize = len(compiledCode)
            if (contractSize >= CONTRACT_SIZE_LIMIT):
                print('%sContract %s is OVER the size limit by %d bytes%s' % (bcolors.FAIL, name, contractSize - CONTRACT_SIZE_LIMIT, bcolors.ENDC))
            elif (contractSize >= CONTRACT_SIZE_WARN_LEVEL):
                print('%sContract %s is under size limit by only %d bytes%s' % (bcolors.WARN, name, CONTRACT_SIZE_LIMIT - contractSize, bcolors.ENDC))
            elif (contractSize > 0):
                pass#print('Size: %i' % contractSize)
            ContractsFixture.compiledCode[name] = compiledCode
            return(compiledCode)

    def compileSolidity(self, relativeFilePath):
        absoluteFilePath = resolveRelativePath(relativeFilePath)
        filename = path.basename(relativeFilePath)
        contractName = path.splitext(filename)[0]
        print absoluteFilePath
        compilerParameter = {
            'language': 'Solidity',
            'sources': {
                absoluteFilePath: {
                    'urls': [ absoluteFilePath ]
                }
            },
            'settings': {
                # TODO: Remove 'remappings' line below and update 'sources' line above
                'remappings': [ '=%s/' % resolveRelativePath(self.relativeContractsPath), 'TEST=%s/' % resolveRelativePath(self.relativeTestContractsPath) ],
                'optimizer': {
                    'enabled': True,
                    'runs': 200
                },
                'outputSelection': {
                    "*": {
                        '*': [ 'metadata', 'evm.bytecode', 'evm.sourceMap', 'abi' ]
                    }
                }
            }
        }
        return compile_standard(compilerParameter, allow_paths=resolveRelativePath("../"))['contracts'][absoluteFilePath][contractName]

    def getAllDependencies(self, filePath, knownDependencies):
        knownDependencies.add(filePath)
        fileDirectory = path.dirname(filePath)
        with open(filePath, 'r') as file:
            fileContents = file.read()
        matches = findall("inset\('(.*?)'\)", fileContents)
        for match in matches:
            dependencyPath = path.abspath(path.join(fileDirectory, match))
            if not dependencyPath in knownDependencies:
                self.getAllDependencies(dependencyPath, knownDependencies)
        matches = findall("create\('(.*?)'\)", fileContents)
        for match in matches:
            dependencyPath = path.abspath(path.join(fileDirectory, match))
            if not dependencyPath in knownDependencies:
                self.getAllDependencies(dependencyPath, knownDependencies)
        matches = findall("import ['\"](.*?)['\"]", fileContents)
        for match in matches:
            dependencyPath = path.join(BASE_PATH, self.relativeContractsPath, match)
            if "TEST" in dependencyPath:
                dependencyPath = path.join(BASE_PATH, self.relativeTestContractsPath, match).replace("TEST/", "")
            if not path.isfile(dependencyPath):
                raise Exception("Could not resolve dependency file path: %s" % dependencyPath)
            if not dependencyPath in knownDependencies:
                self.getAllDependencies(dependencyPath, knownDependencies)
        return(knownDependencies)

    ####
    #### Class Methods
    ####

    def __init__(self):
        tester.GASPRICE = 0
        tester.STARTGAS = long(6.7 * 10**7)
        config_metropolis['GASLIMIT_ADJMAX_FACTOR'] = .000000000001
        config_metropolis['GENESIS_GAS_LIMIT'] = 2**60
        config_metropolis['MIN_GAS_LIMIT'] = 2**60
        config_metropolis['BLOCK_GAS_LIMIT'] = 2**60

        for a in range(10):
            tester.base_alloc[getattr(tester, 'a%i' % a)] = {'balance': 10**24}

        self.chain = Chain(env=Env(config=config_metropolis))
        self.contracts = {}
        self.testerAddress = self.generateTesterMap('a')
        self.testerKey = self.generateTesterMap('k')
        self.testerAddressToKey = dict(zip(self.testerAddress.values(), self.testerKey.values()))
        if path.isfile('./allFiredEvents'):
            remove_file('./allFiredEvents')
        self.relativeContractsPath = '../source/contracts'
        self.relativeTestContractsPath = 'solidity_test_helpers'
        self.externalContractsPath = '../source/contracts/external'
        self.coverageMode = pytest.config.option.cover
        self.subFork = pytest.config.option.subFork
        if self.coverageMode:
            self.chain.head_state.log_listeners.append(self.writeLogToFile)
            self.relativeContractsPath = '../coverageEnv/contracts'
            self.relativeTestContractsPath = '../coverageEnv/solidity_test_helpers'
            self.externalContractsPath = '../coverageEnv/contracts/external'


    def writeLogToFile(self, message):
        with open('./allFiredEvents', 'a') as logsFile:
            logsFile.write(json_dumps(message.to_dict()) + '\n')

    def distributeRep(self, universe):
        # Get the reputation token for this universe and migrate legacy REP to it
        reputationToken = self.applySignature('ReputationToken', universe.getReputationToken())
        legacyRepToken = self.applySignature('LegacyReputationToken', reputationToken.getLegacyRepToken())
        totalSupply = legacyRepToken.balanceOf(tester.a0)
        legacyRepToken.approve(reputationToken.address, totalSupply)
        reputationToken.migrateFromLegacyReputationToken()

    def generateTesterMap(self, ch):
        testers = {}
        for i in range(0,9):
            testers[i] = getattr(tester, ch + "%d" % i)
        return testers

    def uploadAndAddToAugur(self, relativeFilePath, lookupKey = None, signatureKey = None, constructorArgs=[]):
        lookupKey = lookupKey if lookupKey else path.splitext(path.basename(relativeFilePath))[0]
        contract = self.upload(relativeFilePath, lookupKey, signatureKey, constructorArgs)
        if not contract: return None
        self.contracts['Augur'].registerContract(lookupKey.ljust(32, '\x00'), contract.address)
        return(contract)

    def generateAndStoreSignature(self, relativePath):
        key = path.splitext(path.basename(relativePath))[0]
        resolvedPath = resolveRelativePath(relativePath)
        if self.coverageMode:
            resolvedPath = resolvedPath.replace("tests", "coverageEnv").replace("source/", "coverageEnv/")
        if key not in ContractsFixture.signatures:
            ContractsFixture.signatures[key] = self.generateSignature(resolvedPath)

    def upload(self, relativeFilePath, lookupKey = None, signatureKey = None, constructorArgs=[]):
        resolvedPath = resolveRelativePath(relativeFilePath)
        if self.coverageMode:
            resolvedPath = resolvedPath.replace("tests", "coverageEnv").replace("source/", "coverageEnv/")
        lookupKey = lookupKey if lookupKey else path.splitext(path.basename(resolvedPath))[0]
        signatureKey = signatureKey if signatureKey else lookupKey
        if lookupKey in self.contracts:
            return(self.contracts[lookupKey])
        compiledCode = self.getCompiledCode(resolvedPath)
        # abstract contracts have a 0-length array for bytecode
        if len(compiledCode) == 0:
            if ("libraries" in relativeFilePath or lookupKey.startswith("I") or lookupKey.startswith("Base") or lookupKey.startswith("DS")):
                pass#print "Skipping upload of " + lookupKey + " because it had no bytecode (likely a abstract class/interface)."
            else:
                raise Exception("Contract: " + lookupKey + " has no bytecode, but this is not expected. It probably doesn't implement all its abstract methods")
            return None
        if signatureKey not in ContractsFixture.signatures:
            ContractsFixture.signatures[signatureKey] = self.generateSignature(resolvedPath)
        signature = ContractsFixture.signatures[signatureKey]
        contractTranslator = ContractTranslator(signature)
        if len(constructorArgs) > 0:
            compiledCode += contractTranslator.encode_constructor_arguments(constructorArgs)
        contractAddress = bytesToHexString(self.chain.contract(compiledCode, language='evm'))
        contract = ABIContract(self.chain, contractTranslator, contractAddress)
        self.contracts[lookupKey] = contract
        return(contract)

    def applySignature(self, signatureName, address):
        assert address
        if type(address) is long:
            address = longToHexString(address)
        translator = ContractTranslator(ContractsFixture.signatures[signatureName])
        contract = ABIContract(self.chain, translator, address)
        return contract

    def createSnapshot(self):
        self.chain.tx(sender=tester.k0, to=tester.a1, value=0)
        self.chain.mine(1)
        contractsCopy = {}
        for contractName in self.contracts:
            contractsCopy[contractName] = dict(translator = self.contracts[contractName].translator, address = self.contracts[contractName].address)
        return  { 'state': self.chain.head_state.to_snapshot(), 'contracts': contractsCopy }

    def resetToSnapshot(self, snapshot):
        if not 'state' in snapshot: raise "snapshot is missing 'state'"
        if not 'contracts' in snapshot: raise "snapshot is missing 'contracts'"
        self.chain = Chain(genesis=snapshot['state'], env=Env(config=config_metropolis))
        if self.coverageMode:
            self.chain.head_state.log_listeners.append(self.writeLogToFile)
        self.contracts = {}
        for contractName in snapshot['contracts']:
            contract = snapshot['contracts'][contractName]
            self.contracts[contractName] = ABIContract(self.chain, contract['translator'], contract['address'])

    ####
    #### Bulk Operations
    ####

    def uploadAllContracts(self):
        for directory, _, filenames in walk(resolveRelativePath(self.relativeContractsPath)):
            # skip the legacy reputation directory since it is unnecessary and we don't support uploads of contracts with constructors yet
            if 'legacy_reputation' in directory: continue
            if 'external' in directory: continue
            for filename in filenames:
                name = path.splitext(filename)[0]
                extension = path.splitext(filename)[1]
                if extension != '.sol': continue
                if name == 'augur': continue
                if name == 'Augur': continue
                if name == 'Orders': continue # In testing we use the TestOrders version which lets us call protected methods
                if name == 'Time': continue # In testing and development we swap the Time library for a ControlledTime version which lets us manage block timestamp
                if name == 'ReputationTokenFactory': continue # In testing and development we use the TestNetReputationTokenFactory which lets us faucet
                onlySignatures = ["ReputationToken", "TestNetReputationToken", "Universe"]
                if name in onlySignatures:
                    self.generateAndStoreSignature(path.join(directory, filename))
                elif name == "TimeControlled":
                    self.uploadAndAddToAugur(path.join(directory, filename), lookupKey = "Time", signatureKey = "TimeControlled")
                elif name == "TestNetReputationTokenFactory":
                    self.uploadAndAddToAugur(path.join(directory, filename), lookupKey = "ReputationTokenFactory", signatureKey = "TestNetReputationTokenFactory")
                elif name == "TestOrders":
                    self.uploadAndAddToAugur(path.join(directory, filename), lookupKey = "Orders", signatureKey = "TestOrders")
                else:
                    self.uploadAndAddToAugur(path.join(directory, filename))

    def uploadAllMockContracts(self):
        for directory, _, filenames in walk(resolveRelativePath(self.relativeTestContractsPath)):
            for filename in filenames:
                name = path.splitext(filename)[0]
                extension = path.splitext(filename)[1]
                if extension != '.sol': continue
                if not name.startswith('Mock'): continue
                if 'Factory' in name:
                    self.upload(path.join(directory, filename))
                else:
                    self.uploadAndAddToAugur(path.join(directory, filename))

    def uploadExternalContracts(self):
        for directory, _, filenames in walk(resolveRelativePath(self.externalContractsPath)):
            for filename in filenames:
                name = path.splitext(filename)[0]
                extension = path.splitext(filename)[1]
                if extension != '.sol': continue
                constructorArgs = []
                self.upload(path.join(directory, filename), constructorArgs=constructorArgs)

    def initializeAllContracts(self):
        contractsToInitialize = ['CompleteSets','CreateOrder','FillOrder','CancelOrder','Trade','ClaimTradingProceeds','Orders','Time','Cash','LegacyReputationToken']
        for contractName in contractsToInitialize:
            if getattr(self.contracts[contractName], "initializeERC820", None):
                self.contracts[contractName].initializeERC820(self.contracts['Augur'].address)
            elif getattr(self.contracts[contractName], "initialize", None):
                self.contracts[contractName].initialize(self.contracts['Augur'].address)
            else:
                raise "contract has no 'initialize' method on it."

    ####
    #### Helpers
    ####

    def getSeededCash(self):
        cash = self.contracts['Cash']
        cash.depositEther(value = 1, sender = tester.k9)
        return cash

    def approveCentralAuthority(self):
        authority = self.contracts['Augur']
        contractsToApprove = ['Cash']
        testersGivingApproval = [getattr(tester, 'k%i' % x) for x in range(0,10)]
        for testerKey in testersGivingApproval:
            for contractName in contractsToApprove:
                self.contracts[contractName].approve(authority.address, 2**254, sender=testerKey)

    def uploadAugur(self):
        # We have to upload Augur first
        augur = self.upload("../source/contracts/Augur.sol")
        self.contracts['Augur'].registerContract("Augur".ljust(32, '\x00'), augur.address)
        return augur

    def uploadShareToken(self, augurAddress = None):
        augurAddress = augurAddress if augurAddress else self.contracts['Augur'].address
        self.ensureShareTokenDependencies()
        shareTokenFactory = self.contracts['ShareTokenFactory']
        shareToken = shareTokenFactory.createShareToken(augurAddress)
        return self.applySignature('shareToken', shareToken)

    def createUniverse(self):
        universeAddress = self.contracts['Augur'].createGenesisUniverse()
        universe = self.applySignature('Universe', universeAddress)
        assert universe.getTypeName() == stringToBytes('Universe')
        return universe

    def getShareToken(self, market, outcome):
        shareTokenAddress = market.getShareToken(outcome)
        assert shareTokenAddress
        shareToken = ABIContract(self.chain, ContractTranslator(ContractsFixture.signatures['ShareToken']), shareTokenAddress)
        return shareToken

    def getOrCreateChildUniverse(self, parentUniverse, market, payoutDistribution):
        assert payoutDistributionHash
        childUniverseAddress = parentUniverse.getOrCreateChildUniverse(payoutDistribution)
        assert childUniverseAddress
        childUniverse = ABIContract(self.chain, ContractTranslator(ContractsFixture.signatures['Universe']), childUniverseAddress)
        return childUniverse

    def createYesNoMarket(self, universe, endTime, feePerEthInWei, designatedReporterAddress, sender=tester.k0, topic="", description="description", extraInfo="", validityBond=0):
        marketCreationFee = validityBond or universe.getOrCacheMarketCreationCost()
        with BuyWithCash(self.contracts['Cash'], marketCreationFee, sender, "validity bond"):
            marketAddress = universe.createYesNoMarket(endTime, feePerEthInWei, designatedReporterAddress, topic, description, extraInfo, sender=sender)
        assert marketAddress
        market = ABIContract(self.chain, ContractTranslator(ContractsFixture.signatures['Market']), marketAddress)
        return market

    def createCategoricalMarket(self, universe, numOutcomes, endTime, feePerEthInWei, designatedReporterAddress, sender=tester.k0, topic="", description="description", extraInfo=""):
        marketCreationFee = universe.getOrCacheMarketCreationCost()
        outcomes = [" "] * numOutcomes
        with BuyWithCash(self.contracts['Cash'], marketCreationFee, sender, "validity bond"):
            marketAddress = universe.createCategoricalMarket(endTime, feePerEthInWei, designatedReporterAddress, outcomes, topic, description, extraInfo, sender=sender)
        assert marketAddress
        market = ABIContract(self.chain, ContractTranslator(ContractsFixture.signatures['Market']), marketAddress)
        return market

    def createScalarMarket(self, universe, endTime, feePerEthInWei, maxPrice, minPrice, numTicks, designatedReporterAddress, sender=tester.k0, description="description", extraInfo=""):
        marketCreationFee = universe.getOrCacheMarketCreationCost()
        with BuyWithCash(self.contracts['Cash'], marketCreationFee, sender, "validity bond"):
            marketAddress = universe.createScalarMarket(endTime, feePerEthInWei, designatedReporterAddress, minPrice, maxPrice, numTicks, "", description, extraInfo, sender=sender)
        assert marketAddress
        market = ABIContract(self.chain, ContractTranslator(ContractsFixture.signatures['Market']), marketAddress)
        return market

    def createReasonableYesNoMarket(self, universe, sender=tester.k0, topic="", description="description", extraInfo="", validityBond=0):
        return self.createYesNoMarket(
            universe = universe,
            endTime = long(self.contracts["Time"].getTimestamp() + timedelta(days=1).total_seconds()),
            feePerEthInWei = 10**16,
            designatedReporterAddress = tester.a0,
            sender = sender,
            topic= topic,
            description= description,
            extraInfo= extraInfo,
            validityBond= validityBond)

    def createReasonableCategoricalMarket(self, universe, numOutcomes, sender=tester.k0):
        return self.createCategoricalMarket(
            universe = universe,
            numOutcomes = numOutcomes,
            endTime = long(self.contracts["Time"].getTimestamp() + timedelta(days=1).total_seconds()),
            feePerEthInWei = 10**16,
            designatedReporterAddress = tester.a0,
            sender = sender)

    def createReasonableScalarMarket(self, universe, maxPrice, minPrice, numTicks, sender=tester.k0):
        return self.createScalarMarket(
            universe = universe,
            endTime = long(self.contracts["Time"].getTimestamp() + timedelta(days=1).total_seconds()),
            feePerEthInWei = 10**16,
            maxPrice= maxPrice,
            minPrice= minPrice,
            numTicks= numTicks,
            designatedReporterAddress = tester.a0,
            sender = sender)
Ejemplo n.º 10
0
class ContractsFixture:
    signatures = {}
    compiledCode = {}

    ####
    #### Static Methods
    ####

    @staticmethod
    def ensureCacheDirectoryExists():
        if not path.exists(COMPILATION_CACHE):
            makedirs(COMPILATION_CACHE)

    def generateSignature(self, relativeFilePath):
        ContractsFixture.ensureCacheDirectoryExists()
        filename = path.basename(relativeFilePath)
        name = path.splitext(filename)[0]
        outputPath = path.join(COMPILATION_CACHE,  name + 'Signature')
        lastCompilationTime = path.getmtime(outputPath) if path.isfile(outputPath) else 0
        if path.getmtime(relativeFilePath) > lastCompilationTime:
            print('generating signature for ' + name)
            extension = path.splitext(filename)[1]
            signature = None
            if extension == '.sol':
                signature = self.compileSolidity(relativeFilePath)['abi']
            else:
                raise
            with open(outputPath, mode='w') as file:
                json_dump(signature, file)
        else:
            pass#print('using cached signature for ' + name)
        with open(outputPath, 'r') as file:
            signature = json_load(file)
        return(signature)

    def getCompiledCode(self, relativeFilePath):
        filename = path.basename(relativeFilePath)
        name = path.splitext(filename)[0]
        if name in ContractsFixture.compiledCode:
            return ContractsFixture.compiledCode[name]
        dependencySet = set()
        self.getAllDependencies(relativeFilePath, dependencySet)
        ContractsFixture.ensureCacheDirectoryExists()
        compiledOutputPath = path.join(COMPILATION_CACHE, name)
        lastCompilationTime = path.getmtime(compiledOutputPath) if path.isfile(compiledOutputPath) else 0
        needsRecompile = False
        for dependencyPath in dependencySet:
            if (path.getmtime(dependencyPath) > lastCompilationTime):
                needsRecompile = True
                break
        if (needsRecompile):
            print('compiling ' + name + '...')
            extension = path.splitext(filename)[1]
            compiledCode = None
            if extension == '.sol':
                compiledCode = bytearray.fromhex(self.compileSolidity(relativeFilePath)['evm']['bytecode']['object'])
            else:
                raise
            with io_open(compiledOutputPath, mode='wb') as file:
                file.write(compiledCode)
        else:
            pass#print('using cached compilation for ' + name)
        with io_open(compiledOutputPath, mode='rb') as file:
            compiledCode = file.read()
            contractSize = len(compiledCode)
            if (contractSize >= CONTRACT_SIZE_LIMIT):
                print('%sContract %s is OVER the size limit by %d bytes%s' % (bcolors.FAIL, name, contractSize - CONTRACT_SIZE_LIMIT, bcolors.ENDC))
            elif (contractSize >= CONTRACT_SIZE_WARN_LEVEL):
                print('%sContract %s is under size limit by only %d bytes%s' % (bcolors.WARN, name, CONTRACT_SIZE_LIMIT - contractSize, bcolors.ENDC))
            elif (contractSize > 0):
                pass#print('Size: %i' % contractSize)
            ContractsFixture.compiledCode[name] = compiledCode
            return(compiledCode)

    def compileSolidity(self, relativeFilePath):
        absoluteFilePath = resolveRelativePath(relativeFilePath)
        filename = path.basename(relativeFilePath)
        contractName = path.splitext(filename)[0]
        print absoluteFilePath
        compilerParameter = {
            'language': 'Solidity',
            'sources': {
                absoluteFilePath: {
                    'urls': [ absoluteFilePath ]
                }
            },
            'settings': {
                # TODO: Remove 'remappings' line below and update 'sources' line above
                'remappings': [ '=%s/' % resolveRelativePath(self.relativeContractsPath), 'TEST=%s/' % resolveRelativePath(self.relativeTestContractsPath) ],
                'optimizer': {
                    'enabled': True,
                    'runs': 500
                },
                'outputSelection': {
                    "*": {
                        '*': [ 'metadata', 'evm.bytecode', 'evm.sourceMap', 'abi' ]
                    }
                }
            }
        }
        return compile_standard(compilerParameter, allow_paths=resolveRelativePath("../"))['contracts'][absoluteFilePath][contractName]

    def getAllDependencies(self, filePath, knownDependencies):
        knownDependencies.add(filePath)
        fileDirectory = path.dirname(filePath)
        with open(filePath, 'r') as file:
            fileContents = file.read()
        matches = findall("inset\('(.*?)'\)", fileContents)
        for match in matches:
            dependencyPath = path.abspath(path.join(fileDirectory, match))
            if not dependencyPath in knownDependencies:
                self.getAllDependencies(dependencyPath, knownDependencies)
        matches = findall("create\('(.*?)'\)", fileContents)
        for match in matches:
            dependencyPath = path.abspath(path.join(fileDirectory, match))
            if not dependencyPath in knownDependencies:
                self.getAllDependencies(dependencyPath, knownDependencies)
        matches = findall("import ['\"](.*?)['\"]", fileContents)
        for match in matches:
            dependencyPath = path.join(BASE_PATH, self.relativeContractsPath, match)
            if "TEST" in dependencyPath:
                dependencyPath = path.join(BASE_PATH, self.relativeTestContractsPath, match).replace("TEST/", "")
            if not path.isfile(dependencyPath):
                raise Exception("Could not resolve dependency file path: %s" % dependencyPath)
            if not dependencyPath in knownDependencies:
                self.getAllDependencies(dependencyPath, knownDependencies)
        return(knownDependencies)

    ####
    #### Class Methods
    ####

    def __init__(self):
        tester.GASPRICE = 0
        tester.STARTGAS = long(6.7 * 10**7)
        config_metropolis['GASLIMIT_ADJMAX_FACTOR'] = .000000000001
        config_metropolis['GENESIS_GAS_LIMIT'] = 2**60
        config_metropolis['MIN_GAS_LIMIT'] = 2**60
        config_metropolis['BLOCK_GAS_LIMIT'] = 2**60

        for a in range(10):
            tester.base_alloc[getattr(tester, 'a%i' % a)] = {'balance': 10**24}

        self.chain = Chain(env=Env(config=config_metropolis))
        self.contracts = {}
        self.testerAddress = self.generateTesterMap('a')
        self.testerKey = self.generateTesterMap('k')
        self.testerAddressToKey = dict(zip(self.testerAddress.values(), self.testerKey.values()))
        if path.isfile('./allFiredEvents'):
            remove_file('./allFiredEvents')
        self.relativeContractsPath = '../source/contracts'
        self.relativeTestContractsPath = 'solidity_test_helpers'
        self.coverageMode = pytest.config.option.cover
        if self.coverageMode:
            self.chain.head_state.log_listeners.append(self.writeLogToFile)
            self.relativeContractsPath = '../coverageEnv/contracts'
            self.relativeTestContractsPath = '../coverageEnv/solidity_test_helpers'


    def writeLogToFile(self, message):
        with open('./allFiredEvents', 'a') as logsFile:
            logsFile.write(json_dumps(message.to_dict()) + '\n')

    def distributeRep(self, universe):
        # Get the reputation token for this universe and migrate legacy REP to it
        reputationToken = self.applySignature('ReputationToken', universe.getReputationToken())
        reputationToken.migrateBalancesFromLegacyRep([tester.a0])

    def generateTesterMap(self, ch):
        testers = {}
        for i in range(0,9):
            testers[i] = getattr(tester, ch + "%d" % i)
        return testers

    def uploadAndAddToController(self, relativeFilePath, lookupKey = None, signatureKey = None, constructorArgs=[]):
        lookupKey = lookupKey if lookupKey else path.splitext(path.basename(relativeFilePath))[0]
        contract = self.upload(relativeFilePath, lookupKey, signatureKey, constructorArgs)
        if not contract: return None
        self.contracts['Controller'].registerContract(lookupKey.ljust(32, '\x00'), contract.address, garbageBytes20, garbageBytes32)
        return(contract)

    def upload(self, relativeFilePath, lookupKey = None, signatureKey = None, constructorArgs=[]):
        resolvedPath = resolveRelativePath(relativeFilePath)
        if self.coverageMode:
            resolvedPath = resolvedPath.replace("tests", "coverageEnv").replace("source/", "coverageEnv/")
        lookupKey = lookupKey if lookupKey else path.splitext(path.basename(resolvedPath))[0]
        signatureKey = signatureKey if signatureKey else lookupKey
        if lookupKey in self.contracts:
            return(self.contracts[lookupKey])
        compiledCode = self.getCompiledCode(resolvedPath)
        # abstract contracts have a 0-length array for bytecode
        if len(compiledCode) == 0:
            if ("libraries" in relativeFilePath or lookupKey.startswith("I") or lookupKey.startswith("Base")):
                pass#print "Skipping upload of " + lookupKey + " because it had no bytecode (likely a abstract class/interface)."
            else:
                raise Exception("Contract: " + lookupKey + " has no bytecode, but this is not expected. It probably doesn't implement all its abstract methods")
            return None
        if signatureKey not in ContractsFixture.signatures:
            ContractsFixture.signatures[signatureKey] = self.generateSignature(resolvedPath)
        signature = ContractsFixture.signatures[signatureKey]
        contractTranslator = ContractTranslator(signature)
        if len(constructorArgs) > 0:
            compiledCode += contractTranslator.encode_constructor_arguments(constructorArgs)
        contractAddress = bytesToHexString(self.chain.contract(compiledCode, language='evm'))
        contract = ABIContract(self.chain, contractTranslator, contractAddress)
        self.contracts[lookupKey] = contract
        return(contract)

    def applySignature(self, signatureName, address):
        assert address
        if type(address) is long:
            address = longToHexString(address)
        translator = ContractTranslator(ContractsFixture.signatures[signatureName])
        contract = ABIContract(self.chain, translator, address)
        return contract

    def createSnapshot(self):
        self.chain.tx(sender=tester.k0, to=tester.a1, value=0)
        self.chain.mine(1)
        contractsCopy = {}
        for contractName in self.contracts:
            contractsCopy[contractName] = dict(translator = self.contracts[contractName].translator, address = self.contracts[contractName].address)
        return  { 'state': self.chain.head_state.to_snapshot(), 'contracts': contractsCopy }

    def resetToSnapshot(self, snapshot):
        if not 'state' in snapshot: raise "snapshot is missing 'state'"
        if not 'contracts' in snapshot: raise "snapshot is missing 'contracts'"
        self.chain = Chain(genesis=snapshot['state'], env=Env(config=config_metropolis))
        if self.coverageMode:
            self.chain.head_state.log_listeners.append(self.writeLogToFile)
        self.contracts = {}
        for contractName in snapshot['contracts']:
            contract = snapshot['contracts'][contractName]
            self.contracts[contractName] = ABIContract(self.chain, contract['translator'], contract['address'])

    ####
    #### Bulk Operations
    ####

    def uploadAllContracts(self):
        for directory, _, filenames in walk(resolveRelativePath(self.relativeContractsPath)):
            # skip the legacy reputation directory since it is unnecessary and we don't support uploads of contracts with constructors yet
            if 'legacy_reputation' in directory: continue
            for filename in filenames:
                name = path.splitext(filename)[0]
                extension = path.splitext(filename)[1]
                if extension != '.sol': continue
                if name == 'controller': continue
                if name == 'Augur': continue
                if name == 'Time': continue # In testing and development we swap the Time library for a ControlledTime version which lets us manage block timestamp
                contractsToDelegate = ['Orders', 'TradingEscapeHatch', 'Cash']
                if name in contractsToDelegate:
                    delegationTargetName = "".join([name, "Target"])
                    self.uploadAndAddToController(path.join(directory, filename), delegationTargetName, name)
                    self.uploadAndAddToController("../source/contracts/libraries/Delegator.sol", name, "delegator", constructorArgs=[self.contracts['Controller'].address, delegationTargetName.ljust(32, '\x00')])
                    self.contracts[name] = self.applySignature(name, self.contracts[name].address)
                elif name == "TimeControlled":
                    self.uploadAndAddToController(path.join(directory, filename), lookupKey = "Time", signatureKey = "TimeControlled")
                elif name == "Trade":
                    self.uploadAndAddToController("solidity_test_helpers/TestTrade.sol", lookupKey = "Trade", signatureKey = "Trade")
                else:
                    self.uploadAndAddToController(path.join(directory, filename))

    def uploadAllMockContracts(self):
        for directory, _, filenames in walk(resolveRelativePath(self.relativeTestContractsPath)):
            for filename in filenames:
                name = path.splitext(filename)[0]
                extension = path.splitext(filename)[1]
                if extension != '.sol': continue
                if not name.startswith('Mock'): continue
                if 'Factory' in name:
                    self.upload(path.join(directory, filename))
                else:
                    self.uploadAndAddToController(path.join(directory, filename))


    def whitelistTradingContracts(self):
        for filename in listdir(resolveRelativePath('../source/contracts/trading')):
            name = path.splitext(filename)[0]
            extension = path.splitext(filename)[1]
            if extension != '.sol': continue
            if name == "ShareToken": continue
            if not name in self.contracts: continue
            self.contracts['Controller'].addToWhitelist(self.contracts[name].address)

    def initializeAllContracts(self):
        contractsToInitialize = ['CompleteSets','CreateOrder','FillOrder','CancelOrder','Trade','ClaimTradingProceeds','OrdersFetcher', 'Time']
        for contractName in contractsToInitialize:
            if getattr(self.contracts[contractName], "setController", None):
                self.contracts[contractName].setController(self.contracts['Controller'].address)
            elif getattr(self.contracts[contractName], "initialize", None):
                self.contracts[contractName].initialize(self.contracts['Controller'].address)
            else:
                raise "contract has neither 'initialize' nor 'setController' method on it."

    ####
    #### Helpers
    ####

    def getSeededCash(self):
        cash = self.contracts['Cash']
        cash.depositEther(value = 1, sender = tester.k9)
        return cash

    def approveCentralAuthority(self):
        authority = self.contracts['Augur']
        contractsToApprove = ['Cash']
        testersGivingApproval = [getattr(tester, 'k%i' % x) for x in range(0,10)]
        for testerKey in testersGivingApproval:
            for contractName in contractsToApprove:
                self.contracts[contractName].approve(authority.address, 2**254, sender=testerKey)

    def uploadAugur(self):
        # We have to upload Augur first so it can log when contracts are added to the registry
        augur = self.upload("../source/contracts/Augur.sol")
        self.contracts["Augur"].setController(self.contracts['Controller'].address)
        self.contracts['Controller'].registerContract("Augur".ljust(32, '\x00'), augur.address, garbageBytes20, garbageBytes32)
        return augur

    def uploadShareToken(self, controllerAddress = None):
        controllerAddress = controllerAddress if controllerAddress else self.contracts['Controller'].address
        self.ensureShareTokenDependencies()
        shareTokenFactory = self.contracts['ShareTokenFactory']
        shareToken = shareTokenFactory.createShareToken(controllerAddress)
        return self.applySignature('shareToken', shareToken)

    def createUniverse(self):
        universeAddress = self.contracts['Augur'].createGenesisUniverse()
        universe = self.applySignature('Universe', universeAddress)
        assert universe.getTypeName() == stringToBytes('Universe')
        return universe

    def getShareToken(self, market, outcome):
        shareTokenAddress = market.getShareToken(outcome)
        assert shareTokenAddress
        shareToken = ABIContract(self.chain, ContractTranslator(ContractsFixture.signatures['ShareToken']), shareTokenAddress)
        return shareToken

    def getOrCreateChildUniverse(self, parentUniverse, market, payoutDistribution):
        assert payoutDistributionHash
        childUniverseAddress = parentUniverse.getOrCreateChildUniverse(payoutDistribution, False)
        assert childUniverseAddress
        childUniverse = ABIContract(self.chain, ContractTranslator(ContractsFixture.signatures['Universe']), childUniverseAddress)
        return childUniverse

    def createBinaryMarket(self, universe, endTime, feePerEthInWei, denominationToken, designatedReporterAddress, sender=tester.k0, topic="", description="description", extraInfo=""):
        marketCreationFee = universe.getOrCacheMarketCreationCost()
        marketAddress = universe.createBinaryMarket(endTime, feePerEthInWei, denominationToken.address, designatedReporterAddress, topic, description, extraInfo, value = marketCreationFee, sender=sender)
        assert marketAddress
        market = ABIContract(self.chain, ContractTranslator(ContractsFixture.signatures['Market']), marketAddress)
        return market

    def createCategoricalMarket(self, universe, numOutcomes, endTime, feePerEthInWei, denominationToken, designatedReporterAddress, sender=tester.k0, topic="", description="description", extraInfo=""):
        marketCreationFee = universe.getOrCacheMarketCreationCost()
        outcomes = [" "] * numOutcomes
        marketAddress = universe.createCategoricalMarket(endTime, feePerEthInWei, denominationToken.address, designatedReporterAddress, outcomes, topic, description, extraInfo, value = marketCreationFee, sender=sender)
        assert marketAddress
        market = ABIContract(self.chain, ContractTranslator(ContractsFixture.signatures['Market']), marketAddress)
        return market

    def createScalarMarket(self, universe, endTime, feePerEthInWei, denominationToken, maxPrice, minPrice, numTicks, designatedReporterAddress, sender=tester.k0, description="description", extraInfo=""):
        marketCreationFee = universe.getOrCacheMarketCreationCost()
        marketAddress = universe.createScalarMarket(endTime, feePerEthInWei, denominationToken.address, designatedReporterAddress, minPrice, maxPrice, numTicks, "", description, extraInfo, value = marketCreationFee, sender=sender)
        assert marketAddress
        market = ABIContract(self.chain, ContractTranslator(ContractsFixture.signatures['Market']), marketAddress)
        return market

    def createReasonableBinaryMarket(self, universe, denominationToken, sender=tester.k0, topic="", description="description", extraInfo=""):
        return self.createBinaryMarket(
            universe = universe,
            endTime = long(self.contracts["Time"].getTimestamp() + timedelta(days=1).total_seconds()),
            feePerEthInWei = 10**16,
            denominationToken = denominationToken,
            designatedReporterAddress = tester.a0,
            sender = sender,
            topic= topic,
            description= description,
            extraInfo= extraInfo)

    def createReasonableCategoricalMarket(self, universe, numOutcomes, denominationToken, sender=tester.k0):
        return self.createCategoricalMarket(
            universe = universe,
            numOutcomes = numOutcomes,
            endTime = long(self.contracts["Time"].getTimestamp() + timedelta(days=1).total_seconds()),
            feePerEthInWei = 10**16,
            denominationToken = denominationToken,
            designatedReporterAddress = tester.a0,
            sender = sender)

    def createReasonableScalarMarket(self, universe, maxPrice, minPrice, numTicks, denominationToken, sender=tester.k0):
        return self.createScalarMarket(
            universe = universe,
            endTime = long(self.contracts["Time"].getTimestamp() + timedelta(days=1).total_seconds()),
            feePerEthInWei = 10**16,
            denominationToken = denominationToken,
            maxPrice= maxPrice,
            minPrice= minPrice,
            numTicks= numTicks,
            designatedReporterAddress = tester.a0,
            sender = sender)
Ejemplo n.º 11
0
class ContractsFixture:
    signatures = {}
    compiledCode = {}

    ####
    #### Static Methods
    ####

    @staticmethod
    def ensureCacheDirectoryExists():
        if not path.exists(COMPILATION_CACHE):
            makedirs(COMPILATION_CACHE)

    @staticmethod
    def generateSignature(relativeFilePath):
        ContractsFixture.ensureCacheDirectoryExists()
        filename = path.basename(relativeFilePath)
        name = path.splitext(filename)[0]
        outputPath = path.join(COMPILATION_CACHE, name + 'Signature')
        lastCompilationTime = path.getmtime(outputPath) if path.isfile(
            outputPath) else 0
        if path.getmtime(relativeFilePath) > lastCompilationTime:
            print('generating signature for ' + name)
            extension = path.splitext(filename)[1]
            signature = None
            if extension == '.sol':
                signature = ContractsFixture.compileSolidity(
                    relativeFilePath)['abi']
            else:
                raise
            with open(outputPath, mode='w') as file:
                json_dump(signature, file)
        else:
            print('using cached signature for ' + name)
        with open(outputPath, 'r') as file:
            signature = json_load(file)
        return (signature)

    @staticmethod
    def getCompiledCode(relativeFilePath):
        filename = path.basename(relativeFilePath)
        name = path.splitext(filename)[0]
        if name in ContractsFixture.compiledCode:
            return ContractsFixture.compiledCode[name]
        dependencySet = set()
        ContractsFixture.getAllDependencies(relativeFilePath, dependencySet)
        ContractsFixture.ensureCacheDirectoryExists()
        compiledOutputPath = path.join(COMPILATION_CACHE, name)
        lastCompilationTime = path.getmtime(compiledOutputPath) if path.isfile(
            compiledOutputPath) else 0
        needsRecompile = False
        for dependencyPath in dependencySet:
            if (path.getmtime(dependencyPath) > lastCompilationTime):
                needsRecompile = True
                break
        if (needsRecompile):
            print('compiling ' + name + '...')
            extension = path.splitext(filename)[1]
            compiledCode = None
            if extension == '.sol':
                compiledCode = bytearray.fromhex(
                    ContractsFixture.compileSolidity(relativeFilePath)['evm']
                    ['bytecode']['object'])
            else:
                raise
            with io_open(compiledOutputPath, mode='wb') as file:
                file.write(compiledCode)
        else:
            print('using cached compilation for ' + name)
        with io_open(compiledOutputPath, mode='rb') as file:
            compiledCode = file.read()
            contractSize = len(compiledCode)
            if (contractSize >= CONTRACT_SIZE_LIMIT):
                print('%sContract %s is OVER the size limit by %d bytes%s' %
                      (bcolors.FAIL, name, contractSize - CONTRACT_SIZE_LIMIT,
                       bcolors.ENDC))
            elif (contractSize >= CONTRACT_SIZE_WARN_LEVEL):
                print('%sContract %s is under size limit by only %d bytes%s' %
                      (bcolors.WARN, name, CONTRACT_SIZE_LIMIT - contractSize,
                       bcolors.ENDC))
            elif (contractSize > 0):
                print('Size: %i' % contractSize)
            ContractsFixture.compiledCode[name] = compiledCode
            return (compiledCode)

    @staticmethod
    def compileSolidity(relativeFilePath):
        absoluteFilePath = resolveRelativePath(relativeFilePath)
        filename = path.basename(relativeFilePath)
        contractName = path.splitext(filename)[0]
        print absoluteFilePath
        compilerParameter = {
            'language': 'Solidity',
            'sources': {
                absoluteFilePath: {
                    'urls': [absoluteFilePath]
                }
            },
            'settings': {
                # TODO: Remove 'remappings' line below and update 'sources' line above
                'remappings': [
                    '=%s/' % resolveRelativePath("../source/contracts"),
                    'TEST=%s/' % resolveRelativePath("solidity_test_helpers")
                ],
                'optimizer': {
                    'enabled': True,
                    'runs': 500
                },
                'outputSelection': {
                    '*': ['metadata', 'evm.bytecode', 'evm.sourceMap']
                }
            }
        }
        return compile_standard(
            compilerParameter, allow_paths=resolveRelativePath(
                "../"))['contracts'][absoluteFilePath][contractName]

    @staticmethod
    def getAllDependencies(filePath, knownDependencies):
        knownDependencies.add(filePath)
        fileDirectory = path.dirname(filePath)
        with open(filePath, 'r') as file:
            fileContents = file.read()
        matches = findall("inset\('(.*?)'\)", fileContents)
        for match in matches:
            dependencyPath = path.abspath(path.join(fileDirectory, match))
            if not dependencyPath in knownDependencies:
                ContractsFixture.getAllDependencies(dependencyPath,
                                                    knownDependencies)
        matches = findall("create\('(.*?)'\)", fileContents)
        for match in matches:
            dependencyPath = path.abspath(path.join(fileDirectory, match))
            if not dependencyPath in knownDependencies:
                ContractsFixture.getAllDependencies(dependencyPath,
                                                    knownDependencies)
        matches = findall("import ['\"](.*?)['\"]", fileContents)
        for match in matches:
            dependencyPath = path.join(BASE_PATH, '..', 'source/contracts',
                                       match)
            if "TEST" in dependencyPath:
                dependencyPath = path.join(BASE_PATH, 'solidity_test_helpers',
                                           match).replace("TEST/", "")
            if not path.isfile(dependencyPath):
                raise Exception("Could not resolve dependency file path: %s" %
                                dependencyPath)
            if not dependencyPath in knownDependencies:
                ContractsFixture.getAllDependencies(dependencyPath,
                                                    knownDependencies)
        return (knownDependencies)

    ####
    #### Class Methods
    ####

    def __init__(self):
        tester.GASPRICE = 0
        config_metropolis['GASLIMIT_ADJMAX_FACTOR'] = .000000000001
        config_metropolis['GENESIS_GAS_LIMIT'] = 2**60
        config_metropolis['MIN_GAS_LIMIT'] = 2**60
        config_metropolis['BLOCK_GAS_LIMIT'] = 2**60

        for a in range(10):
            tester.base_alloc[getattr(tester, 'a%i' % a)] = {'balance': 10**24}

        self.chain = Chain(env=Env(config=config_metropolis))
        self.contracts = {}
        self.testerAddress = self.generateTesterMap('a')
        self.testerKey = self.generateTesterMap('k')

    def distributeRep(self, universe):
        legacyReputationToken = self.contracts['LegacyReputationToken']
        legacyReputationToken.faucet(11 * 10**6 * 10**18)

        # Get the reputation token for this universe and migrate legacy REP to it
        reputationToken = self.applySignature('ReputationToken',
                                              universe.getReputationToken())
        legacyReputationToken.approve(reputationToken.address,
                                      11 * 10**6 * 10**18)
        reputationToken.migrateFromLegacyReputationToken()

    def generateTesterMap(self, ch):
        testers = {}
        for i in range(0, 9):
            testers[i] = getattr(tester, ch + "%d" % i)
        return testers

    def uploadAndAddToController(self,
                                 relativeFilePath,
                                 lookupKey=None,
                                 signatureKey=None,
                                 constructorArgs=[]):
        lookupKey = lookupKey if lookupKey else path.splitext(
            path.basename(relativeFilePath))[0]
        contract = self.upload(relativeFilePath, lookupKey, signatureKey,
                               constructorArgs)
        if not contract: return None
        self.contracts['Controller'].registerContract(
            lookupKey.ljust(32, '\x00'), contract.address, garbageBytes20,
            garbageBytes32)
        return (contract)

    def upload(self,
               relativeFilePath,
               lookupKey=None,
               signatureKey=None,
               constructorArgs=[]):
        resolvedPath = resolveRelativePath(relativeFilePath)
        lookupKey = lookupKey if lookupKey else path.splitext(
            path.basename(resolvedPath))[0]
        signatureKey = signatureKey if signatureKey else lookupKey
        if lookupKey in self.contracts:
            return (self.contracts[lookupKey])
        compiledCode = ContractsFixture.getCompiledCode(resolvedPath)
        # abstract contracts have a 0-length array for bytecode
        if len(compiledCode) == 0:
            print "Skipping upload of " + lookupKey + " because it had no bytecode (likely a abstract class/interface)."
            return None
        if signatureKey not in ContractsFixture.signatures:
            ContractsFixture.signatures[
                signatureKey] = ContractsFixture.generateSignature(
                    resolvedPath)
        signature = ContractsFixture.signatures[signatureKey]
        contractTranslator = ContractTranslator(signature)
        if len(constructorArgs) > 0:
            compiledCode += contractTranslator.encode_constructor_arguments(
                constructorArgs)
        contractAddress = bytesToHexString(
            self.chain.contract(compiledCode,
                                language='evm',
                                startgas=long(6.7 * 10**6)))
        contract = ABIContract(self.chain, contractTranslator, contractAddress)
        self.contracts[lookupKey] = contract
        return (contract)

    def applySignature(self, signatureName, address):
        assert address
        if type(address) is long:
            address = longToHexString(address)
        translator = ContractTranslator(
            ContractsFixture.signatures[signatureName])
        contract = ABIContract(self.chain, translator, address)
        return contract

    def createSnapshot(self):
        self.chain.tx(sender=tester.k0, to=tester.a1, value=0)
        self.chain.mine(1)
        contractsCopy = {}
        for contractName in self.contracts:
            contractsCopy[contractName] = dict(
                translator=self.contracts[contractName].translator,
                address=self.contracts[contractName].address)
        return {
            'state': self.chain.head_state.to_snapshot(),
            'contracts': contractsCopy
        }

    def resetToSnapshot(self, snapshot):
        if not 'state' in snapshot: raise "snapshot is missing 'state'"
        if not 'contracts' in snapshot: raise "snapshot is missing 'contracts'"
        self.chain = Chain(genesis=snapshot['state'],
                           env=Env(config=config_metropolis))
        self.contracts = {}
        for contractName in snapshot['contracts']:
            contract = snapshot['contracts'][contractName]
            self.contracts[contractName] = ABIContract(self.chain,
                                                       contract['translator'],
                                                       contract['address'])

    ####
    #### Bulk Operations
    ####

    def uploadAllContracts(self):
        for directory, _, filenames in walk(
                resolveRelativePath('../source/contracts')):
            # skip the legacy reputation directory since it is unnecessary and we don't support uploads of contracts with constructors yet
            if 'legacy_reputation' in directory: continue
            for filename in filenames:
                name = path.splitext(filename)[0]
                extension = path.splitext(filename)[1]
                if extension != '.sol': continue
                if name == 'controller': continue
                contractsToDelegate = ['Orders', 'TradingEscapeHatch']
                if name in contractsToDelegate:
                    delegationTargetName = "".join([name, "Target"])
                    self.uploadAndAddToController(
                        path.join(directory, filename), delegationTargetName,
                        name)
                    self.uploadAndAddToController(
                        "../source/contracts/libraries/Delegator.sol",
                        name,
                        "delegator",
                        constructorArgs=[
                            self.contracts['Controller'].address,
                            delegationTargetName.ljust(32, '\x00')
                        ])
                    self.contracts[name] = self.applySignature(
                        name, self.contracts[name].address)
                else:
                    self.uploadAndAddToController(
                        path.join(directory, filename))

    def uploadAllMockContracts(self):
        for directory, _, filenames in walk(
                resolveRelativePath('solidity_test_helpers')):
            for filename in filenames:
                name = path.splitext(filename)[0]
                extension = path.splitext(filename)[1]
                if extension != '.sol': continue
                if not name.startswith('Mock'): continue
                if 'Factory' in name:
                    self.upload(path.join(directory, filename))
                else:
                    self.uploadAndAddToController(
                        path.join(directory, filename))

    def whitelistTradingContracts(self):
        for filename in listdir(
                resolveRelativePath('../source/contracts/trading')):
            name = path.splitext(filename)[0]
            extension = path.splitext(filename)[1]
            if extension != '.sol': continue
            if not name in self.contracts: continue
            self.contracts['Controller'].addToWhitelist(
                self.contracts[name].address)

    def initializeAllContracts(self):
        contractsToInitialize = [
            'Augur', 'Cash', 'CompleteSets', 'CreateOrder', 'FillOrder',
            'CancelOrder', 'Trade', 'ClaimTradingProceeds', 'OrdersFetcher'
        ]
        for contractName in contractsToInitialize:
            if getattr(self.contracts[contractName], "setController", None):
                self.contracts[contractName].setController(
                    self.contracts['Controller'].address)
            elif getattr(self.contracts[contractName], "initialize", None):
                self.contracts[contractName].initialize(
                    self.contracts['Controller'].address)
            else:
                raise "contract has neither 'initialize' nor 'setController' method on it."

    ####
    #### Helpers
    ####

    def getSeededCash(self):
        cash = self.contracts['Cash']
        cash.depositEther(value=1, sender=tester.k9)
        return cash

    def approveCentralAuthority(self):
        authority = self.contracts['Augur']
        contractsToApprove = ['Cash']
        testersGivingApproval = [
            getattr(tester, 'k%i' % x) for x in range(0, 10)
        ]
        for testerKey in testersGivingApproval:
            for contractName in contractsToApprove:
                self.contracts[contractName].approve(authority.address,
                                                     2**254,
                                                     sender=testerKey)

    def uploadShareToken(self, controllerAddress=None):
        controllerAddress = controllerAddress if controllerAddress else self.contracts[
            'Controller'].address
        self.ensureShareTokenDependencies()
        shareTokenFactory = self.contracts['ShareTokenFactory']
        shareToken = shareTokenFactory.createShareToken(controllerAddress)
        return self.applySignature('shareToken', shareToken)

    def createUniverse(self, parentUniverse, payoutDistributionHash):
        universeAddress = self.contracts['UniverseFactory'].createUniverse(
            self.contracts['Controller'].address, parentUniverse,
            payoutDistributionHash)
        universe = self.applySignature('Universe', universeAddress)
        assert universe.getTypeName() == stringToBytes('Universe')
        return universe

    def getStakeToken(self, market, payoutDistribution, invalid=False):
        stakeTokenAddress = market.getStakeToken(payoutDistribution, invalid)
        assert stakeTokenAddress
        stakeToken = ABIContract(
            self.chain,
            ContractTranslator(ContractsFixture.signatures['StakeToken']),
            stakeTokenAddress)
        return stakeToken

    def getShareToken(self, market, outcome):
        shareTokenAddress = market.getShareToken(outcome)
        assert shareTokenAddress
        shareToken = ABIContract(
            self.chain,
            ContractTranslator(ContractsFixture.signatures['ShareToken']),
            shareTokenAddress)
        return shareToken

    def designatedReport(self,
                         market,
                         payoutDistribution,
                         reporterKey,
                         invalid=False):
        stakeToken = self.getStakeToken(market, payoutDistribution, invalid)
        universe = self.applySignature('Universe', market.getUniverse())
        designatedReportStake = universe.getDesignatedReportStake()
        return stakeToken.buy(designatedReportStake, sender=reporterKey)

    def getOrCreateChildUniverse(self, parentUniverse, market,
                                 payoutDistribution):
        payoutDistributionHash = market.derivePayoutDistributionHash(
            payoutDistribution, False)
        assert payoutDistributionHash
        childUniverseAddress = parentUniverse.getOrCreateChildUniverse(
            payoutDistributionHash)
        assert childUniverseAddress
        childUniverse = ABIContract(
            self.chain,
            ContractTranslator(ContractsFixture.signatures['Universe']),
            childUniverseAddress)
        return childUniverse

    def createBinaryMarket(self,
                           universe,
                           endTime,
                           feePerEthInWei,
                           denominationToken,
                           designatedReporterAddress,
                           numTicks,
                           sender=tester.k0,
                           extraInfo=""):
        return self.createCategoricalMarket(universe, 2, endTime,
                                            feePerEthInWei, denominationToken,
                                            designatedReporterAddress,
                                            numTicks, sender, extraInfo)

    def createCategoricalMarket(self,
                                universe,
                                numOutcomes,
                                endTime,
                                feePerEthInWei,
                                denominationToken,
                                designatedReporterAddress,
                                numTicks,
                                sender=tester.k0,
                                extraInfo=""):
        marketCreationFee = universe.getMarketCreationCost()
        reportingWindow = self.applySignature(
            'ReportingWindow',
            universe.getReportingWindowByMarketEndTime(endTime))
        marketAddress = reportingWindow.createMarket(endTime,
                                                     numOutcomes,
                                                     numTicks,
                                                     feePerEthInWei,
                                                     denominationToken.address,
                                                     designatedReporterAddress,
                                                     extraInfo,
                                                     value=marketCreationFee,
                                                     startgas=long(6.7 *
                                                                   10**6),
                                                     sender=sender)
        assert marketAddress
        market = ABIContract(
            self.chain,
            ContractTranslator(ContractsFixture.signatures['Market']),
            marketAddress)
        return market

    def createScalarMarket(self,
                           universe,
                           endTime,
                           feePerEthInWei,
                           denominationToken,
                           numTicks,
                           designatedReporterAddress,
                           sender=tester.k0):
        marketCreationFee = universe.getMarketCreationCost()
        reportingWindow = self.applySignature(
            'ReportingWindow',
            universe.getReportingWindowByMarketEndTime(endTime))
        marketAddress = reportingWindow.createMarket(endTime,
                                                     2,
                                                     numTicks,
                                                     feePerEthInWei,
                                                     denominationToken.address,
                                                     designatedReporterAddress,
                                                     "",
                                                     value=marketCreationFee,
                                                     startgas=long(6.7 *
                                                                   10**6),
                                                     sender=sender)
        assert marketAddress
        market = ABIContract(
            self.chain,
            ContractTranslator(ContractsFixture.signatures['Market']),
            marketAddress)
        return market

    def createReasonableBinaryMarket(self,
                                     universe,
                                     denominationToken,
                                     sender=tester.k0,
                                     extraInfo=""):
        return self.createBinaryMarket(
            universe=universe,
            endTime=long(self.chain.head_state.timestamp +
                         timedelta(days=1).total_seconds()),
            feePerEthInWei=10**16,
            denominationToken=denominationToken,
            designatedReporterAddress=tester.a0,
            numTicks=10**18,
            sender=sender,
            extraInfo=extraInfo)

    def createReasonableCategoricalMarket(self,
                                          universe,
                                          numOutcomes,
                                          denominationToken,
                                          sender=tester.k0):
        return self.createCategoricalMarket(
            universe=universe,
            numOutcomes=numOutcomes,
            endTime=long(self.chain.head_state.timestamp +
                         timedelta(days=1).total_seconds()),
            feePerEthInWei=10**16,
            denominationToken=denominationToken,
            designatedReporterAddress=tester.a0,
            numTicks=3 * 10**17,
            sender=sender)

    def createReasonableScalarMarket(self,
                                     universe,
                                     priceRange,
                                     denominationToken,
                                     sender=tester.k0):
        return self.createScalarMarket(
            universe=universe,
            endTime=long(self.chain.head_state.timestamp +
                         timedelta(days=1).total_seconds()),
            feePerEthInWei=10**16,
            denominationToken=denominationToken,
            numTicks=40 * 10**18,
            designatedReporterAddress=tester.a0,
            sender=sender)