Example #1
0
 def check_block(self, block_info, operator):
     """检查区块是否回滚"""
     if not block_info:
         return False
     info = operator.get_block(int(block_info.block_num) + 1)
     if not info:
         return False
     if hexstr_if_str(to_hex, info['parentHash']) == block_info.block_hash:
         checked_block = {
             'block_num': int(info['number']),
             'block_hash': hexstr_if_str(to_hex, info['hash']),
             'coin_type': self.coin_category
         }
     else:
         new_block_info = {
             'coin':
             self.coin_category,
             'block_num':
             int(block_info.block_num) - int(config.etc_confirmations),
         }
         roll_back_info = operator.get_block(new_block_info['block_num'])
         new_block_info['block_hash'] = hexstr_if_str(
             to_hex, roll_back_info['hash'])
         # self.block_info_coll.update_one({'coin_type': self.coin_category},
         #                                 {'$set': new_block_info})
         checked_block = {
             'block_num': int(roll_back_info['number']),
             'block_hash': hexstr_if_str(to_hex, roll_back_info['hash']),
             'coin_type': self.coin_category
         }
     return checked_block
Example #2
0
def check_block(block_info, operator: ERC20Token):
    """检查区块是否回滚"""
    if not block_info:
        return False
    info = operator.get_block(int(block_info.block_num) + 1)
    if not info:
        return False
    if hexstr_if_str(to_hex, info['parentHash']) == block_info.block_hash:
        new_block_info = {
            'block_num': int(info['number']),
            'block_hash': hexstr_if_str(to_hex, info['hash']),
            'coin_type': coin_type
        }
    else:
        new_block_info = {
            'coin_type': coin_type,
            'block_num':
            int(block_info.block_num) - int(config.eth_confirmations),
        }
        roll_back_info = operator.get_block(new_block_info['block_num'])
        new_block_info['block_hash'] = hexstr_if_str(to_hex,
                                                     roll_back_info['hash'])
        new_block_info = {
            'block_num': int(roll_back_info['number']),
            'block_hash': hexstr_if_str(to_hex, roll_back_info['hash']),
            'coin_type': coin_type
        }
    return new_block_info
Example #3
0
def test_hexstr_if_str_invalid_hex_py2(val, converter):
    try:
        is_hexstr = (is_hex(val) or val == '')
    except ValueError:
        is_hexstr = False

    if not is_hexstr:
        with pytest.raises(ValueError):
            hexstr_if_str(converter, val)
Example #4
0
def test_hexstr_if_str_on_invalid_hex(val):
    try:
        is_hexstr = (is_hex(val) or val == '')
    except ValueError:
        is_hexstr = False

    if not is_hexstr:
        with pytest.raises(ValueError):
            hexstr_if_str(Mock(), val)
Example #5
0
def test_hexstr_if_str_on_invalid_hex(val):
    try:
        is_hexstr = (is_hex(val) or val == '')
    except ValueError:
        is_hexstr = False

    if not is_hexstr:
        with pytest.raises(ValueError):
            hexstr_if_str(Mock(), val)
Example #6
0
 def withdraw_eth(cls, address, amount):
     private_key = hexstr_if_str(to_hex,
                                 load_keyfile(config.eth_private_key_file,
                                              config.eth_password)
                                 )
     eth = ERC20Token(provider_endpoint=config.eth_wallet_url,
                      private_key=private_key,
                      password=config.eth_password)
     checksum_address = eth.web3.toChecksumAddress(address)
     try:
         tx_id = eth.send_ether(checksum_address, amount)
         tb = {
             'amount': amount,
             'txid': tx_id,
             'coin_type': 'ETH',
             'from_address': config.eth_tb_address,
             'to_address': address,
             'status': TbStatusEnum.TRANSFER
         }
     except Exception as e:
         logger.exception(e)
     else:
         try:
             
             document = TbRecord(**tb)
             document.insert()
             return tx_id
         except Exception as e:
             logger.exception(e)
             logger.error("提币行为已经发生,但数据没有插入数据库{}".format(tb))
Example #7
0
    def send2address(self, address, amount, *args, **kwargs):
        password = config.etc_password
        private_key = hexstr_if_str(
            to_hex, load_keyfile(config.etc_private_key_file, password))
        eth = ERC20Token(ipc_path=config.etc_ipc_path,
                         private_key=private_key,
                         password=password)
        checksum_address = eth.web3.toChecksumAddress(address)
        try:
            tx_id = eth.send_ether(checksum_address, amount)
            tb = {
                'amount': amount,
                'txid': tx_id,
                'coin_type': 'ETC',
                'from_address': config.etc_tb_address,
                'to_address': address,
            }
        except Exception as e:
            logger.exception(e)
        else:
            try:

                document = TbRecord(**tb)
                document.insert()
                return tx_id
            except Exception as e:
                logger.exception(e)
                logger.error("提币行为已经发生,但数据没有插入数据库{}".format(tb))
