def create_wallet(self): if self.created: return fail(RuntimeError(f"{self.network} wallet with name {self.wallet_name} already exists.")) self._logger.info("Creating wallet in %s", self.wallet_dir) try: self.wallet = HDWallet.create(self.wallet_name, network=self.network, db_uri=self.db_path) self.wallet.new_key('tribler_payments') self.wallet.new_key('tribler_change', change=1) self.created = True except WalletError as exc: self._logger.error("Cannot create %s wallet!", self.network) return fail(exc) return succeed(None)
async def transfer(self, amount: float, address, **kwargs) -> Future: """ Transfer Monero to another wallet. If the amount exceeds the available balance, an `InsufficientFunds` exception is raised. :param kwargs: payment_id: str, priority: transaction priority, implies fee. The priority can be a number from 1 to 4 (unimportant, normal, elevated, priority). Default is 1. unlock_time: int, default is 0 :param amount: the transfer amount :param address: the receiver address :return: Future of transfer hash, None or InsufficientFundsException """ if self._wallet_connection_alive(): balance = await self.get_balance() if balance['available'] < amount: return fail(InsufficientFunds('Insufficient funds found in Monero wallet')) self._logger.info('Transfer %f to %s', amount, address) transaction = await self.wallet.transfer(address, Decimal(str(amount)), **kwargs, relay=False) return succeed(transaction.hash) return succeed(None)
def merge_account(self, address): """ Delete the wallet and send all funds to the specified address :param address: address to send funds to :return: tx hash """ self.check_and_update_created_on_network() if not self.created_on_network: return fail( RuntimeError( 'Cannot do account merge operation: account is not created on network' )) self._logger.info( 'Deleting wallet and sending all funds to address %s', address) network = Network.PUBLIC_NETWORK_PASSPHRASE if not self.testnet else Network.TESTNET_NETWORK_PASSPHRASE tx = TransactionBuilder( source_account=self.account, base_fee=self.provider.get_base_fee(), network_passphrase=network, ).append_account_merge_op(address).build() tx.sign(self.keypair) xdr_tx_envelope = tx.to_xdr() tx_hash = self.provider.submit_transaction(xdr_tx_envelope) self.created_on_network = False return succeed(tx_hash)
async def test_transfer_error(self): """ Test whether we receive the right response when we try a transfer that errors """ self.market_community.wallets['BTC'].transfer = lambda *_: fail(RuntimeError("error")) self.market_community.wallets['BTC'].created = True post_data = {'amount': 3, 'destination': 'abc'} await self.make_request(self.nodes[0], 'wallets/BTC/transfer', 'POST', expected_status=500, json=post_data)
async def test_transfer_error(self): """ Test whether we receive the right response when we try a transfer that errors """ self.nodes[0].overlay.wallets['BTC'].transfer = lambda *_: fail(RuntimeError("error")) self.nodes[0].overlay.wallets['BTC'].created = True self.should_check_equality = False post_data = {'amount': 3, 'destination': 'abc'} await self.do_request('wallets/BTC/transfer', expected_code=500, request_type='POST', post_data=post_data)
def get_outgoing_payments(self, confirmed=True): """ Get all confirmed outgoing payments for this wallet. :param: if True return only confirmed outgoing payments, else mempool payments :return: list of payments """ if self._wallet_connection_alive(): return succeed(self.wallet.outgoing(confirmed=confirmed, unconfirmed=(not confirmed))) return fail(WalletConnectionError())
def get_confirmations(self, transaction: Payment): """ Return number of confirmations transactions has received. :param transaction: Payment object from monero-python library :return: integer count """ if self._wallet_connection_alive(): return succeed(self.wallet.confirmations(transaction)) return fail(WalletConnectionError())
def insert_bid(self, bid): """ :type bid: Bid """ if not self._bids.tick_exists(bid.order_id) and bid.order_id not in self.completed_orders and bid.is_valid(): self._bids.insert_tick(bid) delay = int(bid.timestamp) + int(bid.timeout) * 1000 - int(time.time() * 1000) return self.register_task("bid_%s_timeout" % bid.order_id, self.timeout_bid, bid.order_id, delay=delay) self.on_invalid_tick_insert() return fail(RuntimeError("bid invalid"))
def insert_ask(self, ask): """ :type ask: Ask """ if not self._asks.tick_exists(ask.order_id) and ask.order_id not in self.completed_orders and ask.is_valid(): self._asks.insert_tick(ask) delay = int(ask.timestamp) + int(ask.timeout) * 1000 - int(time.time() * 1000) return self.register_task("ask_%s_timeout" % ask.order_id, self.timeout_ask, ask.order_id, delay=delay) self.on_invalid_tick_insert() return fail(RuntimeError("ask invalid"))
async def get_transactions(self): """ Retrieve all transactions associated with this Monero wallet. :return: list of dictionary representations of transactions """ if self._wallet_connection_alive(): payments = await self._get_payments() transactions = [self._normalize_transaction(payment) for payment in payments] return succeed(transactions) return fail(WalletConnectionError('No connection to wallet for retrieving transactions'))
async def transfer_multiple(self, transfers: list, **kwargs) -> list: """ Submit multiple transfers simultaneously to the Monero blockchain. May reduce fee. :param transfers: list of tuples of format (address, Decimal(amount)) :param kwargs: payment_id, priority, unlock_time (see `transfer` method above) :return: list of resulting hashes or return InsufficientFundsException """ balance = await self.get_balance() total_amount = float(sum([transfer[1] for transfer in transfers])) if balance['available'] < total_amount: return fail(InsufficientFunds('Insufficient funds found in Monero wallet for all transfers')) if self._wallet_connection_alive(): results = await self.wallet.transfer_multiple(transfers, **kwargs) hashes = [result[0].hash for result in results] return succeed(hashes) return fail(WalletConnectionError('No connection to wallet for making transfers'))
def create_wallet(self): """ Anydex operates on existing wallet with corresponding `wallet-rpc-server`. Creates instance of `monero-python` Wallet instance. """ self._logger.info('Connect to wallet-rpc-server on %s at %d', self.host, self.port) try: self.wallet = monero.wallet.Wallet(JSONRPCWallet(host=self.host, port=self.port)) self.created = True self._logger.info('Connection to wallet-rpc-server established') return succeed(None) except requests.exceptions.ConnectionError: return fail(WalletConnectionError(f'Cannot connect to wallet-rpc-server on {self.host} at {self.port}'))
def create_wallet(self): """ Create a new bitcoin wallet. """ from bitcoinlib.wallets import wallet_exists, HDWallet, WalletError if wallet_exists(self.wallet_name, databasefile=self.db_path): return fail( RuntimeError( f"Bitcoin wallet with name {self.wallet_name} already exists." )) self._logger.info("Creating wallet in %s", self.wallet_dir) try: self.wallet = HDWallet.create(self.wallet_name, network=self.network, databasefile=self.db_path) self.wallet.new_key('tribler_payments') self.wallet.new_key('tribler_change', change=1) self.created = True except WalletError as exc: self._logger.error("Cannot create BTC wallet!") return fail(exc) return succeed(None)
def create_wallet(self): if self.created: return fail( RuntimeError( f'Stellar wallet with name {self.wallet_name} already exists' )) self._logger.info('Creating Stellar wallet with name %s', self.wallet_name) self.keypair = Keypair.random() self.created = True self.account = Account(self.get_address().result(), 0) self.created_on_network = False self.database.add_secret(self.wallet_name, self.keypair.secret, self.keypair.public_key) return succeed(None)
def create_wallet(self): """ Create wallet by creating seed, storing it and setting up API access """ if self.created: return fail(RuntimeError(f'Iota wallet with name {self.wallet_name} already exists.')) self._logger.info(f'Creating Iota wallet with name {self.wallet_name}') # generate random seed and store it in the database as a String instead of TryteString self.seed = Seed.random() self.database.add(DatabaseSeed(name=self.wallet_name, seed=self.seed.__str__())) self.database.commit() # initialize connection with API through the provider and get an active non-spent address self.provider = PyOTAIotaProvider(testnet=self.testnet, seed=self.seed) self.created = True return succeed([])
def create_wallet(self): """ If no account exists yet, create a new one. """ if self.account: return fail( RuntimeError( f'Ethereum wallet with name {self.wallet_name} already exists' )) self._logger.info('Creating Ethereum wallet with name %s', self.wallet_name) if not self.account: self.account = Web3().eth.account.create() self.created = True self.database.add_key(self.wallet_name, self.account.key, self.account.address) return succeed(None)
async def test_change_hops_fail(mock_dlmgr, test_download, rest_api): """ Testing whether the API returns 500 if changing the number of hops in a download fails """ mock_dlmgr.get_download = lambda _: test_download mock_dlmgr.update_hops = lambda *_: fail(RuntimeError) await do_request(rest_api, f'downloads/{test_download.infohash}', post_data={'anon_hops': 1}, expected_code=500, request_type='PATCH', expected_json={ 'error': { 'message': '', 'code': 'RuntimeError', 'handled': True } })
def create_node(network: str, testnet=False) -> Node: """ Constructs a Node from user-provided parameters if key is present in `config.py`-dictionary. Else: constructs Node picked from set of default nodes provided by AnyDex. Return CannotCreateNodeException if required parameters miss from user Node-config: host, port :param testnet: testnet node or not :param network: instance of Cryptocurrency enum :return: Node """ config = get_anydex_configuration() params = {'network': network} if 'node' in config: _logger.info('Parsing user node config') node_config = config['node_config'] params['source'] = Source.USER params['name'] = node_config.get('name', '') try: protocol, username, password, host, port = _parse_url( node_config['host']) except KeyError: return fail( CannotCreateNodeException( 'Missing key `host` from node config')) if port is None: return fail( CannotCreateNodeException( 'Missing port from `host` in node config')) params['protocol'] = protocol if protocol else 'http' params['username'] = username if username else '' params['password'] = password if username else '' _, params['latency'] = determine_latency(node_config['host']) params['host_config'] = HostConfig(host, port, params['protocol']) else: _logger.info('Finding best host from pool of default hosts') params['source'] = Source.DEFAULT params['name'] = '' default_hosts = read_default_hosts() try: if testnet: network_hosts = default_hosts[network]['testnet'] params['testnet'] = True else: network_hosts = default_hosts[network]['non_testnet'] except KeyError: return fail( CannotCreateNodeException( f'Missing default nodes for {network}')) # host format: protocol://username:password@domain:port selected_host, latency = select_best_host(network_hosts) protocol, username, password, host, port = _parse_url(selected_host) if username: params['username'] = username if password: params['password'] = password if protocol: params['host_config'] = HostConfig(host, port, protocol) else: params['host_config'] = HostConfig(host, port) params['latency'] = latency node = Node(**params) _logger.info('Using following node:\n%s', node) return node
def sign_block(self, peer, public_key=EMPTY_PK, block_type=b'unknown', transaction=None, linked=None, additional_info=None): """ Create, sign, persist and send a block signed message :param peer: The peer with whom you have interacted, as a IPv8 peer :param public_key: The public key of the other party you transact with :param block_type: The type of the block to be constructed, as a string :param transaction: A string describing the interaction in this block :param linked: The block that the requester is asking us to sign :param additional_info: Stores additional information, on the transaction """ # NOTE to the future: This method reads from the database, increments and then writes back. If in some future # this method is allowed to execute in parallel, be sure to lock from before .create up to after .add_block # In this particular case there must be an implicit transaction due to the following assert assert peer is not None or peer is None and linked is None and public_key == ANY_COUNTERPARTY_PK, \ "Peer, linked block should not be provided when creating a no counterparty source block. Public key " \ "should be that reserved for any counterpary." assert transaction is None and linked is not None or transaction is not None and linked is None, \ "Either provide a linked block or a transaction, not both %s, %s" % (peer, self.my_peer) assert (additional_info is None or additional_info is not None and linked is not None and transaction is None), \ "Either no additional info is provided or one provides it for a linked block" assert (linked is None or linked.link_public_key == self.my_peer.public_key.key_to_bin() or linked.link_public_key == ANY_COUNTERPARTY_PK ), "Cannot counter sign block not addressed to self" assert linked is None or linked.link_sequence_number == UNKNOWN_SEQ, \ "Cannot counter sign block that is not a request" assert transaction is None or isinstance( transaction, dict), "Transaction should be a dictionary" assert additional_info is None or isinstance( additional_info, dict), "Additional info should be a dictionary" self.persistence_integrity_check() if linked and linked.link_public_key != ANY_COUNTERPARTY_PK: block_type = linked.type block = self.get_block_class(block_type).create( block_type, transaction, self.persistence, self.my_peer.public_key.key_to_bin(), link=linked, additional_info=additional_info, link_pk=public_key) block.sign(self.my_peer.key) validation = block.validate(self.persistence) self.logger.info("Signed block to %s (%s) validation result %s", hexlify(block.link_public_key)[-8:], block, validation) if validation[0] != ValidationResult.partial_next and validation[ 0] != ValidationResult.valid: self.logger.error("Signed block did not validate?! Result %s", repr(validation)) return fail(RuntimeError("Signed block did not validate.")) if not self.persistence.contains(block): self.persistence.add_block(block) self.notify_listeners(block) # This is a source block with no counterparty if not peer and public_key == ANY_COUNTERPARTY_PK: if block.type not in self.settings.block_types_bc_disabled: self.send_block(block) return succeed((block, None)) # If there is a counterparty to sign, we send it self.send_block(block, address=peer.address) # We broadcast the block in the network if we initiated a transaction if block.type not in self.settings.block_types_bc_disabled and not linked: self.send_block(block) if peer == self.my_peer: # We created a self-signed block if block.type not in self.settings.block_types_bc_disabled: self.send_block(block) return succeed( (block, None)) if public_key == ANY_COUNTERPARTY_PK else succeed( (block, linked)) elif not linked: # We keep track of this outstanding sign request. sign_future = Future() self.request_cache.add( HalfBlockSignCache(self, block, sign_future, peer.address)) return sign_future else: # We return a future that fires immediately with both half blocks. if block.type not in self.settings.block_types_bc_disabled: self.send_block_pair(linked, block) return succeed((linked, block))