Exemplo n.º 1
0
def reclaim_all(token: Contract, reclaim_list: List[Entry],
                tx_params: dict) -> int:
    """Reclaim all tokens from the given input sheet.

    Process transactions parallel to speed up the operation.

    :param tx_parms: Ethereum transaction parameters to use
    """

    total_reclaimed = 0

    tx_to_confirm = []  # List of txids to confirm
    tx_batch_size = 16  # How many transactions confirm once
    web3 = token.web3

    for entry in reclaim_list:
        ops, txid = reclaim_address(token, entry, tx_params)
        total_reclaimed += ops

        if not txid:
            # Already reclaimed
            continue

        tx_to_confirm.append(txid)

        # Confirm N transactions when batch max size is reached
        if len(tx_to_confirm) >= tx_batch_size:
            check_multiple_succesful_txs(web3, tx_to_confirm)
            tx_to_confirm = []

    # Confirm dangling transactions
    check_multiple_succesful_txs(web3, tx_to_confirm)

    return total_reclaimed
Exemplo n.º 2
0
def main(chain, address, token, csv_file, limit, start_from, issuer_address, address_column, amount_column, allow_zero, master_address):
    """Distribute tokens to centrally issued crowdsale participant.

    Reads in distribution data as CSV. Then uses Issuer contract to distribute tokens.
    All token counts are multiplied by token contract decimal specifier. E.g. if CSV has amount 15.5,
    token has 2 decimal places, we will issue out 1550 raw token amount.

    To speed up the issuance, transactions are verified in batches. Each batch is 16 transactions at a time.

    Example (first run):

        distribute-tokens --chain=kovan --address=0x001FC7d7E506866aEAB82C11dA515E9DD6D02c25 --token=0x1644a421ae0a0869bac127fa4cce8513bd666705 --csv-file=input.csv --allow-zero --address-column="Ethereum address" --amount-column="Golden tickets earned"

    Example (second run, continue after first run was interrupted):

        distribute-tokens --chain=kovan --address=0x001FC7d7E506866aEAB82C11dA515E9DD6D02c25 --token=0x1644a421ae0a0869bac127fa4cce8513bd666705 --csv-file=input.csv --allow-zero --address-column="Ethereum address" --amount-column="Golden tickets earned" --issuer-address=0x2c9877534f62c8b40aebcd08ec9f54d20cb0a945

    """

    project = Project()

    with project.get_chain(chain) as c:

        web3 = c.web3
        print("Web3 provider is", web3.currentProvider)
        print("Owner address is", address)
        print("Owner balance is", from_wei(web3.eth.getBalance(address), "ether"), "ETH")

        # Goes through geth account unlock process if needed
        if is_account_locked(web3, address):
            request_account_unlock(c, address, timeout=3600*6)
            assert not is_account_locked(web3, address)

        Token = c.provider.get_base_contract_factory('CentrallyIssuedToken')
        token = Token(address=token)

        print("Total supply is", token.call().totalSupply())
        print("Upgrade master is", token.call().upgradeMaster())
        print("Owner token balance master is", token.call().balanceOf(address))

        decimals = token.call().decimals()
        print("Token decimal places is", decimals)
        assert decimals >= 0

        decimal_multiplier = 10**decimals

        transaction = {"from": address}

        Issuer = c.provider.get_base_contract_factory('Issuer')
        if not issuer_address:

            # TODO: Fix Populus support this via an deploy argument
            if "JSONFile" in c.registrar.registrar_backends:
                del c.registrar.registrar_backends["JSONFile"]

            # Create issuer contract
            assert master_address, "You need to give master-address"
            args = [address, master_address, token.address]
            print("Deploying new issuer contract", args)
            issuer, txhash = c.provider.deploy_contract("Issuer", deploy_transaction=transaction, deploy_args=args)
            check_succesful_tx(web3, txhash)

            const_args = get_constructor_arguments(issuer, args)
            chain_name = chain
            fname = "Issuer.sol"
            browser_driver = "chrome"
            verify_contract(
                project=project,
                libraries={},  # TODO: Figure out how to pass around
                chain_name=chain_name,
                address=issuer.address,
                contract_name="Issuer",
                contract_filename=fname,
                constructor_args=const_args,
                # libraries=runtime_data["contracts"][name]["libraries"],
                browser_driver=browser_driver)
            link = get_etherscan_link(chain_name, issuer.address)

            print("Issuer verified contract is", link)
        else:
            print("Reusing existing issuer contract")
            issuer = Issuer(address=issuer_address)

        print("Issuer contract is", issuer.address)
        print("Currently issued", issuer.call().issuedCount())

        if not master_address:
            sys.exit("Please use Token.approve() to give some allowance for the issuer contract by master address")

        allowance = token.call().allowance(master_address, issuer.address)
        print("Issuer allowance", allowance)

        if allowance == 0 or not master_address:
            sys.exit("Please use Token.approve() to give some allowance for the issuer contract by master address")

        print("Reading data", csv_file)
        with open(csv_file, "rt") as inp:
            reader = csv.DictReader(inp)
            rows = [row for row in reader]

        # Check that we have unique addresses
        uniq_addresses = set()
        for row in rows:
            addr = row[address_column].strip()
            if addr in uniq_addresses:
                raise RuntimeError("Address appears twice in input data", addr)
            uniq_addresses.add(addr)

        # Start distribution
        start_time = time.time()
        start_balance = from_wei(web3.eth.getBalance(address), "ether")

        tx_to_confirm = []   # List of txids to confirm
        tx_batch_size = 16  # How many transactions confirm once

        print("Total rows", len(rows))

        for i in range(start_from, min(start_from+limit, len(rows))):
            data = rows[i]
            addr = data[address_column].strip()
            tokens = Decimal(data[amount_column].strip())

            tokens *= decimal_multiplier

            end_balance = from_wei(web3.eth.getBalance(address), "ether")
            spent = start_balance - end_balance

            if tokens == 0:
                if not allow_zero:
                    raise RuntimeError("Encountered zero amount")
                else:
                    continue

            # http://stackoverflow.com/a/19965088/315168
            if not tokens % 1 == 0:
                raise RuntimeError("Could not issue tokens because after multiplication was not integer")

            tokens = int(tokens)

            print("Row", i,  "giving", tokens, "to", addr, "issuer", issuer.address, "time passed", time.time() - start_time, "ETH passed", spent)

            if issuer.call().issued(addr):
                print("Already issued, skipping")
                continue

            txid = issuer.transact(transaction).issue(addr, tokens)

            tx_to_confirm.append(txid)

            # Confirm N transactions when batch max size is reached
            if len(tx_to_confirm) >= tx_batch_size:
                check_multiple_succesful_txs(web3, tx_to_confirm)
                tx_to_confirm = []

        # Confirm dangling transactions
        check_multiple_succesful_txs(web3, tx_to_confirm)

        end_balance = from_wei(web3.eth.getBalance(address), "ether")
        print("Deployment cost is", start_balance - end_balance, "ETH")
        print("All done! Enjoy your decentralized future.")