Example #8
0
 def poll(self):
     logger.info('-----------etc_recharge start-----------')
     session = Session()
     self.init_block_info(session)
     while True:
         try:
             operator = self.erc_op_class(ipc_path=config.etc_ipc_path)
             # 获取区块信息及交易列表
             block_info = session.query(self.block_info_coll).filter_by(
                 coin_type=self.coin_category).first()
             checked_block_info = self.check_block(block_info, operator)
             if not checked_block_info:
                 continue
             tx_list = operator.get_block_tx_id_list(
                 checked_block_info['block_num'])
             # 遍历交易列表
             for tx_id in tx_list:
                 self.tx_process(session, hexstr_if_str(to_hex, tx_id),
                                 operator)
             logger.info(
                 f'pull block finished: {checked_block_info["block_num"]}')
         except Exception as e:
             logger.exception(e)
         else:
             # 存储交易区块信息
             block_info.block_num = checked_block_info['block_num']
             block_info.block_hash = checked_block_info['block_hash']
             try:
                 session.commit()
             except Exception as e:
                 logger.exception("检查回滚区块时发生错误{}".format(e))
                 session.rollback()
         time.sleep(3)
Example #9
0
 def ask_fee(self, session, item):
     password = config.eth_password
     private_key = hexstr_if_str(to_hex,
                                 load_keyfile(config.eth_private_key_file,
                                              password)
                                 )
     now = datetime.datetime.utcnow()
     eth = self.erc_op_class(provider_endpoint=config.eth_wallet_url,
                             private_key=private_key,
                             password=password)
     try:
         amount = item.amount
         tx_id = eth.send_ether(item.to_address, amount)
         logger.info(f'ETH withdraw ask fee done: {item.to_address} '
                     f'{amount}')
     except Exception as e:
         logger.exception("缴费转账时发生错误{}".format(e))
         item.status = AskFeeStatusEnum.ASK_FAILED
         item.updated_at = now
         item.error_msg = e
         try:
             session.commit()
         except Exception as e:
             logger.exception("缴费发生错误时更改状态也错误{}".format(e))
             session.rollback()
     else:
         item.status = AskFeeStatusEnum.WAIT_CONFIRM
         item.updated_at = now
         item.txid = tx_id
         try:
             session.commit()
         except Exception as e:
             logger.exception("缴费成功时更改状态错误{}".format(e))
             session.rollback()
Example #10
0
def main():
    session = Session()
    init_block_info(session)
    while True:
        try:
            operator = ERC20Token(provider_endpoint=config.eth_wallet_url)
            # 获取区块信息及交易列表
            block_info = session.query(block_info_document).filter_by(
                coin_type=coin_type).first()
            checked_block_info = check_block(block_info, operator)

            if not checked_block_info:
                continue

            tx_list = operator.get_block_tx_id_list(
                checked_block_info['block_num'])
            # 遍历交易列表
            for tx_id in tx_list:
                tx_process(session, hexstr_if_str(to_hex, tx_id), operator)
            logger.info(
                f'pull block finished: {checked_block_info["block_num"]}')
        except Exception as e:
            logger.exception(e)
        else:
            block_info.block_hash = checked_block_info['block_hash']
            block_info.block_num = checked_block_info['block_num']
            try:
                session.commit()
            except Exception as e:
                logger.exception("更新区块发生错误{}".format(e))
                session.rollback()
        time.sleep(3)
Example #11
0
def init_block_info(session):
    """第一次初始化数据库区块信息"""
    block_info = session.query(BlockInfo).filter_by(
        coin_type=coin_type).first()
    if block_info:
        return

    while True:
        try:
            operator = ERC20Token(provider_endpoint=config.eth_wallet_url)
            info = operator.get_block(int(operator.get_block_number()))
            block_info = BlockInfo(
                **{
                    'block_num': int(info['number']),
                    'block_hash': hexstr_if_str(to_hex, info['hash']),
                    'coin_type': coin_type
                })
            session.add(block_info)
            session.commit()
            logger.info('block_info init success')
            break
        except Exception as e:
            logger.exception("初始化区块失败{}".format(e))
            session.rollback()
        time.sleep(15)
