def test_double_deposit_same_tx(dbsession, eth_network_id, eth_service, eth_asset_id): """Check that we have some logic to avoid depositing the same asset twice.""" # Create ETH holding account under an address with transaction.manager: # First create the address which holds our account network = dbsession.query(AssetNetwork).get(eth_network_id) address = CryptoAddress(network=network, address=eth_address_to_bin(TEST_ADDRESS)) dbsession.add(address) dbsession.flush() # Create deposit op with transaction.manager: address = dbsession.query(CryptoAddress).one_or_none() asset = dbsession.query(Asset).get(eth_asset_id) txid = txid_to_bin(TEST_TXID) op = address.deposit(Decimal(10), asset, txid, bin_to_txid(txid)) dbsession.add(op) dbsession.flush() op_id = op.id with transaction.manager: address = dbsession.query(CryptoAddress).one_or_none() asset = dbsession.query(Asset).get(eth_asset_id) txid = txid_to_bin(TEST_TXID) op = address.deposit(Decimal(10), asset, txid, bin_to_txid(txid)) assert op.id == op_id assert dbsession.query(CryptoOperation).count() == 1
def token_asset(dbsession, eth_network_id, deposit_address, eth_service: EthereumService) -> UUID: """Database asset referring to the token contract. deposit_address will hold 10000 tokens :return: Asset id """ with transaction.manager: network = dbsession.query(AssetNetwork).get(eth_network_id) asset = network.create_asset(name="MyToken", symbol="MY", supply=Decimal(10000), asset_class=AssetClass.token) address = CryptoAddress.get_network_address(network, eth_address_to_bin(deposit_address)) op = address.create_token(asset) opid = op.id aid = asset.id # This gives op a txid success, fails = eth_service.run_waiting_operations() assert success == 1 wait_for_op_confirmations(eth_service, opid) with transaction.manager: network = dbsession.query(AssetNetwork).get(eth_network_id) asset = dbsession.query(Asset).get(aid) address = CryptoAddress.get_network_address(network, eth_address_to_bin(deposit_address)) account = address.get_account(asset) assert account.account.get_balance() > 0 return aid
def test_create_address_accounts(dbsession, eth_network_id, eth_service, eth_faux_address, eth_asset_id): """Check that we can cerate different accounts under an account.""" # Create ETH account with transaction.manager: network = dbsession.query(AssetNetwork).get(eth_network_id) address = CryptoAddress(network=network, address=eth_address_to_bin(TEST_ADDRESS)) asset = dbsession.query(Asset).get(eth_asset_id) dbsession.flush() account = address.get_or_create_account(asset) account_id = account.id # We get it reflected back second time with transaction.manager: address = dbsession.query(CryptoAddress).one() asset = dbsession.query(Asset).get(eth_asset_id) account = address.get_or_create_account(asset) assert account.id == account_id # We cannot create double account for the same asset with pytest.raises(MultipleAssetAccountsPerAddress): with transaction.manager: address = dbsession.query(CryptoAddress).one() asset = dbsession.query(Asset).get(eth_asset_id) address.create_account(asset)
def token_asset(dbsession, eth_network_id, deposit_address, eth_service: EthereumService) -> UUID: """Database asset referring to the token contract. deposit_address will hold 10000 tokens :return: Asset id """ with transaction.manager: network = dbsession.query(AssetNetwork).get(eth_network_id) asset = network.create_asset(name="MyToken", symbol="MY", supply=Decimal(10000), asset_class=AssetClass.token) address = CryptoAddress.get_network_address( network, eth_address_to_bin(deposit_address)) op = address.create_token(asset) opid = op.id aid = asset.id # This gives op a txid success, fails = eth_service.run_waiting_operations() assert success == 1 wait_for_op_confirmations(eth_service, opid) with transaction.manager: network = dbsession.query(AssetNetwork).get(eth_network_id) asset = dbsession.query(Asset).get(aid) address = CryptoAddress.get_network_address( network, eth_address_to_bin(deposit_address)) account = address.get_account(asset) assert account.account.get_balance() > 0 return aid
def test_create_token(dbsession, eth_network_id, eth_service, coinbase, deposit_address): """Test user initiated token creation.""" # Initiate token creation operation with transaction.manager: network = dbsession.query(AssetNetwork).get(eth_network_id) asset = network.create_asset(name="MyToken", symbol="MY", supply=Decimal(10000), asset_class=AssetClass.token) address = CryptoAddress.get_network_address(network, eth_address_to_bin(deposit_address)) op = address.create_token(asset) opid = op.id aid = asset.id assert op.completed_at is None # Check asset is intact assert asset.symbol == "MY" assert asset.supply == 10000 assert asset.name == "MyToken" # This gives op a txid when smart contract creation tx is posted to geth success_count, failure_count = eth_service.run_waiting_operations() assert success_count == 1 assert failure_count == 0 # Check that initial asset data is in place with transaction.manager: op = dbsession.query(CryptoOperation).get(opid) network = dbsession.query(AssetNetwork).get(eth_network_id) address = CryptoAddress.get_network_address(network, eth_address_to_bin(deposit_address)) asset = network.get_asset(aid) assert op.txid assert not op.block assert op.broadcasted_at is not None assert op.completed_at is None # Initial balance doesn't hit us until tx has been confirmed assert address.get_account(asset).account.get_balance() == 0 # Asset has received its smart contract address assert asset.external_id # Wait that the smart contract creation is confirmed wait_for_op_confirmations(eth_service, opid) # Initial balance doesn't hit us until op has enough confirmations with transaction.manager: op = dbsession.query(CryptoOperation).get(opid) network = dbsession.query(AssetNetwork).get(eth_network_id) address = CryptoAddress.get_network_address(network, eth_address_to_bin(deposit_address)) asset = network.get_asset(aid) assert op.broadcasted_at is not None assert op.completed_at is not None assert address.get_account(asset).account.get_balance() == 10000
def test_double_address(dbsession, eth_network_id): """Cannot create Address object under the same network twice.""" with pytest.raises(sqlalchemy.exc.IntegrityError): with transaction.manager: network = dbsession.query(AssetNetwork).get(eth_network_id) address = CryptoAddress(network=network, address=eth_address_to_bin(TEST_ADDRESS)) dbsession.add(address) dbsession.flush() address = CryptoAddress(network=network, address=eth_address_to_bin(TEST_ADDRESS)) dbsession.add(address)
def test_account_creation_completed(dbsession, eth_network_id, eth_service: MockEthereumService, captured_registry_events): """We receive completed event on account creation.""" with transaction.manager: network = dbsession.query(AssetNetwork).get(eth_network_id) address = CryptoAddress(network=network) dbsession.flush() # Generate address on the account op = CryptoAddressCreation(address) op.required_confirmation_count = 1 dbsession.add(op) dbsession.flush() op_id = op.id eth_service.run_test_ops() # We get performed event on events = captured_registry_events assert len(events) == 2 assert isinstance(events[0], CryptoOperationPerformed) assert isinstance(events[1], CryptoOperationCompleted)
def on_deposit(self, address: CryptoAddress, opid, log_data, log_entry) -> CryptoAddressDeposit: """Handle Hosted Wallet Deposit event. Create incoming holding account holding the ETH assets until we receive enough confirmations. """ op = CryptoAddressDeposit(address.network) # Get or create final account where we deposit the transaction asset = get_ether_asset(self.dbsession, network=address.network) crypto_account = address.get_or_create_account(asset) op.crypto_account = crypto_account op.external_address = eth_address_to_bin(log_data["from"]) # Create holding account that keeps the value until we receive N amount of confirmations acc = Account(asset=asset) self.dbsession.add(acc) self.dbsession.flush() value = wei_to_eth(log_data["value"]) acc.do_withdraw_or_deposit(value, "ETH deposit from {} in tx {}".format(log_data["from"], log_entry["transactionHash"])) op.holding_account = acc return op
def test_create_eth_account(dbsession, eth_service, eth_network_id): """Create Ethereum user deposit address by deploying a hosted wallet contract through geth.""" # Create CryptoAddressCreation operation with transaction.manager: network = dbsession.query(AssetNetwork).get(eth_network_id) address = CryptoAddress(network=network) dbsession.flush() # Generate address on the account op = CryptoAddressCreation(address) dbsession.add(op) dbsession.flush() op_id = op.id # Event cycle should perform the operation success_op_count, failed_op_count = eth_service.run_event_cycle() assert success_op_count == 1 assert failed_op_count == 0 with transaction.manager: assert dbsession.query(CryptoOperation).count() == 1 op = dbsession.query(CryptoOperation).get(op_id) assert op.completed_at assert op.block assert op.performed_at assert op.completed_at address = dbsession.query(CryptoAddress).first() assert address.address
def on_deposit(self, address: CryptoAddress, opid, log_data, log_entry) -> CryptoAddressDeposit: """Handle Hosted Wallet Deposit event. Create incoming holding account holding the ETH assets until we receive enough confirmations. """ op = CryptoAddressDeposit(address.network) # Get or create final account where we deposit the transaction asset = get_ether_asset(self.dbsession, network=address.network) crypto_account = address.get_or_create_account(asset) op.crypto_account = crypto_account op.external_address = eth_address_to_bin(log_data["from"]) # Create holding account that keeps the value until we receive N amount of confirmations acc = Account(asset=asset) self.dbsession.add(acc) self.dbsession.flush() value = wei_to_eth(log_data["value"]) acc.do_withdraw_or_deposit( value, "ETH deposit from {} in tx {}".format( log_data["from"], log_entry["transactionHash"])) op.holding_account = acc return op
def deposit_address(eth_service, eth_network_id, dbsession, registry) -> str: """Creates an address that has matching account on Geth. Sending ETH to this address should trigger a incoming tx logic. :return: 0x hex presentation """ with transaction.manager: network = dbsession.query(AssetNetwork).get(eth_network_id) address = CryptoAddress(network=network) dbsession.flush() # Generate address on the account op = CryptoAddressCreation(address) dbsession.add(op) dbsession.flush() # Creates a hosted wallet success_op_count, failed_op_count = eth_service.run_waiting_operations() assert success_op_count == 1 with transaction.manager: return bin_to_eth_address(dbsession.query(CryptoAddress).one().address)
def test_create_eth_account(dbsession, eth_network_id, eth_service): """Create Ethereum account on Ethereum node.""" with transaction.manager: network = dbsession.query(AssetNetwork).get(eth_network_id) address = CryptoAddress(network=network) dbsession.flush() # Generate address on the account op = CryptoAddressCreation(address) dbsession.add(op) dbsession.flush() op_id = op.id success_op_count, failed_op_count = mock_create_addresses( eth_service, dbsession) assert success_op_count == 1 assert failed_op_count == 0 with transaction.manager: op = dbsession.query(CryptoOperation).get(op_id) assert op.completed_at address = dbsession.query(CryptoAddress).first() assert address.address
def test_deposit_eth_account(dbsession, eth_network_id, eth_service, eth_asset_id): """Deposit Ethereums to an account.""" # Create ETH holding account under an address with transaction.manager: # First create the address which holds our account network = dbsession.query(AssetNetwork).get(eth_network_id) address = CryptoAddress(network=network, address=eth_address_to_bin(TEST_ADDRESS)) dbsession.add(address) dbsession.flush() # Create deposit op with transaction.manager: address = dbsession.query(CryptoAddress).one_or_none() asset = dbsession.query(Asset).get(eth_asset_id) txid = txid_to_bin(TEST_TXID) op = address.deposit(Decimal(10), asset, txid, bin_to_txid(txid)) dbsession.add(op) opid = op.id # Resolve deposit op success_op_count, failed_op_count = eth_service.run_waiting_operations() assert success_op_count == 1 assert failed_op_count == 0 with transaction.manager: op = dbsession.query(CryptoOperation).get(opid) op.resolve() # Force resolution regardless on confirmation count # Check balances are settled with transaction.manager: address = dbsession.query(CryptoAddress).one_or_none() asset = dbsession.query(Asset).get(eth_asset_id) account = address.get_account(asset) op = dbsession.query(CryptoOperation).one() assert account.account.get_balance() == Decimal(10) assert op.holding_account.get_balance() == 0 # Transaction label should be the Ethereum txid tx = account.account.transactions.one() assert tx.message == TEST_TXID
def find_eth_balance(view, column, address: CryptoAddress): """Get link to a user admin show view from the user owned account.""" request = view.request # TODO: Expensive. Should do in get_query() dbsession = request.dbsession eth = get_ether_asset(dbsession) account = address.get_account(eth) if account: return format_asset_amount(account.account.get_balance(), account.account.asset.asset_class) else: return "-"
def get_user_address_asset(request, address: CryptoAddress, asset: Asset) -> UserAddressAsset: assert isinstance(asset, Asset) uca = UserCryptoAddress.get_by_address(address) if not uca: return None wallet_root = route_factory(request) wallet = wallet_root.get_user_wallet(uca.user) address = wallet.get_address_resource(uca) crypto_address_account = address.address.get_crypto_account(asset) asset = address.get_user_address_asset(crypto_address_account) return asset
def test_import_token(dbsession, eth_network_id, web3: Web3, eth_service: EthereumService, coinbase: str, deposit_address: str, token: Token): """Import an existing smart contract token to system.""" # Make sure we have an address that holds some of the tokens so it is cleared up during import txid = token.transfer(deposit_address, Decimal(4000)) confirm_transaction(web3, txid) with transaction.manager: network = dbsession.query(AssetNetwork).get(eth_network_id) op = import_token(network, eth_address_to_bin(token.address)) opid = op.id # Let's create another address that doesn't hold tokens # and see that import doesn't fail for it addr = CryptoAddress(network=network, address=eth_address_to_bin("0x2f70d3d26829e412a602e83fe8eebf80255aeea5")) dbsession.add(addr) success_count, failure_count = eth_service.run_waiting_operations() assert success_count == 1 assert failure_count == 0 # Check that we created a new asset and its imports where fulfilled with transaction.manager: op = dbsession.query(CryptoOperation).get(opid) assert op.completed_at # We got account with tokens on it network = dbsession.query(AssetNetwork).get(eth_network_id) caddress = CryptoAddress.get_network_address(network, eth_address_to_bin(deposit_address)) asset = network.assets.filter_by(external_id=eth_address_to_bin(token.address)).one() assert asset.name == "Mootoken" assert asset.symbol == "MOO" assert asset.supply == 10000 caccount = caddress.get_account_by_address(eth_address_to_bin(token.address)) assert caccount.account.get_balance() == 4000
def create_house_address(network: AssetNetwork) -> CryptoAddressCreation: """Sets up house Ethereum account. Store CryptoAddress UUID under "house_address" key in network.other_data JSON bag. """ assert not network.other_data.get("house_address") op = CryptoAddress.create_address(network) op.required_confirmation_count = 1 addr_id = op.address.id assert addr_id network.other_data["house_address"] = str(addr_id) return op
def do_faux_deposit(address: CryptoAddress, asset_id, amount) -> CryptoAddressDeposit: """Simulate deposit to address.""" network = address.network txid = network.other_data["test_txid_pool"].pop() # txid = "0x00df829c5a142f1fccd7d8216c5785ac562ff41e2dcfdf5785ac562ff41e2dcf" dbsession = Session.object_session(address) asset = dbsession.query(Asset).get(asset_id) txid = txid_to_bin(txid) op = address.deposit(Decimal(amount), asset, txid, bin_to_txid(txid)) op.required_confirmation_count = 1 op.external_address = address.address dbsession.add(op) dbsession.flush() return op
def eth_faux_address(dbsession, registry, eth_network_id): """Create a faux address that is not registered on node.""" with transaction.manager: address = CryptoAddress(network_id=eth_network_id) address.address = "xxx" return address.address
def test_withdraw_eth_account(dbsession, eth_service, eth_network_id, eth_asset_id): """Withdraw ETHs to an address.""" # Create ETH holding account under an address with transaction.manager: # First create the address which holds our account network = dbsession.query(AssetNetwork).get(eth_network_id) address = CryptoAddress(network=network, address=eth_address_to_bin(TEST_ADDRESS)) dbsession.flush() assert address.id assert address.address asset = dbsession.query(Asset).get(eth_asset_id) # Create an account of ETH tokens on that address ca_account = address.create_account(asset) # It should have zero balance by default with transaction.manager: ca_account = dbsession.query(CryptoAddressAccount).one_or_none() assert ca_account.account.asset_id == eth_asset_id assert ca_account.account.get_balance() == Decimal(0) # Faux top up so we have value to withdraw with transaction.manager: ca_account = dbsession.query(CryptoAddressAccount).one_or_none() assert ca_account.account.do_withdraw_or_deposit( Decimal("+10"), "Faux top up") # Create withdraw operations withdraw_address = eth_address_to_bin(TEST_ADDRESS) with transaction.manager: ca_account = dbsession.query(CryptoAddressAccount).one_or_none() op = ca_account.withdraw(Decimal("10"), withdraw_address, "Bailing out") # We withdraw 10 ETHs assert op.holding_account.get_balance() == Decimal("10") assert op.holding_account.asset == dbsession.query(Asset).get( eth_asset_id) assert op.holding_account.transactions.count() == 1 assert op.holding_account.transactions.first().message == "Bailing out" # Check all looks good on sending account assert ca_account.account.transactions.count() == 2 assert ca_account.account.transactions.all( )[0].message == "Faux top up" assert ca_account.account.transactions.all( )[1].message == "Bailing out" assert ca_account.account.get_balance() == 0 def _withdraw_eth(service, dbsession, opid): # Mocked withdraw op that always success with transaction.manager: op = dbsession.query(CryptoOperation).get(opid) op.txid = txid_to_bin(TEST_TXID) op.mark_complete() with mock.patch("websauna.wallet.ethereum.ops.withdraw_eth", new=_withdraw_eth): success_op_count, failed_op_count = eth_service.run_waiting_operations( ) # Check that operations have been marked as success with transaction.manager: ops = list(dbsession.query(CryptoOperation).all()) assert len(ops) == 1 assert isinstance(ops[0], CryptoAddressWithdraw) assert ops[0].state == CryptoOperationState.success assert ops[0].txid == txid_to_bin(TEST_TXID)
def test_withdraw_eth_account(dbsession, eth_service, eth_network_id, eth_asset_id): """Withdraw ETHs to an address.""" # Create ETH holding account under an address with transaction.manager: # First create the address which holds our account network = dbsession.query(AssetNetwork).get(eth_network_id) address = CryptoAddress(network=network, address=eth_address_to_bin(TEST_ADDRESS)) dbsession.flush() assert address.id assert address.address asset = dbsession.query(Asset).get(eth_asset_id) # Create an account of ETH tokens on that address ca_account = address.create_account(asset) # It should have zero balance by default with transaction.manager: ca_account = dbsession.query(CryptoAddressAccount).one_or_none() assert ca_account.account.asset_id == eth_asset_id assert ca_account.account.get_balance() == Decimal(0) # Faux top up so we have value to withdraw with transaction.manager: ca_account = dbsession.query(CryptoAddressAccount).one_or_none() assert ca_account.account.do_withdraw_or_deposit(Decimal("+10"), "Faux top up") # Create withdraw operations withdraw_address = eth_address_to_bin(TEST_ADDRESS) with transaction.manager: ca_account = dbsession.query(CryptoAddressAccount).one_or_none() op = ca_account.withdraw(Decimal("10"), withdraw_address, "Bailing out") # We withdraw 10 ETHs assert op.holding_account.get_balance() == Decimal("10") assert op.holding_account.asset == dbsession.query(Asset).get(eth_asset_id) assert op.holding_account.transactions.count() == 1 assert op.holding_account.transactions.first().message == "Bailing out" # Check all looks good on sending account assert ca_account.account.transactions.count() == 2 assert ca_account.account.transactions.all()[0].message == "Faux top up" assert ca_account.account.transactions.all()[1].message == "Bailing out" assert ca_account.account.get_balance() == 0 def _withdraw_eth(service, dbsession, opid): # Mocked withdraw op that always success with transaction.manager: op = dbsession.query(CryptoOperation).get(opid) op.txid = txid_to_bin(TEST_TXID) op.mark_complete() with mock.patch("websauna.wallet.ethereum.ops.withdraw_eth", new=_withdraw_eth): success_op_count, failed_op_count = eth_service.run_waiting_operations() # Check that operations have been marked as success with transaction.manager: ops = list(dbsession.query(CryptoOperation).all()) assert len(ops) == 1 assert isinstance(ops[0], CryptoAddressWithdraw) assert ops[0].state == CryptoOperationState.success assert ops[0].txid == txid_to_bin(TEST_TXID)
def create_token(network: AssetNetwork, name: str, symbol: str, supply: int, initial_owner_address: CryptoAddress) -> Asset: asset = network.create_asset(name=name, symbol=symbol, supply=Decimal(supply), asset_class=AssetClass.token) op = initial_owner_address.create_token(asset) return asset
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