def load(chain, web3: Web3, address: str, csv_file: str, token: Contract,
         address_column: str, amount_column: str, duration_column: str,
         vault_address: str, override_checksum: bool):

    decimals = token.functions.decimals().call()
    decimal_multiplier = 10**decimals
    transaction = {"from": address}

    TokenVault = chain.provider.get_base_contract_factory('TokenVault')
    token_vault = TokenVault(address=vault_address)

    # Check that our tokens are the same
    assert token_vault.functions.token().call() == token.address

    print("Starting to import investor data to ", token_vault.address)

    print("Reading data", csv_file)
    with open(csv_file, "rt") as inp:
        reader = csv.DictReader(inp)
        rows = [row for row in reader]

    # Check that we have unique addresses
    uniq_addresses = set()
    total = 0
    for row in rows:
        addr = row[address_column].strip()
        amount = row[amount_column].strip()

        if addr in uniq_addresses:
            raise RuntimeError("Address appears twice in input data", addr)
        uniq_addresses.add(addr)
        amount = Decimal(amount)
        total += amount
        if amount <= 0:
            raise RuntimeError("Invalid amount:".format(amount))

    if token_vault.functions.tokensToBeAllocated().call(
    ) != total * decimal_multiplier:
        raise RuntimeError("Expected total amount {}, CSV sum is {}".format(
            token_vault.functions.tokensToBeAllocated().call(),
            int(total * decimal_multiplier)))

    # Start distribution
    start_time = time.time()
    start_balance = from_wei(web3.eth.getBalance(address), "ether")

    tx_to_confirm = []  # List of txids to confirm
    tx_batch_size = 16  # How many transactions confirm once

    print("Total rows", len(rows))

    for i in range(len(rows)):
        data = rows[i]
        addr = data[address_column].strip()
        tokens = Decimal(data[amount_column].strip())

        tokens *= decimal_multiplier

        end_balance = from_wei(web3.eth.getBalance(address), "ether")
        spent = start_balance - end_balance

        # http://stackoverflow.com/a/19965088/315168
        if not tokens % 1 == 0:
            raise RuntimeError(
                "Could not issue tokens because after multiplication was not integer"
            )

        tokens = int(tokens)

        duration = int(row[duration_column].strip())
        if duration > 0:
            tokens_per_second = int(tokens / duration)
        else:
            tokens_per_second = 0

        print("Row", i, "giving", tokens, "to", addr, "vault",
              token_vault.address, "time passed",
              time.time() - start_time, "ETH spent", spent)

        if not is_checksum_address(addr):
            if override_checksum:
                print("WARNING: not a checksummed Ethereum address at row", i,
                      ":", format(addr))
                addr = to_checksum_address(addr)
            else:
                raise RuntimeError(
                    "Address not checksummed", addr,
                    "Use --override-checksum to override if you know what you are doing."
                )

        if token_vault.functions.balances(addr).call() > 0:
            print("Already issued, skipping")
            continue

        txid = token_vault.functions.setInvestor(
            addr, tokens, tokens_per_second).transact(transaction)

        tx_to_confirm.append(txid)

        # Confirm N transactions when batch max size is reached
        if len(tx_to_confirm) >= tx_batch_size:
            check_multiple_succesful_txs(web3, tx_to_confirm)
            tx_to_confirm = []

    # Confirm dangling transactions
    check_multiple_succesful_txs(web3, tx_to_confirm)

    end_balance = from_wei(web3.eth.getBalance(address), "ether")
    print("Deployment cost is", start_balance - end_balance, "ETH")