Example #12
0
 def sign(self,
          message=None,
          private_key=None,
          message_hexstr=None,
          message_text=None):
     '''
     @param private_key in bytes, str, or int.
         In Python 2, a bytes, unicode or str object will be interpreted as hexstr
         In Python 3, only a str object will be interpreted as hexstr
     '''
     msg_bytes = to_bytes(message, hexstr=message_hexstr, text=message_text)
     msg_hash = self.hashMessage(msg_bytes)
     key_bytes = hexstr_if_str(to_bytes, private_key)
     key = self._keys.PrivateKey(key_bytes)
     (v, r, s, eth_signature_bytes) = sign_message_hash(key, msg_hash)
     (r_hex, s_hex, eth_signature_hex) = map(to_hex,
                                             (r, s, eth_signature_bytes))
     return AttributeDict({
         'message': msg_bytes,
         'messageHash': msg_hash,
         'r': r_hex,
         's': s_hex,
         'v': v,
         'signature': eth_signature_hex,
     })
Example #13
0
 def recoverTransaction(self, serialized_transaction):
     txn_bytes = hexstr_if_str(to_bytes, serialized_transaction)
     txn = Transaction.from_bytes(txn_bytes)
     msg_hash = hash_of_signed_transaction(txn)
     if sys.version_info.major < 3:
         msg_hash = to_hex(msg_hash)
     return self.recover(msg_hash, vrs=vrs_from(txn))
Example #14
0
    def send_tokens(self, address, amount):
        """Send tokens from my wallet to address.

        :param str address: the address to send tokens to.

        :param Decimal amount: the amount of tokens to transfer.

        :returns: transaction id (hash)
        :rtype: str

        :raises: :class:`~erc20token.exceptions.SdkConfigurationError`: if the SDK was not configured with a private key.
        :raises: ValueError: if the amount is not positive.
        :raises: ValueError: if the address has a wrong format.
        :raises: ValueError: if the nonce is incorrect.
        :raises: ValueError: if insufficient funds for for gas * gas_price.
        """
        if not self.address:
            raise SdkNotConfiguredError('private key not configured')
        validate_address(address)
        if amount <= 0:
            raise ValueError('amount must be positive')
        hex_data = self.token_contract._encode_transaction_data(
            'transfer', args=(address, self.web3.toWei(amount, 'ether')))
        data = hexstr_if_str(to_bytes, hex_data)
        return self._tx_manager.send_transaction(self.token_contract.address,
                                                 0, data)
Example #15
0
 def recover(self, msghash, vrs=None, signature=None):
     hash_bytes = hexstr_if_str(to_bytes, msghash)
     if vrs is not None:
         v, r, s = map(hexstr_if_str(to_decimal), vrs)
         v_standard = to_standard_v(v)
         signature_obj = self._keys.Signature(vrs=(v_standard, r, s))
     elif signature is not None:
         signature_bytes = hexstr_if_str(to_bytes, signature)
         signature_bytes_standard = to_standard_signature_bytes(
             signature_bytes)
         signature_obj = self._keys.Signature(
             signature_bytes=signature_bytes_standard)
     else:
         raise TypeError(
             "You must supply the vrs tuple or the signature bytes")
     pubkey = signature_obj.recover_public_key_from_msg_hash(hash_bytes)
     return pubkey.to_checksum_address()
Example #16
0
def abi_bytes_to_hex(abi_type, data):
    base, sub, arrlist = process_type(abi_type)
    if base == 'bytes' and not arrlist:
        bytes_data = hexstr_if_str(to_bytes, data)
        if len(bytes_data) != int(sub):
            raise ValueError(
                "This value was expected to be %d bytes, but instead was %d: %r"
                % ((sub, len(bytes_data), data)))
        return abi_type, to_hex(bytes_data)
Example #17
0
 def privateKeyToAccount(self, private_key):
     key_bytes = hexstr_if_str(to_bytes, private_key)
     try:
         key_obj = self._keys.PrivateKey(key_bytes)
         return LocalAccount(key_obj, self)
     except ValidationError as original_exception:
         raise_from(
             ValueError(
                 "The private key must be exactly 32 bytes long, instead of "
                 "%d bytes." % len(key_bytes)), original_exception)
Example #18
0
 def _retrieve_head_block(self):
     while True:
         try:
             block_num = self.wallet_op.get_block_number()
             block_ = self.wallet_op.get_block(block_num)
         except Exception as e:
             logger.exception(e)
         else:
             block_['hash'] = hexstr_if_str(to_hex, block_['hash'])
             return block_
