Ejemplo n.º 1
0
    def buy_at_fixed_rate(self,
                          amount: float,
                          wallet: Wallet,
                          max_OCEAN_amount: float,
                          exchange_id: str = '',
                          data_token: str = '',
                          exchange_owner: str = '') -> bool:

        exchange = self._exchange_contract()
        if not exchange_id:
            assert exchange_owner and data_token, f'exchange_owner and data_token are required when exchange_id is not given.'
            exchange_id = exchange.generateExchangeId(self.ocean_address,
                                                      data_token,
                                                      exchange_owner)

        amount_base = to_base_18(amount)
        max_OCEAN_amount_base = to_base_18(max_OCEAN_amount)

        # Figure out the amount of ocean tokens to approve before triggering the exchange function to do the swap
        ocean_amount_base = exchange.get_base_token_quote(
            exchange_id, amount_base)
        if ocean_amount_base > max_OCEAN_amount_base:
            raise AssertionError(
                f'Buying {amount} datatokens requires {from_base_18(ocean_amount_base)} OCEAN '
                f'tokens which exceeds the max_OCEAN_amount {max_OCEAN_amount}.'
            )
        ocean_token = DataToken(self.ocean_address)
        ocean_token.get_tx_receipt(
            ocean_token.approve(self._exchange_address, ocean_amount_base,
                                wallet))
        tx_id = exchange.buy_data_token(exchange_id,
                                        data_token_amount=amount_base,
                                        from_wallet=wallet)
        return bool(exchange.get_tx_receipt(tx_id).status)
Ejemplo n.º 2
0
    def buy_at_fixed_rate(
        self,
        amount: float,
        wallet: Wallet,
        max_OCEAN_amount: float,
        exchange_id: str = "",
        data_token: str = "",
        exchange_owner: str = "",
    ) -> bool:

        exchange, exchange_id = self.get_exchange_id_fallback_dt_and_owner(
            exchange_id, exchange_owner, data_token)

        amount_base = to_base_18(amount)
        max_OCEAN_amount_base = to_base_18(max_OCEAN_amount)

        # Figure out the amount of ocean tokens to approve before triggering the exchange function to do the swap
        ocean_amount_base = exchange.get_base_token_quote(
            exchange_id, amount_base)
        if ocean_amount_base > max_OCEAN_amount_base:
            raise ValidationError(
                f"Buying {amount} datatokens requires {from_base_18(ocean_amount_base)} OCEAN "
                f"tokens which exceeds the max_OCEAN_amount {max_OCEAN_amount}."
            )
        ocean_token = DataToken(self.ocean_address)
        ocean_token.get_tx_receipt(
            ocean_token.approve(self._exchange_address, ocean_amount_base,
                                wallet))
        tx_id = exchange.buy_data_token(exchange_id,
                                        data_token_amount=amount_base,
                                        from_wallet=wallet)
        return bool(exchange.get_tx_receipt(tx_id).status)
Ejemplo n.º 3
0
def publish_asset(metadata, publisher_wallet):
    ocean = Ocean(config=Config(options_dict=get_config_dict()))

    # create compute service
    compute_descriptor = build_compute_descriptor(ocean, publisher_wallet.address)

    # create asset DDO and datatoken
    try:
        asset = ocean.assets.create(metadata, publisher_wallet, [compute_descriptor],
                        dt_name='Dataset with Compute', dt_symbol='DT-Compute')
        print(f'Dataset asset created successfully: did={asset.did}, datatoken={asset.data_token_address}')
    except Exception as e:
        print(f'Publishing asset failed: {e}')
        return None, None

    dt = DataToken(asset.data_token_address)
    txid = dt.mint_tokens(publisher_wallet.address, 100, publisher_wallet)
    receipt = dt.get_tx_receipt(txid)
    assert receipt and receipt.status == 1, f'datatoken mint failed: tx={txid}, txReceipt={receipt}'

    # Create datatoken liquidity pool for the new asset
    pool = ocean.pool.create(asset.data_token_address, 50, 50, publisher_wallet, 5)
    print(f'datatoken liquidity pool was created at address {pool.address}')

    # Now the asset can be discovered and consumed
    dt_cost = ocean.pool.calcInGivenOut(pool.address, ocean.OCEAN_address, asset.data_token_address, 1.0)
    print(f'Asset {asset.did} can now be purchased from pool @{pool.address} '
          f'at the price of {dt_cost} OCEAN tokens.')
    return asset, pool