Exemplo n.º 4
0
def main(chain, address, contract_address, csv_file, limit, start_from,
         multiplier):
    """Rebuild data on relaunched CrowdsaleToken contract.

    This allows you rerun investment data to fix potential errors in the contract.

    Example::

        rebuild-crowdsale --address=0x001FC7d7E506866aEAB82C11dA515E9DD6D02c25  --chain=kovan --contract-address=0xf09e4a27a02afd29590a989cb2dda9af8eebc77f --start-from=0 --limit=600 --multiplier=12 --csv-file=inputdata.csv

        rebuild-crowdsale --address=0x001FC7d7E506866aEAB82C11dA515E9DD6D02c25  --chain=kovan --contract-address=0xf09e4a27a02afd29590a989cb2dda9af8eebc77f --start-from=0 --limit=600 --multiplier=12 --csv-file=inputdata.csv

    """

    project = Project()

    with project.get_chain(chain) as c:

        web3 = c.web3
        print("Web3 provider is", web3.currentProvider)
        print("Owner address is", address)
        print("Owner balance is",
              from_wei(web3.eth.getBalance(address), "ether"), "ETH")

        # Goes through geth account unlock process if needed
        if is_account_locked(web3, address):
            request_account_unlock(c, address, timeout=3600 * 6)

        print("Reading data", csv_file)
        with open(csv_file, "rt") as inp:
            reader = csv.DictReader(inp)
            rows = [row for row in reader]

        print("Source data has", len(rows), "rows")
        print("Importing rows", start_from, "-", start_from + limit)

        RelaunchedCrowdsale = c.provider.get_base_contract_factory(
            'RelaunchedCrowdsale')
        relaunched_crowdsale = RelaunchedCrowdsale(address=contract_address)

        print("Crowdsale contract is", contract_address)
        print("Currently issued",
              relaunched_crowdsale.functions.tokensSold().call())

        assert relaunched_crowdsale.functions.owner().call(
        ) == address, "We are not the crowdsale owner. Real owner is {}, we are {}".format(
            relaunched_crowdsale.functions.owner().call(), address)

        multiplier = 10**multiplier

        start_time = time.time()
        start_balance = from_wei(web3.eth.getBalance(address), "ether")

        tx_to_confirm = []  # List of txids to confirm
        tx_batch_size = 16  # How many transactions confirm once
        cap_check = True

        for i in range(start_from, min(start_from + limit, len(rows))):
            data = rows[i]
            addr = data["Address"]
            wei = to_wei(data["Invested ETH"], "ether")
            fractional_tokens = Decimal(data["Received tokens"])
            orig_txid = int(data["Tx hash"], 16)
            # orig_tx_index = int(data["Tx index"])

            tokens = fractional_tokens * multiplier

            transaction = {
                "from": address,
                "gasPrice": int(web3.eth.gasPrice * 1.2)
            }

            # http://stackoverflow.com/a/19965088/315168
            if not tokens % 1 == 0:
                raise RuntimeError(
                    "Could not issue tokens because after multiplication was not integer: {} {} {}"
                    .format(tokens, fractional_tokens, multiplier))

            end_balance = from_wei(web3.eth.getBalance(address), "ether")
            spent = start_balance - end_balance
            print("Row", i, "giving", tokens, "to", addr, "from tx", orig_txid,
                  "ETH spent", spent, "time passed",
                  time.time() - start_time, "gas price",
                  transaction["gasPrice"])

            if relaunched_crowdsale.functions.getRestoredTransactionStatus(
                    orig_txid).call():
                print("Already restored, skipping")
                continue

            tokens = int(tokens)

            if cap_check:
                # See if our cap calculation is screwed
                if relaunched_crowdsale.functions.isBreakingCap(
                        wei, tokens,
                        relaunched_crowdsale.functions.weiRaised().call(),
                        relaunched_crowdsale.functions.tokensSold().call()
                ).call():
                    raise RuntimeError("Cap error")

            txid = relaunched_crowdsale.transact(
                transaction).setInvestorDataAndIssueNewToken(
                    addr, wei, tokens, orig_txid)
            tx_to_confirm.append(txid)

            # Confirm N transactions when batch max size is reached
            if len(tx_to_confirm) >= tx_batch_size:
                check_multiple_succesful_txs(web3, tx_to_confirm)
                tx_to_confirm = []

        # Confirm dangling transactions
        check_multiple_succesful_txs(web3, tx_to_confirm)

        end_balance = from_wei(web3.eth.getBalance(address), "ether")
        print("Deployment cost is", start_balance - end_balance, "ETH")
        print("All done! Enjoy your decentralized future.")
