Пример #1
0
 def update_denormalised_balance(self):
     """Denormalise the balance for this account."""
     raw_balance, last_block_num, last_block_at = self.calculate_sum_from_deltas()
     self.set_balance_uint(raw_balance)
     self.last_block_updated_at = last_block_at
     self.last_block_num = last_block_num
     self.balance_calculated_at = now()
Пример #2
0
    def broadcast(self, tx: _PreparedTransaction):
        """Push transactions to Ethereum network."""

        if tx.broadcast_account.address != self.address:
            raise AddressConfigurationMismatch("Could not broadcast due to address mismatch. A pendign transaction was created for account {}, but we are using configured account {}".format(tx.broadcast_account.addres, self.address))

        tx_data = tx.unsigned_payload
        signed = self.web3.eth.account.signTransaction(tx_data, self.private_key_hex)
        tx.txid = signed.hash.hex()
        self.web3.eth.sendRawTransaction(signed.rawTransaction)
        tx.broadcasted_at = now()
        return tx
Пример #3
0
    def update_status(self, tx: _PreparedTransaction):
        """Update tx status from Etheruem network."""

        assert tx.txid

        # https://web3py.readthedocs.io/en/stable/web3.eth.html#web3.eth.Eth.getTransactionReceipt
        receipt = self.web3.eth.getTransactionReceipt(tx.txid)
        if receipt:
            tx.result_block_num = receipt["blockNumber"]

            # https://ethereum.stackexchange.com/a/6003/620
            if receipt["status"] == 0:
                tx.result_transaction_success = False
                tx.result_transaction_reason = "Transaction failed"  # TODO: Need some logic to separate failure modes
            else:
                tx.result_transaction_success = True

        tx.result_fetched_at = now()
        return tx
Пример #4
0
def verify_on_etherscan(logger: Logger, network: str, tx: _PreparedTransaction, api_key: str, session, timeout=120):
    """Verify a contrcact deployment on Etherscan.

    Uses https://etherscan.io/apis#contracts
    """

    assert network in ("ethereum", "kovan", "ropsten", "rinkerby")
    if network != "ethereum":
        url = "https://api-{}.etherscan.io/api".format(network)
    else:
        url = "https://api.etherscan.io/api"

    assert tx.result_transaction_success
    assert tx.contract_deployment

    source = tx.flattened_source_code

    assert source.strip(), "Source code missing"

    compiler = tx.compiler_version
    address = tx.contract_address
    constructor_arguments = tx.constructor_arguments
    contract_name = tx.contract_name

    data = {
        "apikey": api_key,
        "module": "contract",
        "contractaddress": address,
        "action": "verifysourcecode",
        "sourceCode": source,
        "contractname": contract_name,
        "compilerversion": "v" + compiler,  # https://etherscan.io/solcversions
        "constructorArguements": constructor_arguments[2:],  # Remove leading 0x
        "optimizationUsed": 1,  # TODO: Hardcoded
        "runs": 500, # TODO: Hardcoded
    }

    info_data = data.copy()
    del info_data["sourceCode"]  # Too verbose
    del info_data["apikey"]  # Security
    logger.info("Calling EtherScan API as: %s", info_data)

    #
    # Step 1: EtherScan validates input and gives us a ticket id to track the submission status
    #

    resp = session.post(url, data)
    # {'status': '0', 'message': 'NOTOK', 'result': 'Error!'}
    data = resp.json()

    logger.info("Etherscan replied %s", data)
    if data["status"] == "0":

        if "already verified" in data["result"]:
            return

        raise CouldNotVerifyOnEtherScan("Could not verify contract: " + address + " " + str(data))


    ticket = data["result"]

    #
    # Step 2: Poll for results
    #
    ready = False
    started = time.time()
    while not ready and time.time() < started + timeout:
        data = {
            "apikey": api_key,
            "module": "contract",
            "action": "checkverifystatus",
            "guid": ticket,
        }
        logger.info("Checking verification status on EtherScan API as: %s", info_data)
        resp = session.post(url, data)
        # {'status': '0', 'message': 'NOTOK', 'result': 'Error!'}
        data = resp.json()
        logger.info("Got reply %s", data)

        if data["result"] == "Pending in queue":
            # Keep polling
            #  {'status': '0', 'message': 'NOTOK', 'result': 'Pending in queue'}
            time.sleep(5)
            continue
        elif data["status"] == "0":
            # Produced binary did not match
            raise CouldNotVerifyOnEtherScan("Could not verify contract: " + address + " " + str(data))
        else:
            # All good
            assert data["status"] == "1"  # {'status': '1', 'message': 'OK', 'result': 'Pass - Verified'}
            break

    # Write to the database that we managed verify the contract
    tx.verified_at = now()
    tx.verification_info = data