Example #19
0
    def list_transactions(self):
        while True:
            next_ = self.wallet_op.get_block(self.block_num + 1)
            if not next_:
                raise StopIteration

            # check chain block_record conformity
            if hexstr_if_str(to_hex, next_['parentHash']) == self.block_hash:
                self.block_num = int(next_['number'])
                self.block_hash = int(next_['hash'])
            else:
                rollback_num = self.block_num - self.confirmation_count
                rollback_ = self.wallet_op.get_block(rollback_num)
                self.block_num = hexstr_if_str(to_hex, rollback_['number'])
                self.block_hash = hexstr_if_str(to_hex, rollback_['hash'])

            txids = self.wallet_op.get_block_tx_id_list(self.block_num)
            for txid in txids:
                tran = self.wallet_op.get_transaction_data(txid)
                yield tran

            self.block_record.save_head_block(
                dict(block_num=self.block_num, block_hash=self.block_hash))
Example #20
0
 def recover(self, msghash, vrs=None, signature=None):
     hash_bytes = HexBytes(msghash)
     if vrs is not None:
         v, r, s = map(hexstr_if_str(to_int), vrs)
         v_standard = to_standard_v(v)
         signature_obj = self._keys.Signature(vrs=(v_standard, r, s))
     elif signature is not None:
         signature_bytes = HexBytes(signature)
         signature_bytes_standard = to_standard_signature_bytes(signature_bytes)
         signature_obj = self._keys.Signature(signature_bytes=signature_bytes_standard)
     else:
         raise TypeError("You must supply the vrs tuple or the signature bytes")
     pubkey = signature_obj.recover_public_key_from_msg_hash(hash_bytes)
     return pubkey.to_checksum_address()
Example #21
0
def abi_bytes_to_hex(abi_type, data):
    base, sub, arrlist = process_type(abi_type)
    if base == 'bytes' and not arrlist:
        bytes_data = hexstr_if_str(to_bytes, data)
        if not sub:
            return abi_type, to_hex(bytes_data)
        else:
            num_bytes = int(sub)
            if len(bytes_data) <= num_bytes:
                padded = bytes_data.ljust(num_bytes, b'\0')
                return abi_type, to_hex(padded)
            else:
                raise ValueError(
                    "This value was expected to be at most %d bytes, but instead was %d: %r"
                    % ((num_bytes, len(bytes_data), data)))
Example #22
0
def abi_bytes_to_hex(abi_type, data):
    base, sub, arrlist = process_type(abi_type)
    if base == 'bytes' and not arrlist:
        bytes_data = hexstr_if_str(to_bytes, data)
        if not sub:
            return abi_type, to_hex(bytes_data)
        else:
            num_bytes = int(sub)
            if len(bytes_data) <= num_bytes:
                padded = bytes_data.ljust(num_bytes, b'\0')
                return abi_type, to_hex(padded)
            else:
                raise ValueError(
                    "This value was expected to be at most %d bytes, but instead was %d: %r" % (
                        (num_bytes, len(bytes_data), data)
                    )
                )
Example #23
0
 def withdraw_token(cls, to_address, amount, coin_type):
     token_info = CoinSetting.find_one({'id': coin_type,
                                        'main_coin': 'ETH'})
     if not token_info:
         logger.warning('不存在的币种类型{}'.format(coin_type))
         return
     token_address = token_info['token_address']
     private_key = hexstr_if_str(to_hex,
                                 load_keyfile(config.eth_private_key_file,
                                              config.eth_password)
                                 )
     token = ERC20Token(
         provider_endpoint=config.eth_wallet_url,
         contract_address=token_address,
         password=config.eth_password,
         private_key=private_key)
     try:
         tx_id = token.send_tokens(to_address, amount,
                                   token_info['token_unit'])
         data = {
             'amount': amount,
             'txid': tx_id,
             'from_address': getattr(config, f'{coin_type}_tb_address'),
             'coin_type': coin_type,
             'to_address': to_address,
             'status': TbStatusEnum.TRANSFER
         }
         logger.info('withdraw {} to {}'.format(coin_type, to_address))
     except Exception as e:
         logger.exception(e)
     else:
         try:
             tb = TbRecord(**data)
             tb.insert()
             return tx_id
         except Exception as e:
             logger.exception(e)
             logger.error("提币行为已经发生,但数据没有插入数据库{}".format(data))
Example #24
0
 def init_block_info(self, session):
     """第一次初始化数据库区块信息"""
     block_info = session.query(self.block_info_coll).filter_by(
         coin_type=self.coin_category).first()
     if block_info:
         return
     while True:
         try:
             operator = self.erc_op_class(ipc_path=config.etc_ipc_path)
             info = operator.get_block(int(operator.get_block_number()))
             block_info = {
                 'block_num': int(info['number']),
                 'block_hash': hexstr_if_str(to_hex, info['hash']),
                 'coin_type': self.coin_category
             }
             block = self.block_info_coll(**block_info)
             session.add(block)
             session.commit()
             logger.info('etc_block_info init success')
             return
         except Exception as e:
             logger.error("etc初始化区块失败{}".format(e))
             session.rollback()
         time.sleep(15)
