def give_eth(event): """Feed user some test ETH from coinbase.""" user = event.user # TODO: Rework this from websauna.wallet.tests.eth.utils import send_balance_to_address, do_faux_deposit amount = event.network.other_data["initial_assets"].get("eth_amount") if not amount: return # Supply eth from coinbase address = bin_to_eth_address(event.address.address) if event.web3: txid = send_balance_to_address(event.web3, address, Decimal(amount)) else: # MockEthreumService test dbsession = Session.object_session(event.address) network = event.address.network asset = get_ether_asset(dbsession, network) op = do_faux_deposit(event.address, asset.id, Decimal(amount)) txid = bin_to_txid(op.txid) # Record this operation in user data so we can verify it later op_txs = user.user_data.get("starter_asset_txs", []) op_txs.append({"eth": txid}) user.user_data["starter_asset_txs"] = op_txs
def test_deposit_eth(dbsession, eth_network_id, web3, eth_service, coinbase, deposit_address): """Accept incoming deposit.""" # Do a transaction over ETH network txid = send_balance_to_address(web3, deposit_address, TEST_VALUE) confirm_transaction(web3, txid) success_op_count, failed_op_count = eth_service.run_listener_operations() assert success_op_count == 1 assert failed_op_count == 0 # We get a operation, which is not resolved yet due to block confirmation numbers with transaction.manager: # Account not yet updated address = dbsession.query(CryptoAddress).filter_by(address=eth_address_to_bin(deposit_address)).one() eth_asset = get_ether_asset(dbsession) assert address.get_account(eth_asset).account.get_balance() == 0 # We have one ETH account on this address assert address.crypto_address_accounts.count() == 1 # We have one pending operation ops = list(dbsession.query(CryptoOperation).all()) assert len(ops) == 2 # Create + deposit op = ops[-1] assert isinstance(op, CryptoAddressDeposit) assert op.holding_account.get_balance() == TEST_VALUE assert op.completed_at is None opid = op.id # Wait that we reach critical confirmation count wait_for_op_confirmations(eth_service, opid) # Now account shoult have been settled with transaction.manager: # We have one complete operation ops = list(dbsession.query(CryptoOperation).all()) assert len(ops) == 2 # Create + deposit op = ops[-1] assert isinstance(op, CryptoAddressDeposit) assert op.holding_account.get_balance() == 0 assert op.completed_at is not None address = dbsession.query(CryptoAddress).filter_by(address=eth_address_to_bin(deposit_address)).one() # We have one ETH account on this address assert address.crypto_address_accounts.count() == 1 # We have one credited account eth_asset = get_ether_asset(dbsession) caccount = address.get_account(eth_asset) assert caccount.account.get_balance() == TEST_VALUE assert op.state == CryptoOperationState.success
def withdraw_address(web3: Web3, dbsession, eth_service: EthereumService, coinbase, deposit_address) -> str: """Create a managed hosted wallet that has withdraw balance for testing.""" txid = send_balance_to_address(web3, deposit_address, TEST_VALUE) confirm_transaction(web3, txid) assert web3.eth.getBalance(deposit_address) > 0 success_op_count, failed_op_count = eth_service.run_listener_operations() assert success_op_count == 1 assert failed_op_count == 0 with transaction.manager: # We bypass normal transction confirmation count mechanism to credit the account right away to speed up the test deposit = dbsession.query(CryptoAddressDeposit).one() deposit.resolve() return deposit_address
def withdraw_address(web3: Web3, dbsession, eth_service: EthereumService, coinbase, deposit_address) -> str: """Create a managed hosted wallet that has withdraw balance for testing.""" # Do a transaction over ETH network txid = send_balance_to_address(web3, deposit_address, TEST_VALUE) confirm_transaction(web3, txid) assert web3.eth.getBalance(deposit_address) > 0 success_op_count, failed_op_count = eth_service.run_listener_operations() assert success_op_count == 1 assert failed_op_count == 0 with transaction.manager: # We bypass normal transction confirmation count mechanism to credit the account right away to speed up the test deposit = dbsession.query(CryptoAddressDeposit).one() deposit.resolve() return deposit_address
def test_double_scan_deposit(dbsession, eth_network_id, web3, eth_service, coinbase, deposit_address): """Make sure that scanning the same transaction twice doesn't get duplicated in the database.""" # Do a transaction over ETH network txid = send_balance_to_address(web3, deposit_address, TEST_VALUE) confirm_transaction(web3, txid) success_op_count, failed_op_count = eth_service.run_listener_operations() assert success_op_count == 1 # Now force run over the same blocks again success_op_count, failed_op_count = eth_service.eth_wallet_listener.force_scan(0, web3.eth.blockNumber) assert success_op_count == 0 assert failed_op_count == 0 # We get a operation, which is not resolved yet due to block confirmation numbers with transaction.manager: # We have one pending operation ops = list(dbsession.query(CryptoOperation).all()) assert len(ops) == 2 # Create + deposit
def house_address(dbsession, eth_service, web3, eth_network_id) -> UUID: """Create a network specific house address. :return: Address UUID """ with transaction.manager: network = dbsession.query(AssetNetwork).get(eth_network_id) op = create_house_address(network) opid = op.id address_id = op.address.id assert address_id # this runs op eth_service.run_waiting_operations() with transaction.manager: address = dbsession.query(CryptoAddress).get(address_id) addr = bin_to_eth_address(address.address) # Send some funds to the house from coinbase txid = send_balance_to_address(web3, addr, Decimal("0.1")) wait_tx(web3, txid) return address_id
def test_transfer_tokens_between_accounts(dbsession, eth_network_id, web3: Web3, eth_service: EthereumService, deposit_address: str, token_asset: str, coinbase: str): """Transfer tokens between two internal accounts. Do transfers in two batches to make sure subsequent events top up correctly. """ # Initiate a target address creatin with transaction.manager: network = dbsession.query(AssetNetwork).get(eth_network_id) opid = CryptoAddress.create_address(network).id # Run address creation success_count, failure_count = eth_service.run_waiting_operations() assert success_count == 1 assert failure_count == 0 # We resolved address creation operation. # Get the fresh address for the future withdraw targets. with transaction.manager: op = dbsession.query(CryptoAddressCreation).get(opid) addr = op.address.address assert addr # Move tokens between accounts with transaction.manager: address = dbsession.query(CryptoAddress).filter_by(address=eth_address_to_bin(deposit_address)).one() asset = dbsession.query(Asset).get(token_asset) caccount = address.get_account(asset) op = caccount.withdraw(Decimal(2000), addr, "Sending to friend") opid = op.id # Resolve the 1st transaction eth_service.run_event_cycle() wait_for_op_confirmations(eth_service, opid) # See that our internal balances match with transaction.manager: # Withdraw operation is complete op = dbsession.query(CryptoOperation).get(opid) assert op.completed_at assert op.completed_at, "Op not confirmed {}".format(op) # We should have received a Transfer operation targetting target account op = dbsession.query(CryptoOperation).join(CryptoAddressAccount).join(CryptoAddress).filter_by(address=addr).one() opid = op.id # Confirm incoming Transfer wait_for_op_confirmations(eth_service, opid, timeout=180) # Check Transfer looks valid with transaction.manager: op = dbsession.query(CryptoOperation).get(opid) assert op.completed_at assert op.completed_at, "Op not confirmed {}".format(op) asset = dbsession.query(Asset).get(token_asset) source = dbsession.query(CryptoAddress).filter_by(address=eth_address_to_bin(deposit_address)).one() target = dbsession.query(CryptoAddress).filter_by(address=addr).one() assert source.get_account(asset).account.get_balance() == 8000 assert target.get_account(asset).account.get_balance() == 2000 # Add some ETH on deposit_address txid = send_balance_to_address(web3, deposit_address, TEST_VALUE) confirm_transaction(web3, txid) eth_service.run_event_cycle() # Wait for confirmations to have ETH deposit credired with transaction.manager: op = dbsession.query(CryptoOperation).filter_by(txid=txid_to_bin(txid)).one() opid = op.id confirmed = op.completed_at if not confirmed: wait_for_op_confirmations(eth_service, opid) # Send some more tokens + ether, so we see account can't get mixed up with transaction.manager: address = dbsession.query(CryptoAddress).filter_by(address=eth_address_to_bin(deposit_address)).one() asset = dbsession.query(Asset).get(token_asset) caccount = address.get_account(asset) op = caccount.withdraw(Decimal(4000), addr, "Sending tokens to friend äää") eth_asset = get_ether_asset(dbsession) caccount = address.get_account(eth_asset) op = caccount.withdraw(TEST_VALUE, addr, "Sending ETH to friend äää") opid = op.id # Resolve second transaction eth_service.run_event_cycle() wait_for_op_confirmations(eth_service, opid) # See that our internal balances match with transaction.manager: op = dbsession.query(CryptoOperation).get(opid) assert op.completed_at assert op.completed_at asset = dbsession.query(Asset).get(token_asset) source = dbsession.query(CryptoAddress).filter_by(address=eth_address_to_bin(deposit_address)).one() target = dbsession.query(CryptoAddress).filter_by(address=addr).one() eth_asset = get_ether_asset(dbsession) assert source.get_account(asset).account.get_balance() == 4000 assert target.get_account(asset).account.get_balance() == 6000 assert target.get_account(eth_asset).account.get_balance() == TEST_VALUE # Transfer 3: # Send everything back plus some ether with transaction.manager: address = dbsession.query(CryptoAddress).filter_by(address=addr).one() asset = dbsession.query(Asset).get(token_asset) caccount = address.get_account(asset) op = caccount.withdraw(Decimal(6000), eth_address_to_bin(deposit_address), "Sending everything back to friend äää") opid = op.id # Resolve third transaction wait_for_op_confirmations(eth_service, opid) eth_service.run_event_cycle() # See that our internal balances match with transaction.manager: op = dbsession.query(CryptoOperation).get(opid) assert op.completed_at assert op.completed_at asset = dbsession.query(Asset).get(token_asset) source = dbsession.query(CryptoAddress).filter_by(address=eth_address_to_bin(deposit_address)).one() target = dbsession.query(CryptoAddress).filter_by(address=addr).one() assert source.get_account(asset).account.get_balance() == 10000 assert target.get_account(asset).account.get_balance() == 0 eth_asset = get_ether_asset(dbsession) assert source.get_account(eth_asset).account.get_balance() == 0 assert target.get_account(eth_asset).account.get_balance() == TEST_VALUE