Exemplo n.º 5
0
def main(chain, address, token, csv_file, limit, start_from, issuer_address,
         address_column, amount_column, external_id_column, allow_addresless,
         master_address, gas_price, solc_version):
    """Distribute tokens to centrally issued crowdsale participant or bounty program participants using an external key.

    Reads in distribution data as CSV. Then uses Issuer contract to distribute tokens.
    All token counts are multiplied by token contract decimal specifier. E.g. if CSV has amount 15.5,
    token has 2 decimal places, we will issue out 1550 raw token amount.

    The external id uniquely identifies participants. This is different from the distribute-tokens where the
    Ethereum address uniquely identifies participants.

    To speed up the issuance, transactions are verified in batches. Each batch is 16 transactions at a time.

    First have a issuer contract created:

        distribute-tokens-ext-id \
          --chain=mainnet \
          --address=0xccba4928c4e9d10242788d9cf144d865348c6c7f \
          --token=0x1a7a8bd9106f2b8d977e08582dc7d24c723ab0db \
          --master-address=0xa684a3371e0d46bca4a6db1ff538a44f1440a855 \
          --csv-file=data.csv \
          --address-column="Ethereum address" \
          --amount-column="Token amount" \
          --external-id-column="External ID number" \
          --solc-version="v0.4.16+commit.d7661dd9" \
          --gas-price=100

    Then perform EIP-20 approve() to give tokens to the issuer contract deployed in the last command.

    Then run the distribution:

        distribute-tokens-ext-id \
          --chain=mainnet \
          --address=0xccba4928c4e9d10242788d9cf144d865348c6c7f \
          --token=0x1a7a8bd9106f2b8d977e08582dc7d24c723ab0db \
          --master-address=0xa684a3371e0d46bca4a6db1ff538a44f1440a855 \
          --issuer-address=0x60cfb02266310e66dd99b1635e702c519a564726 \
          --csv-file=combined.csv \
          --address-column="Address" \
          --amount-column="Amount" \
          --gas-price=70 \
          --start-from=670
    """

    project = Project()

    with project.get_chain(chain) as c:

        web3 = c.web3
        print("Web3 provider is", web3.currentProvider)
        print("Deployer account address is", address)
        print("Deployer account balance is",
              from_wei(web3.eth.getBalance(address), "ether"), "ETH")

        # Goes through geth account unlock process if needed
        if is_account_locked(web3, address):
            request_account_unlock(c, address, timeout=3600 * 6)
            assert not is_account_locked(web3, address)

        Token = c.provider.get_base_contract_factory('CentrallyIssuedToken')
        token = Token(address=token)

        print("Token is", token.address)
        print("Total supply is", token.functions.totalSupply().call())
        print("Upgrade master is", token.functions.upgradeMaster().call())
        print("Deployer account token balance is",
              token.functions.balanceOf(address).call())

        decimals = token.functions.decimals().call()
        print("Token decimal places is", decimals)
        assert decimals >= 0

        decimal_multiplier = 10**decimals

        if gas_price:
            gas_price = int(gas_price) * 10**9
        else:
            gas_price = web3.eth.gasPrice * 2

        transaction = {"from": address, "gasPrice": gas_price}

        print("Using gas price of", gas_price / 10**9, "GWei")

        IssuerWithId = c.provider.get_base_contract_factory('IssuerWithId')
        if not issuer_address:

            # TODO: Fix Populus support this via an deploy argument
            if "JSONFile" in c.registrar.registrar_backends:
                del c.registrar.registrar_backends["JSONFile"]

            # Create issuer contract
            assert master_address, "You need to give master-address"
            args = [address, master_address, token.address]
            print("Deploying new issuer contract", args,
                  "transaction parameters", transaction)
            issuer, txhash = c.provider.deploy_contract(
                "IssuerWithId",
                deploy_transaction=transaction,
                deploy_args=args)

            print("Deployment transaction is", txhash)
            print("Waiting contract to be deployed")
            check_succesful_tx(web3, txhash)

            const_args = get_constructor_arguments(issuer, args)
            print("Contract constructor arguments are", const_args)
            chain_name = chain
            fname = "IssuerWithId.sol"
            browser_driver = "chrome"
            verify_contract(
                project=project,
                libraries={},  # TODO: Figure out how to pass around
                chain_name=chain_name,
                address=issuer.address,
                contract_name="IssuerWithId",
                contract_filename=fname,
                constructor_args=const_args,
                browser_driver=browser_driver,
                compiler=solc_version)
            link = get_etherscan_link(chain_name, issuer.address)
            print("Issuer verified contract is", link)
        else:
            print("Using existing issuer contract")
            issuer = IssuerWithId(address=issuer_address)

        print("Issuer contract is", issuer.address)
        print("Currently issued", issuer.functions.issuedCount().call())

        if not master_address:
            sys.exit(
                "Please use Token.approve() to give some allowance for the issuer contract by master address"
            )

        allowance = token.functions.allowance(master_address,
                                              issuer.address).call()
        print("Issuer allowance", allowance)

        if allowance == 0 or not master_address:
            sys.exit(
                "Please use Token.approve() to give some allowance for the issuer contract by master address"
            )

        print("Reading data", csv_file)
        with open(csv_file, "rt") as inp:
            reader = csv.DictReader(inp)
            rows = [row for row in reader]

        # Prevalidate addresses
        # For distributetokens.py this is done by combine-csv
        # Here we do it inline and make skip addresses that are not valid.
        for idx, row in enumerate(rows):
            addr = row[address_column].strip()
            try:
                if addr:
                    validate_ethereum_address(addr)
            except ValueError as e:
                print("Invalid Ethereum address on row:", idx + 1, "address:",
                      addr, "reason:", str(e), "external_id:",
                      row[external_id_column])
                # Proceed regardless of invalid data
                row[address_column] = ""

        # Start distribution
        start_time = time.time()
        start_balance = from_wei(web3.eth.getBalance(address), "ether")

        tx_to_confirm = []  # List of txids to confirm
        tx_batch_size = 16  # How many transactions confirm once

        print("Total rows", len(rows))

        for i in range(start_from, min(start_from + limit, len(rows))):
            data = rows[i]
            addr = data[address_column].strip()
            external_id = data[external_id_column].strip()
            tokens = Decimal(data[amount_column].strip())

            tokens *= decimal_multiplier

            end_balance = from_wei(web3.eth.getBalance(address), "ether")
            spent = start_balance - end_balance

            if addr == "":
                if not allow_addresless:
                    raise RuntimeError("Encountered missing address")
                else:
                    continue

            if not external_id:
                raise RuntimeError("Missing external id on row #{}".format(i +
                                                                           1))

            # http://stackoverflow.com/a/19965088/315168
            if not tokens % 1 == 0:
                raise RuntimeError(
                    "Could not issue tokens because after multiplication was not integer"
                )

            transaction = {
                "from": address,
                "gasPrice": gas_price,
                "gas": 100000,  # Use 100k gas unit limit
            }

            tokens = int(tokens)
            external_id = int(external_id)

            if not external_id > 0:
                raise RuntimeError(
                    "External id must be a positive integer on row #{}".format(
                        i + 1))

            print("Row", i, "giving", tokens, "to", addr, "issuer",
                  issuer.address, "time passed",
                  time.time() - start_time, "ETH passed", spent, "gas price",
                  transaction["gasPrice"] / (10**9))

            if issuer.functions.issued(external_id).call():
                print("Already issued, skipping")
                continue

            txid = issuer.functions.issue(addr, tokens,
                                          external_id).transact(transaction)
            tx_to_confirm.append(txid)

            # Confirm N transactions when batch max size is reached
            if len(tx_to_confirm) >= tx_batch_size:
                check_multiple_succesful_txs(web3, tx_to_confirm)
                tx_to_confirm = []

        # Confirm dangling transactions
        check_multiple_succesful_txs(web3, tx_to_confirm)

        end_balance = from_wei(web3.eth.getBalance(address), "ether")
        print("Deployment cost is", start_balance - end_balance, "ETH")
        print("All done! Enjoy your decentralized future.")