Example #25
0
    def send_tokens(self, address, amount):
        """Send tokens from my wallet to address.

        :param str address: the address to send tokens to.

        :param Decimal amount: the amount of tokens to transfer.

        :returns: transaction id (hash)
        :rtype: str

        :raises: :class:`~erc20token.exceptions.SdkConfigurationError`: if the SDK was not configured with a private key.
        :raises: ValueError: if the amount is not positive.
        :raises: ValueError: if the address has a wrong format.
        :raises: ValueError: if the nonce is incorrect.
        :raises: ValueError: if insufficient funds for for gas * gas_price.
        """
        if not self.address:
            raise SdkNotConfiguredError('private key not configured')
        validate_address(address)
        if amount <= 0:
            raise ValueError('amount must be positive')
        hex_data = self.token_contract._encode_transaction_data('transfer', args=(address, self.web3.toWei(amount, 'ether')))
        data = hexstr_if_str(to_bytes, hex_data)
        return self._tx_manager.send_transaction(self.token_contract.address, 0, data)
Example #26
0
    def __init__(self, keyfile='', password='', private_key='', provider='', provider_endpoint_uri='',
                 contract_address='', contract_abi={}, gas_price=None, gas_limit=None):
        """Create a new instance of the Token SDK.

        The SDK needs a JSON-RPC provider, contract definitions and (optionally) a wallet private key.

        The user may pass either a provider or a provider endpoint URI, in which case a default
        :class:`web3:providers:HTTPProvider` will be created. If neither private_key nor keyfile+password
        are provided, the SDK can still be used in "anonymous" mode, with only the following functions available:
            - get_address_ether_balance
            - get_transaction_status
            - get_transaction_data
            - monitor_ether_transactions

        :param str private_key: a private key to initialize the wallet with. If either private key or keyfile
            are not provided, the wallet will not be initialized and methods needing the wallet will raise exception.

        :param str keyfile: the path to the keyfile to initialize the wallet with. You will also need to supply
            a password for this keyfile.

        :param str password: a password for the keyfile.

        :param provider: JSON-RPC provider to work with. If not given, a default `web3:providers:HTTPProvider`
            is used, inited with provider_endpoint_uri.
        :type provider: :class:`web3:providers:BaseProvider`

        :param str provider_endpoint_uri: a URI to use with a default HTTPProvider.

        :param str contract_address: the address of the token contract.

        :param list contract_abi: The contract ABI json.

        :param number gas_price: The price of gas in Gwei.

        :param number gas_limit: Transaction gas limit.

        :returns: An instance of the SDK.
        :rtype: :class:`~erc20tokensdk.SDK`

        :raises: :class:`~erc20tokensdk.exceptions.SdkConfigurationError` if some of the configuration
            parameters are invalid.
        """

        if not provider and not provider_endpoint_uri:
            raise SdkConfigurationError('either provider or provider endpoint must be provided')

        try:
            validate_address(contract_address)
        except ValueError as ve:
            raise SdkConfigurationError('invalid token contract address: ' + str(ve))

        try:
            validate_abi(contract_abi)
        except Exception as e:
            raise SdkConfigurationError('invalid token contract abi: ' + str(e))

        if gas_price and not (isinstance(gas_price, int) or isinstance(gas_price, float)):
            raise SdkConfigurationError('gas price must be either integer of float')

        if gas_limit and not isinstance(gas_limit, int):
            raise SdkConfigurationError('gas limit must be integer')

        if provider:
            self.web3 = Web3(provider)
        else:
            self.web3 = Web3(RetryHTTPProvider(provider_endpoint_uri))
        if not self.web3.isConnected():
            raise SdkConfigurationError('cannot connect to provider endpoint')

        self.token_contract = self.web3.eth.contract(contract_address, abi=contract_abi)
        self.private_key = None
        self.address = None

        if keyfile:
            try:
                self.private_key = load_keyfile(keyfile, password)
            except Exception as e:
                raise SdkConfigurationError('cannot load keyfile: ' + str(e))
        elif private_key:
            self.private_key = private_key

        if self.private_key:
            try:
                private_key_bytes = hexstr_if_str(to_bytes, self.private_key)
                pk = keys.PrivateKey(private_key_bytes)
                self.address = self.web3.eth.defaultAccount = pk.public_key.to_checksum_address()
            except ValidationError as e:
                raise SdkConfigurationError('cannot load private key: ' + str(e))

            # init transaction manager
            self._tx_manager = TransactionManager(self.web3, self.private_key, self.address, self.token_contract,
                                                  gas_price, gas_limit)

        # monitoring filter manager
        self._filter_mgr = FilterManager(self.web3)
