예제 #1
0
def restart_nonce(
    logger: Logger,
    dbsession: Session,
    network: str,
    ethereum_node_url: str,
    ethereum_private_key: str,
    ethereum_gas_limit: str,
    ethereum_gas_price: str,
):
    check_good_private_key(ethereum_private_key)

    web3 = create_web3(ethereum_node_url)

    service = EthereumStoredTXService(network, dbsession, web3,
                                      ethereum_private_key, ethereum_gas_price,
                                      ethereum_gas_limit, BroadcastAccount,
                                      PreparedTransaction)

    service.ensure_accounts_in_sync()

    account = service.get_or_create_broadcast_account()
    txs = service.get_last_transactions(limit=1)
    if txs.count() > 0:
        raise HistoryDeleteNeeded(
            "Cannot reset nonce as the database contains txs for {}. Delete database to restart."
            .format(service.address))

    # read nonce from the network and record to the database
    tx_count = web3.eth.getTransactionCount(service.address)
    account.current_nonce = tx_count

    logger.info("Address %s, nonce is now set to %d", service.address,
                account.current_nonce)
    dbsession.flush()
예제 #2
0
파일: main.py 프로젝트: uivlis/sto
def payout_dividends(config: BoardCommmadConfiguration, transfer_amount):
    from sto.ethereum.utils import (get_contract_deployed_tx, create_web3,
                                    get_abi, broadcast as _broadcast)
    from sto.ethereum.txservice import EthereumStoredTXService
    from sto.models.implementation import BroadcastAccount, PreparedTransaction

    tx = get_contract_deployed_tx(config.dbsession, 'PayoutContract')
    if not tx:
        raise Exception(
            'PayoutContract not found. Call payout-deploy to deploy PayoutContract'
        )
    web3 = create_web3(config.ethereum_node_url)
    service = EthereumStoredTXService(config.network, config.dbsession, web3,
                                      config.ethereum_private_key,
                                      config.ethereum_gas_price,
                                      config.ethereum_gas_limit,
                                      BroadcastAccount, PreparedTransaction)
    abi = get_abi(config.ethereum_abi_file)
    service.interact_with_contract(
        contract_name='PayoutContract',
        abi=abi,
        address=tx.contract_address,
        note='transferring amount: {0}'.format(transfer_amount),
        func_name='act',
        args={'amount': transfer_amount})
    _broadcast(config)
예제 #3
0
파일: main.py 프로젝트: uivlis/sto
def payout_deposit(config: BoardCommmadConfiguration):
    """
    the private key here needs to belong to the customer who wants to fetch tokens
    """
    from sto.ethereum.utils import (get_contract_deployed_tx, create_web3,
                                    get_abi, broadcast as _broadcast)
    from sto.ethereum.txservice import EthereumStoredTXService
    from sto.models.implementation import BroadcastAccount, PreparedTransaction

    tx = get_contract_deployed_tx(config.dbsession, 'PayoutContract')
    if not tx:
        raise Exception(
            'PayoutContract not found. Call payout-deploy to deploy PayoutContract'
        )
    web3 = create_web3(config.ethereum_node_url)
    service = EthereumStoredTXService(config.network, config.dbsession, web3,
                                      config.ethereum_private_key,
                                      config.ethereum_gas_price,
                                      config.ethereum_gas_limit,
                                      BroadcastAccount, PreparedTransaction)

    abi = get_abi(config.ethereum_abi_file)
    service.interact_with_contract(contract_name='PayoutContract',
                                   abi=abi,
                                   address=tx.contract_address,
                                   note='calling fetchTokens',
                                   func_name='fetchTokens',
                                   args={})
    _broadcast(config)
