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 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_starter_token(dbsession, registry, eth_network_id, web3: Web3, eth_service: EthereumService, house_address, toybox): """See that a fresh user account is supplied with some play assets.""" with transaction.manager: user = create_user(dbsession, registry) setup_user_account(user) # Let all the events completed success, fail = eth_service.run_event_cycle() assert success == 1 assert fail == 0 # We need another event cycle to process the initial asset transfers with transaction.manager: user = dbsession.query(User).first() opid = user.user_data["starter_asset_txs"][0]["toybox"] assert opid wait_for_op_confirmations(eth_service, opid) # Let the transfer come through eth_service.run_event_cycle() # Make sure we confirm the deposit with transaction.manager: user = dbsession.query(User).first() user_depo = user.owned_crypto_operations.join(CryptoOperation).filter_by(operation_type=CryptoOperationType.deposit).first() opid = user_depo.crypto_operation.id wait_for_op_confirmations(eth_service, opid) with transaction.manager: # Sanity check our token contract posts us logs user = dbsession.query(User).first() client = get_rpc_client(web3) asset = dbsession.query(Asset).get(toybox) address = bin_to_eth_address(asset.external_id) network = dbsession.query(AssetNetwork).get(eth_network_id) user_address = UserCryptoAddress.get_default(user, network).address house_address = dbsession.query(CryptoAddress).get(house_address) house = bin_to_eth_address(house_address.address) token = Token.get(web3, address) # Check we correctly resolved low level logs token_logs = client.get_logs(from_block=0, address=[address]) wallet_logs = client.get_logs(from_block=0, address=[house]) assert len(token_logs) > 0 assert len(wallet_logs) > 0 # Check contract state matches assert token.contract.call().balanceOf(house) == 9990 assert token.contract.call().balanceOf(bin_to_eth_address(user_address.address)) == 10 # Check our internal book keeping matches assert house_address.get_account(asset).account.get_balance() == 9990 assert user_address.get_account(asset).account.get_balance() == 10
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_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_starter_eth(dbsession, registry, eth_network_id, web3: Web3, eth_service: EthereumService, house_address, starter_eth): """Test the user gets some starter ETH when signing up.""" with transaction.manager: user = create_user(dbsession, registry) setup_user_account(user, do_mainnet=True) # Let all the events completed success, fail = eth_service.run_event_cycle() assert success >= 1 assert fail == 0 # When op is confirmed, the user account is correctly credited with transaction.manager: user = dbsession.query(User).first() txid = user.user_data["starter_asset_txs"][0]["eth"] confirm_transaction(web3, txid) # Let the transfer come through eth_service.run_event_cycle() with transaction.manager: user = dbsession.query(User).first() client = get_rpc_client(web3) asset = get_ether_asset(dbsession) ua = user.owned_crypto_addresses.first() address = bin_to_eth_address(ua.address.address) # Sanity check we get events from starter deposit logs = client.get_logs(from_block=0, address=[address]) ops = list(user.owned_crypto_operations) # The event was processed on log level assert len(logs) == 1 # The last user operation is deposit depo = ops[-1] assert isinstance(depo.crypto_operation, CryptoAddressDeposit) opid = depo.crypto_operation.id # Wait deposit to confirm wait_for_op_confirmations(eth_service, opid) with transaction.manager: # User ETH balance is expected asset = get_ether_asset(dbsession) user = dbsession.query(User).first() ua = user.owned_crypto_addresses.first() caccout = ua.address.get_account(asset) assert caccout.account.get_balance() == Decimal("0.1")
def test_starter_eth(dbsession, registry, eth_network_id, web3: Web3, eth_service: EthereumService, house_address, starter_eth): """Test the user gets some starter ETH when signing up.""" with transaction.manager: user = create_user(dbsession, registry) setup_user_account(user) # Let all the events completed success, fail = eth_service.run_event_cycle() assert success >= 1 assert fail == 0 # When op is confirmed, the user account is correctly credited with transaction.manager: user = dbsession.query(User).first() txid = user.user_data["starter_asset_txs"][0]["eth"] confirm_transaction(web3, txid) # Let the transfer come through eth_service.run_event_cycle() with transaction.manager: user = dbsession.query(User).first() client = get_rpc_client(web3) asset = get_ether_asset(dbsession) ua = user.owned_crypto_addresses.first() address = bin_to_eth_address(ua.address.address) # Sanity check we get events from starter deposit logs = client.get_logs(from_block=0, address=[address]) ops = list(user.owned_crypto_operations) # The event was processed on log level assert len(logs) == 1 # The last user operation is deposit depo = ops[-1] assert isinstance(depo.crypto_operation, CryptoAddressDeposit) opid = depo.crypto_operation.id # Wait deposit to confirm wait_for_op_confirmations(eth_service, opid) with transaction.manager: # User ETH balance is expected asset = get_ether_asset(dbsession) user = dbsession.query(User).first() ua = user.owned_crypto_addresses.first() caccout = ua.address.get_account(asset) assert caccout.account.get_balance() == Decimal("0.1")
def test_deposit_token(dbsession, eth_network_id, web3: Web3, eth_service: EthereumService, coinbase: str, deposit_address: str, token: Token): """"See that we can deposit tokens to accounts.""" # Import a contract where coinbase has all balance with transaction.manager: network = dbsession.query(AssetNetwork).get(eth_network_id) import_token(network, eth_address_to_bin(token.address)) # Run import token operation success_count, failure_count = eth_service.run_waiting_operations() assert success_count == 1 assert failure_count == 0 # Coinbase transfers token balance to deposit address txid = token.transfer(deposit_address, Decimal(4000)) confirm_transaction(web3, txid) # We should pick up incoming deposit success_count, failure_count = eth_service.run_listener_operations() assert success_count == 1 assert failure_count == 0 # Check that data is setup correctly on incoming transaction with transaction.manager: op = dbsession.query(CryptoOperation).all()[-1] opid = op.id assert not op.completed_at address = dbsession.query(CryptoAddress).filter_by(address=eth_address_to_bin(deposit_address)).one() asset = op.holding_account.asset assert op.holding_account.get_balance() == 4000 assert op.completed_at is None assert address.get_account(asset).account.get_balance() == 0 # Not credited until confirmations reached assert address.crypto_address_accounts.count() == 1 # Wait the token transaction to get enough confirmations wait_for_op_confirmations(eth_service, opid) # Check that the transaction is not final with transaction.manager: op = dbsession.query(CryptoOperation).get(opid) assert op.completed_at assert op.completed_at address = dbsession.query(CryptoAddress).filter_by(address=eth_address_to_bin(deposit_address)).one() asset = op.holding_account.asset assert op.holding_account.get_balance() == 0 assert address.get_account(asset).account.get_balance() == 4000 assert op.state == CryptoOperationState.success
def test_withdraw_token(dbsession, eth_network_id, web3: Web3, eth_service: EthereumService, deposit_address: str, token_asset: str, target_account: str): """"See that we can withdraw token outside to an account.""" 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), eth_address_to_bin(target_account), "Sending to friend") opid = op.id assert caccount.account.get_balance() == 8000 # Run import token operation success_count, failure_count = eth_service.run_waiting_operations() assert success_count == 1 assert failure_count == 0 # TX was broadcasted, marked as complete with transaction.manager: op = dbsession.query(CryptoOperation).get(opid) assert isinstance(op, CryptoAddressWithdraw) asset = dbsession.query(Asset).get(token_asset) assert op.broadcasted_at assert not op.completed_at wait_for_op_confirmations(eth_service, opid) # After tx has been mined the new balances should match with transaction.manager: op = dbsession.query(CryptoOperation).get(opid) assert op.broadcasted_at assert op.completed_at asset = dbsession.query(Asset).get(token_asset) # Tokens have been removed on from account token = Token.get(web3, bin_to_eth_address(asset.external_id)) assert token.contract.call().balanceOf(deposit_address) == 8000 # Tokens have been credited on to account token = Token.get(web3, bin_to_eth_address(asset.external_id)) assert token.contract.call().balanceOf(target_account) == 2000
def test_withdraw_token(dbsession, eth_network_id, web3: Web3, eth_service: EthereumService, deposit_address: str, token_asset: str, target_account: str): """"See that we can withdraw token outside to an account.""" 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), eth_address_to_bin(target_account), "Sending to friend") opid = op.id assert caccount.account.get_balance() == 8000 # Run import token operation success_count, failure_count = eth_service.run_waiting_operations() assert success_count == 1 assert failure_count == 0 # TX was broadcasted, marked as complete with transaction.manager: op = dbsession.query(CryptoOperation).get(opid) assert isinstance(op, CryptoAddressWithdraw) asset = dbsession.query(Asset).get(token_asset) assert op.broadcasted_at assert not op.completed_at wait_for_op_confirmations(eth_service, opid) with transaction.manager: op = dbsession.query(CryptoOperation).get(opid) assert op.broadcasted_at assert op.completed_at asset = dbsession.query(Asset).get(token_asset) # Tokens have been removed on from account token = Token.get(web3, bin_to_eth_address(asset.external_id)) assert token.contract.call().balanceOf(deposit_address) == 8000 # Tokens have been credited on to account token = Token.get(web3, bin_to_eth_address(asset.external_id)) assert token.contract.call().balanceOf(target_account) == 2000
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_starter_token(dbsession, registry, eth_network_id, web3: Web3, eth_service: EthereumService, house_address, toybox): """See that a fresh user account is supplied with some play assets.""" with transaction.manager: user = create_user(dbsession, registry) setup_user_account(user, do_mainnet=True) # Let all the events completed success, fail = eth_service.run_event_cycle() assert success == 1 assert fail == 0 # We need another event cycle to process the initial asset transfers with transaction.manager: user = dbsession.query(User).first() opid = user.user_data["starter_asset_txs"][0]["toybox"] assert opid wait_for_op_confirmations(eth_service, opid) # Let the transfer come through eth_service.run_event_cycle() # Make sure we confirm the deposit with transaction.manager: user = dbsession.query(User).first() user_depo = user.owned_crypto_operations.join( CryptoOperation).filter_by( operation_type=CryptoOperationType.deposit).first() opid = user_depo.crypto_operation.id wait_for_op_confirmations(eth_service, opid) with transaction.manager: # Sanity check our token contract posts us logs user = dbsession.query(User).first() client = get_rpc_client(web3) asset = dbsession.query(Asset).get(toybox) address = bin_to_eth_address(asset.external_id) network = dbsession.query(AssetNetwork).get(eth_network_id) user_address = UserCryptoAddress.get_default(user, network).address house_address = dbsession.query(CryptoAddress).get(house_address) house = bin_to_eth_address(house_address.address) token = Token.get(web3, address) # Check we correctly resolved low level logs token_logs = client.get_logs(from_block=0, address=[address]) wallet_logs = client.get_logs(from_block=0, address=[house]) assert len(token_logs) > 0 assert len(wallet_logs) > 0 # Check contract state matches assert token.contract.call().balanceOf(house) == 9990 assert token.contract.call().balanceOf( bin_to_eth_address(user_address.address)) == 10 # Check our internal book keeping matches assert house_address.get_account(asset).account.get_balance() == 9990 assert user_address.get_account(asset).account.get_balance() == 10