Example #27
0
    def __init__(self, keyfile='', password='', private_key='', provider='', provider_endpoint_uri='',
                 contract_address='', contract_abi={}, gas_price=None, gas_limit=None):
        """Create a new instance of the Token SDK.

        The SDK needs a JSON-RPC provider, contract definitions and (optionally) a wallet private key.

        The user may pass either a provider or a provider endpoint URI, in which case a default
        :class:`web3:providers:HTTPProvider` will be created. If neither private_key nor keyfile+password
        are provided, the SDK can still be used in "anonymous" mode, with only the following functions available:
            - get_address_ether_balance
            - get_transaction_status
            - get_transaction_data
            - monitor_ether_transactions

        :param str private_key: a private key to initialize the wallet with. If either private key or keyfile
            are not provided, the wallet will not be initialized and methods needing the wallet will raise exception.

        :param str keyfile: the path to the keyfile to initialize the wallet with. You will also need to supply
            a password for this keyfile.

        :param str password: a password for the keyfile.

        :param provider: JSON-RPC provider to work with. If not given, a default `web3:providers:HTTPProvider`
            is used, inited with provider_endpoint_uri.
        :type provider: :class:`web3:providers:BaseProvider`

        :param str provider_endpoint_uri: a URI to use with a default HTTPProvider.

        :param str contract_address: the address of the token contract.

        :param list contract_abi: The contract ABI json.

        :param number gas_price: The price of gas in Gwei.

        :param number gas_limit: Transaction gas limit.

        :returns: An instance of the SDK.
        :rtype: :class:`~erc20token.SDK`

        :raises: :class:`~erc20token.exceptions.SdkConfigurationError` if some of the configuration
            parameters are invalid.
        """

        if not provider and not provider_endpoint_uri:
            raise SdkConfigurationError('either provider or provider endpoint must be provided')

        try:
            validate_address(contract_address)
        except ValueError as ve:
            raise SdkConfigurationError('invalid token contract address: ' + str(ve))

        try:
            validate_abi(contract_abi)
        except Exception as e:
            raise SdkConfigurationError('invalid token contract abi: ' + str(e))

        if gas_price and not (isinstance(gas_price, int) or isinstance(gas_price, float)):
            raise SdkConfigurationError('gas price must be either integer of float')

        if gas_limit and not isinstance(gas_limit, int):
            raise SdkConfigurationError('gas limit must be integer')

        if provider:
            self.web3 = Web3(provider)
        else:
            self.web3 = Web3(RetryHTTPProvider(provider_endpoint_uri))
        if not self.web3.isConnected():
            raise SdkConfigurationError('cannot connect to provider endpoint')

        self.token_contract = self.web3.eth.contract(contract_address, abi=contract_abi)
        self.private_key = None
        self.address = None

        if keyfile:
            try:
                self.private_key = load_keyfile(keyfile, password)
            except Exception as e:
                raise SdkConfigurationError('cannot load keyfile: ' + str(e))
        elif private_key:
            self.private_key = private_key

        if self.private_key:
            try:
                private_key_bytes = hexstr_if_str(to_bytes, self.private_key)
                pk = keys.PrivateKey(private_key_bytes)
                self.address = self.web3.eth.defaultAccount = pk.public_key.to_checksum_address()
            except ValidationError as e:
                raise SdkConfigurationError('cannot load private key: ' + str(e))

            # init transaction manager
            self._tx_manager = TransactionManager(self.web3, self.private_key, self.address, self.token_contract,
                                                  gas_price, gas_limit)

        # monitoring filter manager
        self._filter_mgr = FilterManager(self.web3)