Ejemplo n.º 4
0
def publish_asset(metadata, publisher_wallet):
    ocean = Ocean(config=Config(options_dict=get_config_dict()))

    # create compute service
    compute_descriptor = build_compute_descriptor(ocean, publisher_wallet.address)

    # create asset DDO and datatoken
    try:
        asset = ocean.assets.create(metadata, publisher_wallet, [compute_descriptor], dt_name='Compute with data6', dt_symbol='DT-Testx7')
        print(f'Dataset asset created successfully: did={asset.did}, datatoken={asset.data_token_address}')
        #Dataset asset created successfully: did=did:op:2cbDb0Aaa1F546829E31267d1a7F74d926Bb5B1B, datatoken=0x2cbDb0Aaa1F546829E31267d1a7F74d926Bb5B1B
    except Exception as e:
        print(f'Publishing asset failed: {e}')
        return None, None

    dt = DataToken(asset.data_token_address)
    txid = dt.mint_tokens(publisher_wallet.address, 100, publisher_wallet)
    receipt = dt.get_tx_receipt(txid)
    assert receipt and receipt.status == 1, f'datatoken mint failed: tx={txid}, txReceipt={receipt}'


    # Create datatoken liquidity pool for the new asset
    pool = ocean.pool.create(asset.data_token_address, 50, 5, publisher_wallet, 5) #50 datatokens - 5 ocean in pool
    print(f'datatoken liquidity pool was created at address {pool.address}')
    #datatoken liquidity pool was created at address 0xeaD638506951B4a4c3575bbC0c7D1491c17B7A08
    # Now the asset can be discovered and consumed
    dt_cost = ocean.pool.calcInGivenOut(pool.address, ocean.OCEAN_address, asset.data_token_address, 1.0)
    print(f'Asset {asset.did} can now be purchased from pool @{pool.address} '
          f'at the price of {dt_cost} OCEAN tokens.')
    return asset, pool
Ejemplo n.º 5
0
    def buy_at_fixed_rate(
        self,
        amount: int,
        wallet: Wallet,
        max_OCEAN_amount: int,
        exchange_id: Optional[Union[bytes, str]] = "",
        data_token: Optional[str] = "",
        exchange_owner: Optional[str] = "",
    ) -> bool:

        exchange, exchange_id = self.get_exchange_id_fallback_dt_and_owner(
            exchange_id, exchange_owner, data_token)

        # Figure out the amount of ocean tokens to approve before triggering the exchange function to do the swap
        ocean_amount = exchange.get_base_token_quote(exchange_id, amount)
        ocean_token = DataToken(self._web3, self.ocean_address)
        ocean_ticker = ocean_token.symbol()
        if ocean_amount > max_OCEAN_amount:
            raise ValidationError(
                f"Buying {pretty_ether_and_wei(amount, 'DataTokens')} requires {pretty_ether_and_wei(ocean_amount, ocean_ticker)} "
                f"tokens which exceeds the max_OCEAN_amount {pretty_ether_and_wei(max_OCEAN_amount, ocean_ticker)}."
            )
        if ocean_token.balanceOf(wallet.address) < ocean_amount:
            raise InsufficientBalance(
                f"Insufficient funds for buying {pretty_ether_and_wei(amount, 'DataTokens')}!"
            )
        if ocean_token.allowance(wallet.address,
                                 self._exchange_address) < ocean_amount:
            tx_id = ocean_token.approve(self._exchange_address, ocean_amount,
                                        wallet)
            tx_receipt = ocean_token.get_tx_receipt(self._web3, tx_id)
            if not tx_receipt or tx_receipt.status != 1:
                raise VerifyTxFailed(
                    f"Approve OCEAN tokens failed, exchange address was {self._exchange_address} and tx id was {tx_id}!"
                )
        tx_id = exchange.buy_data_token(exchange_id,
                                        data_token_amount=amount,
                                        from_wallet=wallet)
        return bool(exchange.get_tx_receipt(self._web3, tx_id).status)