def main(chain, address, token, csv_file, limit, start_from, issuer_address, address_column, amount_column, allow_zero, master_address):
    """Distribute tokens to centrally issued crowdsale participant or bounty program participants.

    Reads in distribution data as CSV. Then uses Issuer contract to distribute tokens.
    All token counts are multiplied by token contract decimal specifier. E.g. if CSV has amount 15.5,
    token has 2 decimal places, we will issue out 1550 raw token amount.

    To speed up the issuance, transactions are verified in batches. Each batch is 16 transactions at a time.

    Example (first run):

        distribute-tokens --chain=kovan --address=0x001FC7d7E506866aEAB82C11dA515E9DD6D02c25 --token=0x1644a421ae0a0869bac127fa4cce8513bd666705 --master-address=0x9a60ad6de185c4ea95058601beaf16f63742782a --csv-file=input.csv --allow-zero --address-column="Ethereum address" --amount-column="Token amount"

    Example (second run, continue after first run was interrupted):

        distribute-tokens --chain=kovan --address=0x001FC7d7E506866aEAB82C11dA515E9DD6D02c25 --token=0x1644a421ae0a0869bac127fa4cce8513bd666705 --csv-file=input.csv --allow-zero --address-column="Ethereum address" --amount-column="Token amount" --issuer-address=0x2c9877534f62c8b40aebcd08ec9f54d20cb0a945

    """

    project = Project()

    with project.get_chain(chain) as c:

        web3 = c.web3
        print("Web3 provider is", web3.currentProvider)
        print("Owner address is", address)
        print("Owner balance is", from_wei(web3.eth.getBalance(address), "ether"), "ETH")

        # Goes through geth account unlock process if needed
        if is_account_locked(web3, address):
            request_account_unlock(c, address, timeout=3600*6)
            assert not is_account_locked(web3, address)

        Token = c.provider.get_base_contract_factory('CentrallyIssuedToken')
        token = Token(address=token)

        print("Token is", token.address)
        print("Total supply is", token.call().totalSupply())
        print("Upgrade master is", token.call().upgradeMaster())
        print("Owner token balance master is", token.call().balanceOf(address))

        decimals = token.call().decimals()
        print("Token decimal places is", decimals)
        assert decimals >= 0

        decimal_multiplier = 10**decimals

        transaction = {"from": address}

        Issuer = c.provider.get_base_contract_factory('Issuer')
        if not issuer_address:

            # TODO: Fix Populus support this via an deploy argument
            if "JSONFile" in c.registrar.registrar_backends:
                del c.registrar.registrar_backends["JSONFile"]

            # Create issuer contract
            assert master_address, "You need to give master-address"
            args = [address, master_address, token.address]
            print("Deploying new issuer contract", args)
            issuer, txhash = c.provider.deploy_contract("Issuer", deploy_transaction=transaction, deploy_args=args)
            check_succesful_tx(web3, txhash)

            const_args = get_constructor_arguments(issuer, args)
            chain_name = chain
            fname = "Issuer.sol"
            browser_driver = "chrome"
            verify_contract(
                project=project,
                libraries={},  # TODO: Figure out how to pass around
                chain_name=chain_name,
                address=issuer.address,
                contract_name="Issuer",
                contract_filename=fname,
                constructor_args=const_args,
                # libraries=runtime_data["contracts"][name]["libraries"],
                browser_driver=browser_driver)
            link = get_etherscan_link(chain_name, issuer.address)

            print("Issuer verified contract is", link)
        else:
            print("Reusing existing issuer contract")
            issuer = Issuer(address=issuer_address)

        print("Issuer contract is", issuer.address)
        print("Currently issued", issuer.call().issuedCount())

        if not master_address:
            sys.exit("Please use Token.approve() to give some allowance for the issuer contract by master address")

        allowance = token.call().allowance(master_address, issuer.address)
        print("Issuer allowance", allowance)

        if allowance == 0 or not master_address:
            sys.exit("Please use Token.approve() to give some allowance for the issuer contract by master address")

        print("Reading data", csv_file)
        with open(csv_file, "rt") as inp:
            reader = csv.DictReader(inp)
            rows = [row for row in reader]

        # Check that we have unique addresses
        uniq_addresses = set()
        for row in rows:
            addr = row[address_column].strip()
            if addr in uniq_addresses:
                raise RuntimeError("Address appears twice in input data", addr)
            uniq_addresses.add(addr)

        # Start distribution
        start_time = time.time()
        start_balance = from_wei(web3.eth.getBalance(address), "ether")

        tx_to_confirm = []   # List of txids to confirm
        tx_batch_size = 16  # How many transactions confirm once

        print("Total rows", len(rows))

        for i in range(start_from, min(start_from+limit, len(rows))):
            data = rows[i]
            addr = data[address_column].strip()
            tokens = Decimal(data[amount_column].strip())

            tokens *= decimal_multiplier

            end_balance = from_wei(web3.eth.getBalance(address), "ether")
            spent = start_balance - end_balance

            if tokens == 0:
                if not allow_zero:
                    raise RuntimeError("Encountered zero amount")
                else:
                    continue

            # http://stackoverflow.com/a/19965088/315168
            if not tokens % 1 == 0:
                raise RuntimeError("Could not issue tokens because after multiplication was not integer")

            transaction = {
                "from": address,
                "gasPrice": int(web3.eth.gasPrice * 1.5)
            }

            tokens = int(tokens)

            print("Row", i,  "giving", tokens, "to", addr, "issuer", issuer.address, "time passed", time.time() - start_time, "ETH passed", spent)

            if issuer.call().issued(addr):
                print("Already issued, skipping")
                continue

            txid = issuer.transact(transaction).issue(addr, tokens)

            tx_to_confirm.append(txid)

            # Confirm N transactions when batch max size is reached
            if len(tx_to_confirm) >= tx_batch_size:
                check_multiple_succesful_txs(web3, tx_to_confirm)
                tx_to_confirm = []

        # Confirm dangling transactions
        check_multiple_succesful_txs(web3, tx_to_confirm)

        end_balance = from_wei(web3.eth.getBalance(address), "ether")
        print("Deployment cost is", start_balance - end_balance, "ETH")
        print("All done! Enjoy your decentralized future.")