예제 #4
0
파일: main.py 프로젝트: uivlis/sto
def payout_approve(
    config: BoardCommmadConfiguration,
    payout_token_address: str,
    payout_token_name: str,
):
    """
    approve tokens to the payout contract
    """
    from sto.ethereum.utils import (get_contract_deployed_tx, create_web3,
                                    get_abi, broadcast as _broadcast,
                                    priv_key_to_address)
    from sto.ethereum.txservice import EthereumStoredTXService
    from sto.models.implementation import BroadcastAccount, PreparedTransaction

    tx = get_contract_deployed_tx(config.dbsession, 'PayoutContract')
    if not tx:
        raise Exception(
            'PayoutContract not found. Call payout-deploy to deploy PayoutContract'
        )
    if payout_token_name:
        tx = get_contract_deployed_tx(config.dbsession, payout_token_name)
        payout_token_address = tx.contract_address
    if payout_token_address is None:
        raise Exception('''
            Either payout token is not deployed or --payout-token-address not provided
            ''')
    tx = get_contract_deployed_tx(config.dbsession, 'PayoutContract')
    if not tx:
        raise Exception(
            'PayoutContract not found. Call payout-deploy to deploy PayoutContract'
        )
    payout_contract_address = tx.contract_address

    web3 = create_web3(config.ethereum_node_url)
    service = EthereumStoredTXService(config.network, config.dbsession, web3,
                                      config.ethereum_private_key,
                                      config.ethereum_gas_price,
                                      config.ethereum_gas_limit,
                                      BroadcastAccount, PreparedTransaction)
    abi = get_abi(config.ethereum_abi_file)
    payout_token_contract = web3.eth.contract(
        address=payout_token_address, abi=abi[payout_token_name]['abi'])
    service.interact_with_contract(
        payout_token_name,
        abi,
        payout_token_address,
        'approving tokens',
        'approve',
        args={
            '_spender':
            payout_contract_address,
            '_value':
            payout_token_contract.functions.balanceOf(
                priv_key_to_address(config.ethereum_private_key)).call()
        },
        use_bytecode=False)
    _broadcast(config)
예제 #5
0
파일: broadcast.py 프로젝트: uivlis/sto
def broadcast(
    logger: Logger,
    dbsession: Session,
    network: str,
    ethereum_node_url: Union[str, Web3],
    ethereum_private_key: str,
    ethereum_gas_limit: Optional[str],
    ethereum_gas_price: Optional[str],
    commit=True,
):
    """Issue out a new Ethereum token."""

    check_good_private_key(ethereum_private_key)

    web3 = create_web3(ethereum_node_url)

    service = EthereumStoredTXService(network, dbsession, web3,
                                      ethereum_private_key, ethereum_gas_price,
                                      ethereum_gas_limit, BroadcastAccount,
                                      PreparedTransaction)

    service.ensure_accounts_in_sync()

    pending_broadcasts = service.get_pending_broadcasts()

    logger.info("Pending %d transactions for broadcasting in network %s",
                pending_broadcasts.count(), network)

    if pending_broadcasts.count() == 0:
        logger.info(
            "No new transactions to broadcast. Use sto tx-update command to see tx status."
        )
        return []

    account = Account.privateKeyToAccount(ethereum_private_key)
    balance = web3.eth.getBalance(account.address)

    logger.info("Our address %s has ETH balance of %f for operations",
                account.address, from_wei(balance, "ether"))

    txs = list(pending_broadcasts)
    # https://stackoverflow.com/questions/41985993/tqdm-show-progress-for-a-generator-i-know-the-length-of
    for tx in tqdm(txs, total=pending_broadcasts.count()):
        try:
            service.broadcast(tx)
            # logger.info("Broadcasted %s", tx.txid)
        except Exception as e:
            logger.exception(e)
            logger.error("Failed to broadcast transaction %s: %s", tx.txid,
                         tx.human_readable_description)
            raise e

        if commit:
            dbsession.commit()  # Try to minimise file system sync issues

    return txs