Ejemplo n.º 6
0
def test_fixed_rate_exchange(web3, alice_ocean, alice_wallet, T1, bob_wallet,
                             T2, contracts_addresses):
    """Tests for fixed rate exchange.

    tests:
        create
        generateExchangeId
        getExchange
        getExchanges
        getNumberOfExchanges
        get_base_token_quote
        buy_data_token

    """
    fixed_ex = FixedRateExchange(
        web3, contracts_addresses[FixedRateExchange.CONTRACT_NAME])
    num_ex = fixed_ex.getNumberOfExchanges()
    assert num_ex == len(fixed_ex.getExchanges()
                         ), "num exchanges do not match num of exchange ids."

    ocean_t = alice_ocean.OCEAN_address
    ocn_token = DataToken(web3, ocean_t)
    bob_ocean_balance = ocn_token.balanceOf(bob_wallet.address)
    assert bob_ocean_balance >= to_wei(100), (
        f"bob wallet does not have the expected OCEAN tokens balance, "
        f"got {from_wei(bob_ocean_balance)} instead of 100")

    # clear any previous ocean token allowance for the exchange contract
    assert (ocn_token.get_tx_receipt(
        web3, ocn_token.approve(fixed_ex.address, 1,
                                bob_wallet)).status == 1), "approve failed"
    assert ocn_token.allowance(bob_wallet.address, fixed_ex.address) == 1, ""

    rate = to_wei("0.1")
    tx_id = fixed_ex.create(ocean_t, T1.address, rate, alice_wallet)
    r = fixed_ex.get_tx_receipt(web3, tx_id)
    assert r.status == 1, f"create fixed rate exchange failed: TxId {tx_id}."

    ex_id = fixed_ex.generateExchangeId(ocean_t, T1.address,
                                        alice_wallet.address).hex()
    ex_data = fixed_ex.getExchange(ex_id)
    expected_values = (alice_wallet.address, T1.address, ocean_t, rate, True,
                       0)
    assert ex_data == expected_values, (
        f"fixed rate exchange {ex_id} with values {ex_data} "
        f"does not match the expected values {expected_values}")

    assert (
        fixed_ex.getNumberOfExchanges() == num_ex + 1
    ), f"Number of exchanges does not match, expected {num_ex+1} got {fixed_ex.getNumberOfExchanges()}."

    ###################
    # Test quote and buy datatokens
    amount = to_wei(10)  # 10 data tokens
    base_token_quote = fixed_ex.get_base_token_quote(ex_id, amount)
    expected_base_token_quote = int(amount * rate / to_wei(1))
    assert base_token_quote == (
        expected_base_token_quote
    ), f"quote does not seem correct: expected {expected_base_token_quote}, got {base_token_quote}"
    assert base_token_quote == to_wei(1), ""
    # buy without approving OCEAN tokens, should fail
    assert (
        run_failing_tx(fixed_ex, fixed_ex.buy_data_token, ex_id, amount,
                       bob_wallet) == 0
    ), (f"buy_data_token/swap on EX {ex_id} is expected to fail but did not, "
        f"maybe the FixedRateExchange is already approved as spender for bob_wallet."
        )
    # approve ocean tokens, buying should still fail because datatokens are not approved by exchange owner
    assert (ocn_token.get_tx_receipt(
        web3, ocn_token.approve(fixed_ex.address, base_token_quote,
                                bob_wallet)).status == 1), "approve failed"
    assert (
        run_failing_tx(fixed_ex, fixed_ex.buy_data_token, ex_id, amount,
                       bob_wallet) == 0
    ), (f"buy_data_token/swap on EX {ex_id} is expected to fail but did not, "
        f"maybe the FixedRateExchange is already approved as spender for bob_wallet."
        )

    # approve data token, now buying should succeed
    assert (T1.get_tx_receipt(
        web3, T1.approve(fixed_ex.address, amount,
                         alice_wallet)).status == 1), "approve failed"
    assert (ocn_token.allowance(bob_wallet.address,
                                fixed_ex.address) == base_token_quote), ""
    tx_id = fixed_ex.buy_data_token(ex_id, amount, bob_wallet)
    r = fixed_ex.get_tx_receipt(web3, tx_id)
    assert (
        r.status == 1
    ), f"buy_data_token/swap on EX {ex_id} failed with status 0: amount {amount}."
    # verify bob's datatokens balance
    assert T1.balanceOf(bob_wallet.address) == amount, (
        f"bobs datatoken balance is not right, "
        f"should be {amount}, got {T1.balanceOf(bob_wallet.address)}")
    assert ocn_token.allowance(bob_wallet.address, fixed_ex.address) == 0, ""

    #####################
    # create another ex then do more tests
    rate2 = to_wei("0.8")
    tx_id = fixed_ex.create(ocean_t, T2.address, rate2, alice_wallet)
    r = fixed_ex.get_tx_receipt(web3, tx_id)
    assert r.status == 1, f"create fixed rate exchange failed: TxId {tx_id}."

    assert fixed_ex.getNumberOfExchanges() == num_ex + 2, (
        f"Number of exchanges does not match, "
        f"expected {num_ex+2} got {fixed_ex.getNumberOfExchanges()}.")

    t2_ex_id = fixed_ex.generateExchangeId(ocean_t, T2.address,
                                           alice_wallet.address).hex()
    exchange_ids = {ti.hex() for ti in fixed_ex.getExchanges()}
    assert ex_id in exchange_ids, "exchange id not found."
    assert t2_ex_id in exchange_ids, "exchange id not found."

    ##############################
    # test activate/deactivate
    assert fixed_ex.isActive(ex_id) is True, f"exchange {ex_id} is not active."
    assert fixed_ex.isActive(
        t2_ex_id) is True, f"exchange {t2_ex_id} is not active."

    assert (
        run_failing_tx(fixed_ex, fixed_ex.deactivate, t2_ex_id,
                       bob_wallet) == 0
    ), f"exchange {t2_ex_id} deactivate (using bob_wallet) should fail but did not."

    assert (fixed_ex.get_tx_receipt(
        web3, fixed_ex.deactivate(t2_ex_id, alice_wallet)).status == 1
            ), f"exchange {t2_ex_id} deactivate failed."
    assert (fixed_ex.isActive(t2_ex_id) is False
            ), f"exchange {t2_ex_id} is active, but it should be deactivated."

    ###################################
    # try buying from deactivated ex
    amount = to_wei(4)  # num data tokens
    base_token_quote = fixed_ex.get_base_token_quote(
        t2_ex_id, amount)  # num base token (OCEAN tokens)
    expected_base_token_quote = int(amount * rate2 / to_wei(1))
    assert base_token_quote == (
        expected_base_token_quote
    ), f"quote does not seem correct: expected {expected_base_token_quote}, got {base_token_quote}"
    ocn_token.get_tx_receipt(
        web3, ocn_token.approve(fixed_ex.address, base_token_quote,
                                bob_wallet))
    # buy should fail (deactivated exchange)
    assert (
        run_failing_tx(fixed_ex, fixed_ex.buy_data_token, t2_ex_id, amount,
                       bob_wallet) == 0
    ), (f"buy_data_token/swap on EX {t2_ex_id} is expected to fail but did not, "
        f"maybe the FixedRateExchange is already approved as spender for bob_wallet."
        )
    assert (ocn_token.allowance(bob_wallet.address,
                                fixed_ex.address) == base_token_quote), ""
    assert (fixed_ex.get_tx_receipt(web3,
                                    fixed_ex.activate(
                                        t2_ex_id, alice_wallet)).status == 1
            ), f"exchange {t2_ex_id} deactivate failed."
    assert (fixed_ex.isActive(t2_ex_id) is
            True), f"exchange {t2_ex_id} is not active, but it should be."

    ##############################
    # buy should still fail as datatokens are not approved to spend by the exchange contract
    assert (
        run_failing_tx(fixed_ex, fixed_ex.buy_data_token, t2_ex_id, amount,
                       bob_wallet) == 0
    ), (f"buy_data_token/swap on EX {t2_ex_id} is expected to fail but did not, "
        f"maybe the FixedRateExchange is already approved as spender for bob_wallet."
        )

    # now buy tokens should succeed
    assert (T2.get_tx_receipt(
        web3, T2.approve(fixed_ex.address, amount * 3,
                         alice_wallet)).status == 1), "approve failed"
    assert (fixed_ex.get_tx_receipt(
        web3, fixed_ex.buy_data_token(t2_ex_id, amount,
                                      bob_wallet)).status == 1
            ), f"buy_data_token/swap on EX {ex_id} failed, "
    assert ocn_token.allowance(bob_wallet.address, fixed_ex.address) == 0, ""

    # approve again for another purchase
    ocn_token.get_tx_receipt(
        web3, ocn_token.approve(fixed_ex.address, base_token_quote,
                                bob_wallet))
    assert (
        run_failing_tx(fixed_ex, fixed_ex.buy_data_token, t2_ex_id, to_wei(5),
                       bob_wallet) == 0
    ), f"buy_data_token/swap on EX {t2_ex_id} should fail because not enough Ocean tokens are approved by buyer."

    # get new quote for new amount
    base_token_quote = fixed_ex.get_base_token_quote(
        t2_ex_id, to_wei(5))  # num base token (OCEAN tokens
    ocn_token.get_tx_receipt(
        web3, ocn_token.approve(fixed_ex.address, base_token_quote,
                                bob_wallet))
    assert (fixed_ex.get_tx_receipt(
        web3, fixed_ex.buy_data_token(t2_ex_id, to_wei(5),
                                      bob_wallet)).status == 1
            ), f"buy_data_token/swap on EX {t2_ex_id} failed."
    assert ocn_token.allowance(bob_wallet.address, fixed_ex.address) == 0, ""

    ##############################
    # test getRate/setRate
    assert (
        fixed_ex.getRate(t2_ex_id) == rate2
    ), f"T2 exchange rate does not match {rate2}, got {fixed_ex.getRate(t2_ex_id)}"
    assert (
        fixed_ex.getRate(ex_id) == rate
    ), f"T1 exchange rate does not match {rate}, got {fixed_ex.getRate(ex_id)}"
    rate2 = to_wei("0.75")
    assert (fixed_ex.get_tx_receipt(
        web3, fixed_ex.setRate(t2_ex_id, rate2,
                               alice_wallet)).status == 1), "setRate failed."
    assert (
        fixed_ex.getRate(t2_ex_id) == rate2
    ), f"T2 exchange rate does not match {rate2}, got {fixed_ex.getRate(t2_ex_id)}"

    assert (run_failing_tx(
        fixed_ex, fixed_ex.setRate, t2_ex_id, 0,
        alice_wallet) == 0), "should not accept rate of Zero."
    assert (run_failing_tx(
        fixed_ex, fixed_ex.setRate, t2_ex_id, -to_wei("0.05"),
        alice_wallet) == 0), "should not accept a negative rate."
    assert (fixed_ex.get_tx_receipt(
        web3, fixed_ex.setRate(t2_ex_id, to_wei(1000),
                               alice_wallet)).status == 1), "setRate failed."
