Example #1
0
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 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
Example #4
0
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
Example #5
0
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 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
Example #8
0
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
Example #9
0
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
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