Exemplo n.º 7
0
 def _confirm_multiple_txs(*txids, timeout=180):
     check_multiple_succesful_txs(web3, txids, timeout=timeout)
def load(chain, web3: Web3, address: str, csv_file: str, token: Contract, address_column: str, amount_column: str, vault_address: str):

    decimals = token.call().decimals()
    decimal_multiplier = 10 ** decimals
    transaction = {"from": address}

    TokenVault = chain.contract_factories.TokenVault
    token_vault = TokenVault(address=vault_address)

    # Check that our tokens are the same
    assert token_vault.call().token().lower() == token.address.lower()

    print("Starting to import investor data to ", token_vault.address)

    print("Reading data", csv_file)
    with open(csv_file, "rt") as inp:
        reader = csv.DictReader(inp)
        rows = [row for row in reader]

    # Check that we have unique addresses
    uniq_addresses = set()
    total = 0
    for row in rows:
        addr = row[address_column].strip()
        amount = row[amount_column].strip()
        if addr in uniq_addresses:
            raise RuntimeError("Address appears twice in input data", addr)
        uniq_addresses.add(addr)
        amount = Decimal(amount)
        total += amount
        if amount <= 0:
            raise RuntimeError("Invalid amount:".format(amount))

    if token_vault.call().tokensToBeAllocated() != total * decimal_multiplier:
        raise RuntimeError("Expected total amount {}, CSV sum is {}".format(token_vault.call().tokensToBeAllocated(), total))

    # Start distribution
    start_time = time.time()
    start_balance = from_wei(web3.eth.getBalance(address), "ether")

    tx_to_confirm = []  # List of txids to confirm
    tx_batch_size = 16  # How many transactions confirm once

    print("Total rows", len(rows))

    for i in range(len(rows)):
        data = rows[i]
        addr = data[address_column].strip()
        tokens = Decimal(data[amount_column].strip())

        tokens *= decimal_multiplier

        end_balance = from_wei(web3.eth.getBalance(address), "ether")
        spent = start_balance - end_balance

        # http://stackoverflow.com/a/19965088/315168
        if not tokens % 1 == 0:
            raise RuntimeError("Could not issue tokens because after multiplication was not integer")

        tokens = int(tokens)

        print("Row", i, "giving", tokens, "to", addr, "vault", token_vault.address, "time passed", time.time() - start_time, "ETH spent", spent)

        if token_vault.call().balances(addr) > 0:
            print("Already issued, skipping")
            continue

        txid = token_vault.transact(transaction).setInvestor(addr, tokens)

        tx_to_confirm.append(txid)

        # Confirm N transactions when batch max size is reached
        if len(tx_to_confirm) >= tx_batch_size:
            check_multiple_succesful_txs(web3, tx_to_confirm)
            tx_to_confirm = []

    # Confirm dangling transactions
    check_multiple_succesful_txs(web3, tx_to_confirm)

    end_balance = from_wei(web3.eth.getBalance(address), "ether")
    print("Deployment cost is", start_balance - end_balance, "ETH")
 def _confirm_multiple_txs(*txids, timeout=180):
     check_multiple_succesful_txs(web3, txids, timeout=timeout)