Example #28
0
     compose(
         apply_formatter_at_index(block_number_formatter, 0),
         apply_formatter_at_index(integer_to_hex, 1),
     ),
     'eth_getTransactionCount':
     apply_formatter_at_index(block_number_formatter, 1),
     'eth_getUncleCountByBlockNumber':
     apply_formatter_at_index(block_number_formatter, 0),
     'eth_newFilter':
     apply_formatter_at_index(filter_params_formatter, 0),
     'eth_getLogs':
     apply_formatter_at_index(filter_params_formatter, 0),
     # personal
     'personal_importRawKey':
     apply_formatter_at_index(
         compose(remove_0x_prefix, hexstr_if_str(to_hex)),
         0,
     ),
     'personal_sign':
     apply_formatter_at_index(encode_hex, 0),
     'personal_ecRecover':
     apply_formatter_at_index(encode_hex, 0),
     # Snapshot and Revert
     'evm_revert':
     apply_formatter_at_index(integer_to_hex, 0),
 },
 result_formatters={
     # Eth
     'eth_accounts':
     apply_formatter_to_array(to_checksum_address),
     'eth_blockNumber':
def abi_bytes_to_bytes(abi_type, data):
    base, sub, arrlist = process_type(abi_type)
    if base == 'bytes' and not arrlist:
        return abi_type, hexstr_if_str(to_bytes, data)
Example #30
0
def abi_int_to_hex(abi_type, data):
    base, _sub, arrlist = process_type(abi_type)
    if base == 'uint' and not arrlist:
        return abi_type, hexstr_if_str(to_hex, data)
Example #31
0
def encode_transaction(unsigned_transaction, vrs):
    (v, r, s) = vrs
    chain_naive_transaction = dissoc(vars(unsigned_transaction), 'v', 'r', 's')
    signed_transaction = Transaction(v=v, r=r, s=s, **chain_naive_transaction)
    return rlp.encode(signed_transaction)


TRANSACTION_DEFAULTS = {
    'gasPrice': lambda web3: web3.eth.gasPrice,
    'value': 0,
    'data': b'',
    'chainId': lambda web3: int(web3.net.version),
}

TRANSACTION_FORMATTERS = {
    'nonce': hexstr_if_str(to_int),
    'gasPrice': hexstr_if_str(to_int),
    'gas': hexstr_if_str(to_int),
    'to': apply_formatter_if(is_string, decode_hex),
    'value': hexstr_if_str(to_int),
    'data': apply_formatter_if(is_string, decode_hex),
    'v': hexstr_if_str(to_int),
    'r': hexstr_if_str(to_int),
    's': hexstr_if_str(to_int),
}


def chain_id_to_v(transaction_dict):
    # See EIP 155
    chain_id = transaction_dict.pop('chainId')
    if chain_id is None:
Example #32
0
def test_hexstr_if_str_passthrough(val):
    to_type = Mock(return_value='zoot')
    assert hexstr_if_str(to_type, val) == 'zoot'
    assert to_type.call_args == ((val, ), {'hexstr': None})
Example #33
0
def test_hexstr_if_str_on_valid_hex(val):
    to_type = Mock(return_value='zoot')
    assert hexstr_if_str(to_type, val) == 'zoot'
    assert to_type.call_args == ((None, ), {'hexstr': val})
Example #34
0
def test_hexstr_if_str_on_valid_hex(val):
    to_type = Mock(return_value='zoot')
    assert hexstr_if_str(to_type, val) == 'zoot'
    assert to_type.call_args == ((None, ), {'hexstr': val})
Example #35
0
def test_hexstr_if_str_curried():
    converter = hexstr_if_str(to_hex)
    assert converter(255) == '0xff'
Example #36
0
def abi_bytes_to_bytes(abi_type, data):
    base, sub, arrlist = process_type(abi_type)
    if base == 'bytes' and not arrlist:
        return abi_type, hexstr_if_str(to_bytes, data)
Example #37
0
 def __new__(cls, val):
     bytesval = hexstr_if_str(to_bytes, val)
     return super().__new__(cls, bytesval)
Example #38
0
def test_hexstr_if_str_curried():
    converter = hexstr_if_str(to_hex)
    assert converter(255) == '0xff'
Example #39
0
    (v, r, s) = vrs
    chain_naive_transaction = dissoc(vars(unsigned_transaction), 'v', 'r', 's')
    signed_transaction = Transaction(v=v, r=r, s=s, **chain_naive_transaction)
    return rlp.encode(signed_transaction)


TRANSACTION_DEFAULTS = {
    'value': 0,
    'data': b'',
    'gas': lambda web3, tx: web3.eth.estimateGas(tx),
    'gasPrice': lambda web3, tx: web3.eth.generateGasPrice(tx) or web3.eth.gasPrice,
    'chainId': lambda web3, tx: int(web3.net.version),
}

TRANSACTION_FORMATTERS = {
    'nonce': hexstr_if_str(to_int),
    'gasPrice': hexstr_if_str(to_int),
    'gas': hexstr_if_str(to_int),
    'to': apply_formatter_if(is_string, decode_hex),
    'value': hexstr_if_str(to_int),
    'data': apply_formatter_if(is_string, decode_hex),
    'v': hexstr_if_str(to_int),
    'r': hexstr_if_str(to_int),
    's': hexstr_if_str(to_int),
}


def chain_id_to_v(transaction_dict):
    # See EIP 155
    chain_id = transaction_dict.pop('chainId')
    if chain_id is None:
Example #40
0
def get_event_data(event_abi, log_entry):
    """
    Given an event ABI and a log entry for that event, return the decoded
    event data
    """
    if event_abi['anonymous']:
        log_topics = log_entry['topics']
    elif not log_entry['topics']:
        raise MismatchedABI("Expected non-anonymous event to have 1 or more topics")
    elif event_abi_to_log_topic(event_abi) != log_entry['topics'][0]:
        raise MismatchedABI("The event signature did not match the provided ABI")
    else:
        log_topics = log_entry['topics'][1:]

    log_topics_abi = get_indexed_event_inputs(event_abi)
    log_topic_normalized_inputs = normalize_event_input_types(log_topics_abi)
    log_topic_types = get_event_abi_types_for_decoding(log_topic_normalized_inputs)
    log_topic_names = get_abi_input_names({'inputs': log_topics_abi})

    if len(log_topics) != len(log_topic_types):
        raise ValueError("Expected {0} log topics.  Got {1}".format(
            len(log_topic_types),
            len(log_topics),
        ))

    log_data = hexstr_if_str(to_bytes, log_entry['data'])
    log_data_abi = exclude_indexed_event_inputs(event_abi)
    log_data_normalized_inputs = normalize_event_input_types(log_data_abi)
    log_data_types = get_event_abi_types_for_decoding(log_data_normalized_inputs)
    log_data_names = get_abi_input_names({'inputs': log_data_abi})

    # sanity check that there are not name intersections between the topic
    # names and the data argument names.
    duplicate_names = set(log_topic_names).intersection(log_data_names)
    if duplicate_names:
        raise ValueError(
            "Invalid Event ABI:  The following argument names are duplicated "
            "between event inputs: '{0}'".format(', '.join(duplicate_names))
        )

    decoded_log_data = decode_abi(log_data_types, log_data)
    normalized_log_data = map_abi_data(
        BASE_RETURN_NORMALIZERS,
        log_data_types,
        decoded_log_data
    )

    decoded_topic_data = [
        decode_single(topic_type, topic_data)
        for topic_type, topic_data
        in zip(log_topic_types, log_topics)
    ]
    normalized_topic_data = map_abi_data(
        BASE_RETURN_NORMALIZERS,
        log_topic_types,
        decoded_topic_data
    )

    event_args = dict(itertools.chain(
        zip(log_topic_names, normalized_topic_data),
        zip(log_data_names, normalized_log_data),
    ))

    event_data = {
        'args': event_args,
        'event': event_abi['name'],
        'logIndex': log_entry['logIndex'],
        'transactionIndex': log_entry['transactionIndex'],
        'transactionHash': log_entry['transactionHash'],
        'address': log_entry['address'],
        'blockHash': log_entry['blockHash'],
        'blockNumber': log_entry['blockNumber'],
    }

    return AttributeDict.recursive(event_data)
Example #41
0
         block_number_formatter,
         0,
     ),
     'eth_getCode': apply_formatter_at_index(block_number_formatter, 1),
     'eth_getStorageAt': apply_formatter_at_index(block_number_formatter, 2),
     'eth_getTransactionByBlockNumberAndIndex': compose(
         apply_formatter_at_index(block_number_formatter, 0),
         apply_formatter_at_index(integer_to_hex, 1),
     ),
     'eth_getTransactionCount': apply_formatter_at_index(block_number_formatter, 1),
     'eth_getUncleCountByBlockNumber': apply_formatter_at_index(block_number_formatter, 0),
     'eth_newFilter': apply_formatter_at_index(filter_params_formatter, 0),
     'eth_getLogs': apply_formatter_at_index(filter_params_formatter, 0),
     # personal
     'personal_importRawKey': apply_formatter_at_index(
         compose(remove_0x_prefix, hexstr_if_str(to_hex)),
         0,
     ),
     'personal_sign': apply_formatter_at_index(encode_hex, 0),
     'personal_ecRecover': apply_formatter_at_index(encode_hex, 0),
     # Snapshot and Revert
     'evm_revert': apply_formatter_if(
         bool,
         apply_formatter_at_index(to_integer_if_hex, 0),
     )
 },
 result_formatters={
     # Eth
     'eth_accounts': apply_formatter_to_array(to_checksum_address),
     'eth_blockNumber': to_integer_if_hex,
     'eth_coinbase': to_checksum_address,
Example #42
0
def hexstrs_to_bytes(abi_type, data):
    base, sub, arrlist = process_type(abi_type)
    if base in {'string', 'bytes'}:
        return abi_type, hexstr_if_str(to_bytes, data)
Example #43
0
def test_hexstr_if_str_passthrough(val):
    to_type = Mock(return_value='zoot')
    assert hexstr_if_str(to_type, val) == 'zoot'
    assert to_type.call_args == ((val, ), {'hexstr': None})