Ejemplo n.º 7
0
    def _build_and_validate_algo(self, algo_data):
        """Returns False if invalid, otherwise sets the validated_algo_dict attribute."""
        algorithm_did = algo_data.get("algorithmDid")
        self.algo_service = None

        if algorithm_did and not algo_data.get("algorithmMeta"):
            algorithm_token_address = algo_data.get("algorithmDataToken")
            algorithm_tx_id = algo_data.get("algorithmTransferTxId")

            algo = get_asset_from_metadatastore(get_metadata_url(),
                                                algorithm_did)

            try:
                asset_type = algo.metadata["main"]["type"]
            except ValueError:
                asset_type = None

            if asset_type != "algorithm":
                self.error = f"DID {algorithm_did} is not a valid algorithm"
                return False

            try:
                dt = DataToken(self.consumer_address)
                tx_receipt = dt.get_tx_receipt(algorithm_tx_id)
                event_logs = dt.events.OrderStarted().processReceipt(
                    tx_receipt)
                order_log = event_logs[0] if event_logs else None
                algo_service_id = order_log.args.serviceId
                self.algo_service = get_service_at_index(algo, algo_service_id)

                if self.algo_service.type == ServiceTypes.CLOUD_COMPUTE:
                    asset_urls = get_asset_download_urls(
                        algo,
                        self.provider_wallet,
                        config_file=app.config["CONFIG_FILE"],
                    )

                    if not asset_urls:
                        self.error = "Services in algorithm with compute type must be in the same provider you are calling."
                        return False

                if not self.algo_service:
                    self.error = "Failed to retrieve purchased algorithm service id."
                    return False

                _tx, _order_log, _transfer_log = validate_order(
                    self.consumer_address,
                    algorithm_token_address,
                    float(self.algo_service.get_cost()),
                    algorithm_tx_id,
                    add_0x_prefix(did_to_id(algorithm_did))
                    if algorithm_did.startswith("did:") else algorithm_did,
                    self.algo_service.index,
                )
                validate_transfer_not_used_for_other_service(
                    algorithm_did,
                    self.algo_service.index,
                    algorithm_tx_id,
                    self.consumer_address,
                    algorithm_token_address,
                )
                record_consume_request(
                    algorithm_did,
                    self.algo_service.index,
                    algorithm_tx_id,
                    self.consumer_address,
                    algorithm_token_address,
                    self.algo_service.get_cost(),
                )
            except Exception:
                self.error = "Algorithm is already in use or can not be found on chain."
                return False

        algorithm_dict = StageAlgoSerializer(self.consumer_address,
                                             self.provider_wallet, algo_data,
                                             self.algo_service).serialize()

        valid, error_msg = validate_formatted_algorithm_dict(
            algorithm_dict, algorithm_did)

        if not valid:
            self.error = error_msg
            return False

        self.validated_algo_dict = algorithm_dict

        return True