예제 #6
0
def distribute_single(logger: Logger, dbsession: Session, network: str,
                      ethereum_node_url: Union[str, Web3],
                      ethereum_abi_file: Optional[str],
                      ethereum_private_key: Optional[str],
                      ethereum_gas_limit: Optional[int],
                      ethereum_gas_price: Optional[int], token_address: str,
                      ext_id: str, email: str, name: str, to_address: str,
                      amount: Decimal) -> bool:
    """Send out a single transfer.

    :return: True if a new tx for broadcasting was created
    """

    d = DistributionEntry(ext_id, email, name, to_address, amount)

    check_good_private_key(ethereum_private_key)

    abi = get_abi(ethereum_abi_file)

    web3 = create_web3(ethereum_node_url)

    service = EthereumStoredTXService(network, dbsession, web3,
                                      ethereum_private_key, ethereum_gas_price,
                                      ethereum_gas_limit, BroadcastAccount,
                                      PreparedTransaction)

    logger.info(
        "Starting creating distribution transactions for %s token from nonce %s",
        token_address, service.get_next_nonce())

    total = d.amount * 10**18

    available = service.get_raw_token_balance(token_address, abi)
    if total > available:
        raise NotEnoughTokens(
            "Not enough tokens for distribution. Account {} has {} raw token balance, needed {}"
            .format(service.get_or_create_broadcast_account().address,
                    available, total))

    if not service.is_distributed(d.external_id, token_address):
        # Going to tx queue
        raw_amount = int(d.amount * 10**18)
        note = "Distributing tokens, raw amount: {}".format(raw_amount)
        service.distribute_tokens(d.external_id, d.address, raw_amount,
                                  token_address, abi, note)
        logger.info("New broadcast has been created")
        return True
    else:
        logger.error("Already distributed")
        return False
예제 #7
0
def distribute_tokens(logger: Logger, dbsession: Session, network: str,
                      ethereum_node_url: Union[str, Web3],
                      ethereum_abi_file: Optional[str],
                      ethereum_private_key: Optional[str],
                      ethereum_gas_limit: Optional[int],
                      ethereum_gas_price: Optional[int], token_address: str,
                      dists: List[DistributionEntry]) -> Tuple[int, int]:
    """Sends tokens to their first owners in primary markets."""

    check_good_private_key(ethereum_private_key)

    abi = get_abi(ethereum_abi_file)

    web3 = create_web3(ethereum_node_url)

    service = EthereumStoredTXService(network, dbsession, web3,
                                      ethereum_private_key, ethereum_gas_price,
                                      ethereum_gas_limit, BroadcastAccount,
                                      PreparedTransaction)

    logger.info(
        "Starting creating distribution transactions for %s token from nonce %s",
        token_address, service.get_next_nonce())

    total = sum([dist.amount * 10**18 for dist in dists])

    available = service.get_raw_token_balance(token_address, abi)
    if total > available:
        raise NotEnoughTokens(
            "Not enough tokens for distribution. Account {} has {} raw token balance, needed {}"
            .format(service.get_or_create_broadcast_account().address,
                    available, total))

    new_distributes = old_distributes = 0

    for d in tqdm(dists):
        if not service.is_distributed(d.external_id, token_address):
            # Going to tx queue
            raw_amount = int(d.amount * 10**18)
            note = "Distributing tokens, raw amount: {}".format(raw_amount)
            service.distribute_tokens(d.external_id, d.address, raw_amount,
                                      token_address, abi, note)
            new_distributes += 1
        else:
            # CSV reimports
            old_distributes += 1

    logger.info("Prepared transactions for broadcasting for network %s",
                network)
    return new_distributes, old_distributes
예제 #8
0
파일: issuance.py 프로젝트: mandlamag/sto
def contract_status(logger: Logger, dbsession: Session, network: str,
                    ethereum_node_url: str, ethereum_abi_file: str,
                    ethereum_private_key: str, ethereum_gas_limit: str,
                    ethereum_gas_price: str, token_contract: str):
    """Poll STO contract status."""

    abi = get_abi(ethereum_abi_file)

    web3 = create_web3(ethereum_node_url)

    service = EthereumStoredTXService(network, dbsession, web3,
                                      ethereum_private_key, ethereum_gas_price,
                                      ethereum_gas_limit, BroadcastAccount,
                                      PreparedTransaction)
    contract = service.get_contract_proxy("SecurityToken", abi, token_contract)

    try:
        logger.info("Name: %s", contract.functions.name().call())
        logger.info("Symbol: %s", contract.functions.symbol().call())
        supply = contract.functions.totalSupply().call()
        human_supply = Decimal(supply) / Decimal(
            10**contract.functions.decimals().call())
        raw_balance = contract.functions.balanceOf(
            service.get_or_create_broadcast_account().address).call()
        normal_balance = Decimal(raw_balance) / Decimal(
            10**contract.functions.decimals().call())
        logger.info("Total supply: %s", human_supply)
        logger.info("Decimals: %d", contract.functions.decimals().call())
        logger.info("Owner: %s", contract.functions.owner().call())
        logger.info("Broadcast account token balance: %f", normal_balance)
        logger.info("Transfer verified: %s",
                    contract.functions.transferVerifier().call())
    except BadFunctionCallOutput as e:
        raise BadContractException(
            "Looks like this is not a token contract address. Please check on EtherScan that the address presents the token contract"
        )

    return {
        "name": contract.functions.name().call(),
        "symbol": contract.functions.symbol().call(),
        "totalSupply": contract.functions.totalSupply().call(),
        "broadcastBalance": raw_balance,
    }
