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
Example #2
0
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)
Example #4
0
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
Example #5
0
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 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_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
Example #8
0
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)
Example #9
0
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
Example #13
0
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)
Example #14
0
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
Example #15
0
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 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
Example #17
0
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 "-"
Example #18
0
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
Example #19
0
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 "-"
Example #20
0
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
Example #21
0
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 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
Example #23
0
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
Example #24
0
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
Example #25
0
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
Example #26
0
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 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
Example #28
0
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
Example #29
0
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)
Example #31
0
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
Example #32
0
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_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
Example #34
0
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