Ejemplo n.º 8
0
    def create(self,
               data_token_address: str,
               data_token_amount: float,
               OCEAN_amount: float,
               from_wallet: Wallet,
               data_token_weight: float = balancer_constants.INIT_WEIGHT_DT,
               swap_fee: float = balancer_constants.DEFAULT_SWAP_FEE) -> BPool:
        """
        Create a new pool with bound datatoken and OCEAN token then finalize it.
        The pool will have publicSwap enabled and swap fee is set
        to `balancer_constants.DEFAULT_SWAP_FEE`.
        Balances of both data tokens and OCEAN tokens must be sufficient in the
        `from_wallet`, otherwise this will fail.

        :param data_token_address: str address of the DataToken contract
        :param data_token_amount: float amount of initial liquidity of data tokens
        :param OCEAN_amount: float amount of initial liquidity of OCEAN tokens
        :param from_wallet: Wallet instance of pool owner
        :param data_token_weight: float weight of the data token to be set in the new pool must be >= 1 & <= 9
        :param swap_fee: float the fee taken by the pool on each swap transaction
        :return: BPool instance
        """

        bfactory = BFactory(self.bfactory_address)
        pool_address = bfactory.newBPool(from_wallet)
        pool = BPool(pool_address)
        logger.debug(f'pool created with address {pool_address}.')

        assert 1 <= data_token_weight <= 9
        base_weight = 10.0 - data_token_weight

        # Must approve datatoken and Ocean tokens to the new pool as spender
        dt = DataToken(data_token_address)
        tx_id = dt.approve_tokens(pool_address,
                                  data_token_amount,
                                  from_wallet,
                                  wait=True)
        if dt.get_tx_receipt(tx_id).status != 1:
            raise AssertionError(
                f'Approve datatokens failed, pool was created at {pool_address}'
            )

        ot = DataToken(self.ocean_address)
        tx_id = ot.approve_tokens(pool_address,
                                  OCEAN_amount,
                                  from_wallet,
                                  wait=True)
        if ot.get_tx_receipt(tx_id).status != 1:
            raise AssertionError(
                f'Approve OCEAN tokens failed, pool was created at {pool_address}'
            )

        tx_id = pool.setup(data_token_address, to_base_18(data_token_amount),
                           to_base_18(data_token_weight), self.ocean_address,
                           to_base_18(OCEAN_amount), to_base_18(base_weight),
                           to_base_18(swap_fee), from_wallet)
        if pool.get_tx_receipt(tx_id).status != 1:
            raise AssertionError(
                f'pool.setup failed: txId={tx_id}, receipt={pool.get_tx_receipt(tx_id)}'
            )

        logger.debug(
            f'create pool completed: poolAddress={pool_address}, pool setup TxId={tx_id}'
        )

        return pool
