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)
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)
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
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
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)
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."
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
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.'
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