예제 #9
0
파일: status.py 프로젝트: uivlis/sto
def update_status(
    logger: Logger,
    dbsession: Session,
    network: str,
    ethereum_node_url: Union[str, Web3],
    ethereum_private_key: str,
    ethereum_gas_limit: str,
    ethereum_gas_price: str,
    commit=True,
):
    """Issue out a new Ethereum token."""

    check_good_private_key(ethereum_private_key)

    web3 = create_web3(ethereum_node_url)

    service = EthereumStoredTXService(network, dbsession, web3,
                                      ethereum_private_key, ethereum_gas_price,
                                      ethereum_gas_limit, BroadcastAccount,
                                      PreparedTransaction)

    unfinished_txs = service.get_unmined_txs()

    logger.info(
        "Updating status for %d unfinished transactions for broadcasting in network %s",
        unfinished_txs.count(), network)

    if unfinished_txs.count() == 0:
        logger.info(
            "No transactions to update. Use sto tx-last command to show the status of the last transactions."
        )
        return []

    unfinished_txs = list(unfinished_txs)

    # https://stackoverflow.com/questions/41985993/tqdm-show-progress-for-a-generator-i-know-the-length-of
    for tx in tqdm(unfinished_txs):
        service.update_status(tx)
        if commit:
            dbsession.commit()  # Try to minimise file system sync issues

    return unfinished_txs
예제 #10
0
def next_nonce(
    logger: Logger,
    dbsession: Session,
    network: str,
    ethereum_node_url: str,
    ethereum_private_key: str,
    ethereum_gas_limit: str,
    ethereum_gas_price: str,
):
    check_good_private_key(ethereum_private_key)

    web3 = create_web3(ethereum_node_url)

    service = EthereumStoredTXService(network, dbsession, web3,
                                      ethereum_private_key, ethereum_gas_price,
                                      ethereum_gas_limit, BroadcastAccount,
                                      PreparedTransaction)
    account = service.get_or_create_broadcast_account()
    ft = pretty_date(account.created_at)
    logger.info("Address %s, created at %s, nonce is now set to %d",
                service.address, ft, account.current_nonce)
예제 #11
0
파일: last.py 프로젝트: uivlis/sto
def get_last_transactions(logger: Logger,
              dbsession: Session,
              network: str,
              limit: int,
              ethereum_node_url: str,
              ethereum_private_key: str,
              ethereum_gas_limit: str,
              ethereum_gas_price: str,
):
    """Issue out a new Ethereum token."""

    check_good_private_key(ethereum_private_key)

    web3 = create_web3(ethereum_node_url)

    service = EthereumStoredTXService(network, dbsession, web3, ethereum_private_key, ethereum_gas_price, ethereum_gas_limit, BroadcastAccount, PreparedTransaction)

    last_txs = service.get_last_transactions(limit)
    if last_txs.count() == 0:
        logger.info("No transactions yet")
        return []

    return list(last_txs)