def test_fixed_rate_exchange(alice_ocean, alice_wallet, T1, bob_wallet, T2,
                             contracts_addresses):
    """
    tests:
        create
        generateExchangeId
        getExchange
        getExchanges
        getNumberOfExchanges
        get_base_token_quote
        buy_data_token

    """
    base_unit = to_base_18(1.0)
    fixed_ex = FixedRateExchange(
        contracts_addresses[FixedRateExchange.CONTRACT_NAME])
    num_ex = fixed_ex.getNumberOfExchanges()
    assert num_ex == len(fixed_ex.getExchanges()
                         ), f'num exchanges do not match num of exchange ids.'

    ocean_t = alice_ocean.OCEAN_address
    ocn_token = DataToken(ocean_t)
    # owner_wallet = get_ganache_wallet()
    # ocn_token.transfer_tokens(bob_wallet.address, 100, owner_wallet)
    assert ocn_token.token_balance(bob_wallet.address) >= 100, \
        f'bob wallet does not have the expected OCEAN tokens balance, ' \
        f'got {ocn_token.token_balance(bob_wallet.address)} instead of 100'

    # clear any previous ocean token allowance for the exchange contract
    assert ocn_token.get_tx_receipt(
        ocn_token.approve(fixed_ex.address, 1,
                          bob_wallet)).status == 1, f'approve failed'
    assert ocn_token.allowance(bob_wallet.address, fixed_ex.address) == 1, f''

    rate = to_base_18(0.1)
    tx_id = fixed_ex.create(ocean_t, T1.address, rate, alice_wallet)
    r = fixed_ex.get_tx_receipt(tx_id)
    assert r.status == 1, f'create fixed rate exchange failed: TxId {tx_id}.'

    ex_id = fixed_ex.generateExchangeId(ocean_t, T1.address,
                                        alice_wallet.address).hex()
    ex_data = fixed_ex.getExchange(ex_id)
    expected_values = (alice_wallet.address, T1.address, ocean_t, rate, True,
                       0)
    assert ex_data == expected_values, f'fixed rate exchange {ex_id} with values {ex_data} ' \
                                       f'does not match the expected values {expected_values}'

    assert fixed_ex.getNumberOfExchanges() == num_ex+1, \
        f'Number of exchanges does not match, expected {num_ex+1} got {fixed_ex.getNumberOfExchanges()}.'

    ###################
    # Test quote and buy datatokens
    amount = to_base_18(10.0)  # 10 data tokens
    base_token_quote = fixed_ex.get_base_token_quote(ex_id, amount)
    # quote = from_base_18(base_token_quote)
    assert base_token_quote == (
        amount * rate / base_unit
    ), f'quote does not seem correct: expected {amount*rate/base_unit}, got {base_token_quote}'
    assert from_base_18(base_token_quote) == 1.0, f''
    # buy without approving OCEAN tokens, should fail
    assert run_failing_tx(
        fixed_ex, fixed_ex.buy_data_token, ex_id, amount, bob_wallet
    ) == 0, f'buy_data_token/swap on EX {ex_id} is expected to fail but did not, ' \
            f'maybe the FixedRateExchange is already approved as spender for bob_wallet.'
    # approve ocean tokens, buying should still fail because datatokens are not approved by exchange owner
    assert ocn_token.get_tx_receipt(
        ocn_token.approve(fixed_ex.address, base_token_quote,
                          bob_wallet)).status == 1, f'approve failed'
    assert run_failing_tx(
        fixed_ex, fixed_ex.buy_data_token, ex_id, amount, bob_wallet
    ) == 0, f'buy_data_token/swap on EX {ex_id} is expected to fail but did not, ' \
            f'maybe the FixedRateExchange is already approved as spender for bob_wallet.'

    # approve data token, now buying should succeed
    assert T1.get_tx_receipt(T1.approve(
        fixed_ex.address, amount, alice_wallet)).status == 1, f'approve failed'
    assert ocn_token.allowance(bob_wallet.address,
                               fixed_ex.address) == base_token_quote, f''
    tx_id = fixed_ex.buy_data_token(ex_id, amount, bob_wallet)
    r = fixed_ex.get_tx_receipt(tx_id)
    assert r.status == 1, f'buy_data_token/swap on EX {ex_id} failed with status 0: amount {amount}.'
    # verify bob's datatokens balance
    assert T1.balanceOf(bob_wallet.address) == amount, f'bobs datatoken balance is not right, ' \
                                                       f'should be {amount}, got {T1.balanceOf(bob_wallet.address)}'
    assert ocn_token.allowance(bob_wallet.address, fixed_ex.address) == 0, f''

    #####################
    # create another ex then do more tests
    rate2 = to_base_18(0.8)
    tx_id = fixed_ex.create(ocean_t, T2.address, rate2, alice_wallet)
    r = fixed_ex.get_tx_receipt(tx_id)
    assert r.status == 1, f'create fixed rate exchange failed: TxId {tx_id}.'

    assert fixed_ex.getNumberOfExchanges() == num_ex+2, f'Number of exchanges does not match, ' \
                                                        f'expected {num_ex+2} got {fixed_ex.getNumberOfExchanges()}.'

    t2_ex_id = fixed_ex.generateExchangeId(ocean_t, T2.address,
                                           alice_wallet.address).hex()
    exchange_ids = {ti.hex() for ti in fixed_ex.getExchanges()}
    assert ex_id in exchange_ids, f'exchange id not found.'
    assert t2_ex_id in exchange_ids, f'exchange id not found.'

    ##############################
    # test activate/deactivate
    assert fixed_ex.isActive(ex_id) is True, f'exchange {ex_id} is not active.'
    assert fixed_ex.isActive(
        t2_ex_id) is True, f'exchange {t2_ex_id} is not active.'

    assert run_failing_tx(
        fixed_ex, fixed_ex.deactivate, t2_ex_id, bob_wallet
    ) == 0, f'exchange {t2_ex_id} deactivate (using bob_wallet) should fail but did not.'

    assert fixed_ex.get_tx_receipt(fixed_ex.deactivate(
        t2_ex_id,
        alice_wallet)).status == 1, f'exchange {t2_ex_id} deactivate failed.'
    assert fixed_ex.isActive(
        t2_ex_id
    ) is False, f'exchange {t2_ex_id} is active, but it should be deactivated.'

    ###################################
    # try buying from deactivated ex
    amount = to_base_18(4.0)  # num data tokens
    base_token_quote = fixed_ex.get_base_token_quote(
        t2_ex_id, amount)  # num base token (OCEAN tokens
    assert base_token_quote == (amount * rate2 / base_unit), \
        f'quote does not seem correct: expected {amount*rate2/base_unit}, got {base_token_quote}'
    ocn_token.get_tx_receipt(
        ocn_token.approve(fixed_ex.address, base_token_quote, bob_wallet))
    # buy should fail (deactivated exchange)
    assert run_failing_tx(
        fixed_ex, fixed_ex.buy_data_token, t2_ex_id, amount, bob_wallet
    ) == 0, f'buy_data_token/swap on EX {t2_ex_id} is expected to fail but did not, ' \
            f'maybe the FixedRateExchange is already approved as spender for bob_wallet.'
    assert ocn_token.allowance(bob_wallet.address,
                               fixed_ex.address) == base_token_quote, f''
    assert fixed_ex.get_tx_receipt(fixed_ex.activate(
        t2_ex_id,
        alice_wallet)).status == 1, f'exchange {t2_ex_id} deactivate failed.'
    assert fixed_ex.isActive(
        t2_ex_id
    ) is True, f'exchange {t2_ex_id} is not active, but it should be.'

    ##############################
    # buy should still fail as datatokens are not approved to spend by the exchange contract
    assert run_failing_tx(
        fixed_ex, fixed_ex.buy_data_token, t2_ex_id, amount, bob_wallet
    ) == 0, f'buy_data_token/swap on EX {t2_ex_id} is expected to fail but did not, ' \
            f'maybe the FixedRateExchange is already approved as spender for bob_wallet.'

    # now buy tokens should succeed
    assert T2.get_tx_receipt(
        T2.approve(fixed_ex.address, amount * 3,
                   alice_wallet)).status == 1, f'approve failed'
    assert fixed_ex.get_tx_receipt(fixed_ex.buy_data_token(t2_ex_id, amount, bob_wallet)).status == 1, \
        f'buy_data_token/swap on EX {ex_id} failed, '
    assert ocn_token.allowance(bob_wallet.address, fixed_ex.address) == 0, f''

    # approve again for another purchase
    ocn_token.get_tx_receipt(
        ocn_token.approve(fixed_ex.address, base_token_quote, bob_wallet))
    assert run_failing_tx(
        fixed_ex, fixed_ex.buy_data_token, t2_ex_id, to_base_18(5.0),
        bob_wallet
    ) == 0, f'buy_data_token/swap on EX {t2_ex_id} should fail because not enough Ocean tokens are approved by buyer.'

    # get new quote for new amount
    base_token_quote = fixed_ex.get_base_token_quote(
        t2_ex_id, to_base_18(5.0))  # num base token (OCEAN tokens
    ocn_token.get_tx_receipt(
        ocn_token.approve(fixed_ex.address, base_token_quote, bob_wallet))
    assert fixed_ex.get_tx_receipt(
        fixed_ex.buy_data_token(t2_ex_id, to_base_18(5.0), bob_wallet)
    ).status == 1, f'buy_data_token/swap on EX {t2_ex_id} failed.'
    assert ocn_token.allowance(bob_wallet.address, fixed_ex.address) == 0, f''

    ##############################
    # test getRate/setRate
    assert fixed_ex.getRate(
        t2_ex_id
    ) == rate2, f'T2 exchange rate does not match {rate2}, got {fixed_ex.getRate(t2_ex_id)}'
    assert fixed_ex.getRate(
        ex_id
    ) == rate, f'T1 exchange rate does not match {rate}, got {fixed_ex.getRate(ex_id)}'
    rate2 = to_base_18(0.75)
    assert fixed_ex.get_tx_receipt(
        fixed_ex.setRate(t2_ex_id, rate2,
                         alice_wallet)).status == 1, f'setRate failed.'
    assert fixed_ex.getRate(
        t2_ex_id
    ) == rate2, f'T2 exchange rate does not match {rate2}, got {fixed_ex.getRate(t2_ex_id)}'

    assert run_failing_tx(
        fixed_ex, fixed_ex.setRate, t2_ex_id, to_base_18(0.0),
        alice_wallet) == 0, f'should not accept rate of Zero.'
    assert run_failing_tx(
        fixed_ex, fixed_ex.setRate, t2_ex_id, -to_base_18(0.05),
        alice_wallet) == 0, f'should not accept a negative rate.'
    assert fixed_ex.get_tx_receipt(
        fixed_ex.setRate(t2_ex_id, to_base_18(1000.0),
                         alice_wallet)).status == 1, f'setRate failed.'
Ejemplo n.º 10
0
    def create(
        self,
        data_token_address: str,
        data_token_amount: int,
        OCEAN_amount: int,
        from_wallet: Wallet,
        data_token_weight: int = balancer_constants.INIT_WEIGHT_DT,
        swap_fee: int = balancer_constants.DEFAULT_SWAP_FEE,
    ) -> BPool:
        """
        Create a new pool with bound datatoken and OCEAN token then finalize it.
        The pool will have publicSwap enabled and swap fee is set
        to `balancer_constants.DEFAULT_SWAP_FEE`.
        Balances of both data tokens and OCEAN tokens must be sufficient in the
        `from_wallet`, otherwise this will fail.

        :param data_token_address: str address of the DataToken contract
        :param data_token_amount: int amount of initial liquidity of data tokens
        :param OCEAN_amount: int amount of initial liquidity of OCEAN tokens
        :param from_wallet: Wallet instance of pool owner
        :param data_token_weight: int weight of the data token to be set in the new pool must be >= 1 & <= 9
        :param swap_fee: int the fee taken by the pool on each swap transaction
        :return: BPool instance
        """
        bfactory = BFactory(self.web3, self.bfactory_address)
        pool_address = bfactory.newBPool(from_wallet)
        pool = BPool(self.web3, pool_address)
        logger.debug(f"pool created with address {pool_address}.")

        assert to_wei("1") <= data_token_weight <= to_wei("9")
        base_weight = to_wei(10) - data_token_weight

        # Must approve datatoken and Ocean tokens to the new pool as spender
        dt = DataToken(self.web3, data_token_address)
        if dt.balanceOf(from_wallet.address) < data_token_amount:
            raise InsufficientBalance(
                "Insufficient datatoken balance for pool creation!"
            )
        if dt.allowance(from_wallet.address, pool_address) < data_token_amount:
            tx_id = dt.approve(pool_address, data_token_amount, from_wallet)
            if dt.get_tx_receipt(self.web3, tx_id).status != 1:
                raise VerifyTxFailed(
                    f"Approve datatokens failed, pool was created at {pool_address}"
                )

        ot = DataToken(self.web3, self.ocean_address)
        if ot.balanceOf(from_wallet.address) < OCEAN_amount:
            raise InsufficientBalance("Insufficient OCEAN balance for pool creation!")
        if ot.allowance(from_wallet.address, pool_address) < OCEAN_amount:
            tx_id = ot.approve(pool_address, OCEAN_amount, from_wallet)
            if ot.get_tx_receipt(self.web3, tx_id).status != 1:
                raise VerifyTxFailed(
                    f"Approve OCEAN tokens failed, pool was created at {pool_address}"
                )
        tx_id = pool.setup(
            data_token_address,
            data_token_amount,
            data_token_weight,
            self.ocean_address,
            OCEAN_amount,
            base_weight,
            swap_fee,
            from_wallet,
        )
        if pool.get_tx_receipt(self.web3, tx_id).status != 1:
            raise VerifyTxFailed(
                f"pool.setup failed: txId={tx_id}, receipt={pool.get_tx_receipt(self.web3, tx_id)}"
            )

        logger.debug(
            f"create pool completed: poolAddress={pool_address}, pool setup TxId={tx_id}"
        )

        return pool