예제 #12
0
파일: issuance.py 프로젝트: mandlamag/sto
def deploy_token_contracts(
        logger: Logger, dbsession: Session, network: str,
        ethereum_node_url: Union[str, Web3], ethereum_abi_file: Optional[str],
        ethereum_private_key: Optional[str], ethereum_gas_limit: Optional[int],
        ethereum_gas_price: Optional[int], name: str, symbol: str, url: str,
        amount: int, transfer_restriction: str):
    """Issue out a new Ethereum token."""

    assert type(amount) == int
    decimals = 18  # Everything else is bad idea

    check_good_private_key(ethereum_private_key)

    abi = get_abi(ethereum_abi_file)

    web3 = create_web3(ethereum_node_url)

    # We do not have anything else implemented yet
    assert transfer_restriction == "unrestricted"

    service = EthereumStoredTXService(network, dbsession, web3,
                                      ethereum_private_key, ethereum_gas_price,
                                      ethereum_gas_limit, BroadcastAccount,
                                      PreparedTransaction)

    # Deploy security token
    note = "Deploying token contract for {}".format(name)
    deploy_tx1 = service.deploy_contract("SecurityToken",
                                         abi,
                                         note,
                                         constructor_args={
                                             "_name": name,
                                             "_symbol": symbol,
                                             "_url": url
                                         })  # See SecurityToken.sol

    # Deploy transfer agent
    note = "Deploying unrestricted transfer policy for {}".format(name)
    deploy_tx2 = service.deploy_contract("UnrestrictedTransferAgent", abi,
                                         note)

    # Set transfer agent
    note = "Making transfer restriction policy for {} effective".format(name)
    contract_address = deploy_tx1.contract_address
    update_tx1 = service.interact_with_contract(
        "SecurityToken", abi, contract_address, note, "setTransactionVerifier",
        {"newVerifier": deploy_tx2.contract_address})

    # Issue out initial shares
    note = "Creating {} initial shares for {}".format(amount, name)
    contract_address = deploy_tx1.contract_address
    amount_18 = int(amount * 10**decimals)
    update_tx2 = service.interact_with_contract("SecurityToken", abi,
                                                contract_address, note,
                                                "issueTokens",
                                                {"value": amount_18})

    logger.info("Prepared transactions for broadcasting for network %s",
                network)
    logger.info("STO token contract address will be %s%s%s",
                colorama.Fore.LIGHTGREEN_EX, deploy_tx1.contract_address,
                colorama.Fore.RESET)
    return [deploy_tx1, deploy_tx2, update_tx1, update_tx2]
예제 #13
0
def diagnose(logger: Logger,
             node_url: str,
             private_key_hex: str,
             check_timestamps=True) -> Optional[Exception]:
    """Run Ethereum connection and account diagnostics.

    Check that the user has properly configured Ethereum node and private key.

    Never fails. Exceptions are written to the logger output and returned.
    """

    try:
        check_good_node_url(node_url)

        logger.info("Attempting to connect to Ethereum node %s", node_url)
        web3 = create_web3(node_url)

        logger.info("Connected to Ethereum node software %s",
                    web3.version.node)

        block_num = web3.eth.blockNumber

        d = datetime.datetime.utcnow()
        unix_time = calendar.timegm(d.utctimetuple())

        block_info = web3.eth.getBlock(block_num)
        last_time = block_info["timestamp"]

        if check_timestamps:
            if last_time == 0:
                raise NodeNotSynced(
                    "Looks like your node has not yet been synced.")

            ago = unix_time - last_time

            logger.info(
                "Current Ethereum node block number: %d, last block %d seconds ago - compare this to data on https://etherscan.io",
                block_num, ago)

            if ago < 0:
                raise NodeNotSynced(
                    "Last block in the future? Do we have a clock with a wrong timezone somewhere?"
                )

            if ago > 1800:
                raise NodeNotSynced(
                    "Looks like your node has not received a block for half an hour. It is most likely unsynced at the moment."
                )

        check_good_private_key(private_key_hex)

        logger.info("Using private key %s...", private_key_hex[0:3])
        account = Account.privateKeyToAccount(to_bytes(hexstr=private_key_hex))

        balance = web3.eth.getBalance(account.address)
        logger.info("Address %s has ETH balance of %f", account.address,
                    from_wei(balance, "ether"))

        if balance == 0:
            raise NeedMoney(
                "Your Ethereum account {} needs to have ETH in order to use this tool"
                .format(account.address))

    except Exception as e:

        logger.error("Diagnostics failure")
        logger.exception(e)
        return e