def _deployAndMintToken(symbol: str, to_address: str) -> btoken.BToken: wallet = get_factory_deployer_wallet(_NETWORK) dt_address = DataToken.deploy( wallet.web3, wallet, None, "Template Contract", "TEMPLATE", wallet.address, to_base_18(1000), DTFactory.FIRST_BLOB, to_address, ) dt_factory = DTFactory( DTFactory.deploy(wallet.web3, wallet, None, dt_address, to_address) ) token_address = dt_factory.get_token_address( dt_factory.createToken( symbol, symbol, symbol, DataToken.DEFAULT_CAP_BASE, wallet ) ) token = DataToken(token_address) token.mint(to_address, to_base_18(1000), wallet) return btoken.BToken(token.address)
def test_get_token_address_fails(web3, dtfactory_address): """Tests the failure case for get_token_address.""" dtfactory = DTFactory(web3, dtfactory_address) # Transaction 0x is not in the chain with pytest.raises(TimeExhausted): with patch("ocean_lib.models.dtfactory.DTFactory.get_tx_receipt") as mock: # throw the exception without acually waiting mock.side_effect = TimeExhausted() # we are checking that this exception bubbles up to get_token_address() dtfactory.get_token_address("")
def test_get_token_minter(web3, alice_wallet, dtfactory_address, alice_address): """Tests proper retrieval of token minter from DTFactory.""" dtfactory = DTFactory(web3, dtfactory_address) dt_address = dtfactory.createToken( "foo_blob", "DT1", "DT1", to_wei(1000), from_wallet=alice_wallet ) dt = DataToken(web3, dtfactory.get_token_address(dt_address)) dt.mint(alice_address, to_wei(10), from_wallet=alice_wallet) assert dtfactory.get_token_minter(dt.address) == alice_address
def get_dtfactory(self, dtfactory_address: str = "") -> DTFactory: """ :param dtfactory_address: contract address, str :return: `DTFactory` instance """ dtf_address = dtfactory_address or DTFactory.configured_address( get_network_name(web3=self.web3), self.config.address_file ) return DTFactory(self.web3, dtf_address)
def test_data_token_creation(web3, alice_wallet, dtfactory_address): """Tests that a data token can be created using a DTFactory object.""" dtfactory = DTFactory(web3, dtfactory_address) dt_address = dtfactory.createToken( "foo_blob", "DT1", "DT1", to_wei(1000), from_wallet=alice_wallet ) dt = DataToken(web3, dtfactory.get_token_address(dt_address)) assert isinstance(dt, DataToken) assert dt.blob() == "foo_blob" assert dtfactory.verify_data_token(dt.address)
def test1(network, alice_wallet, dtfactory_address): dtfactory = DTFactory(dtfactory_address) dt_address = dtfactory.createToken("foo_blob", "DT1", "DT1", to_base_18(1000), from_wallet=alice_wallet) dt = DataToken(dtfactory.get_token_address(dt_address)) assert isinstance(dt, DataToken) assert dt.blob() == "foo_blob"
def new_factory_contract(): web3 = Web3Provider.get_web3() deployer_wallet = get_ganache_wallet() dt_address = DataToken.deploy( web3, deployer_wallet, ContractHandler.artifacts_path, 'Template Contract', 'TEMPLATE', deployer_wallet.address, DataToken.DEFAULT_CAP_BASE, DTFactory.FIRST_BLOB, deployer_wallet.address) return DTFactory( DTFactory.deploy(web3, deployer_wallet, ContractHandler.artifacts_path, dt_address, deployer_wallet.address))
def test_data_token_event_registered(alice_wallet, dtfactory_address, alice_ocean): """Tests that a token registration event is created and can be retrieved.""" dtfactory = DTFactory(dtfactory_address) dt_address = dtfactory.createToken( "foo_blob", "DT1", "DT1", to_base_18(1000.0), from_wallet=alice_wallet ) dt = DataToken(dtfactory.get_token_address(dt_address)) block = alice_ocean.web3.eth.blockNumber # with explicit address registered_event = dtfactory.get_token_registered_event( block - 1, block + 1, token_address=dt.address ) assert registered_event.args.tokenAddress == dt.address
def get_dtfactory_address( address_file: str, network: Optional[str] = None, web3: Optional[Web3] = None ) -> str: """Returns the DTFactory address for given network or web3 instance Requires either network name or web3 instance. """ return DTFactory.configured_address( network or get_network_name(web3=web3), address_file )
def search_exchange_by_data_token(self, data_token: str) -> List[AttributeDict]: dtfactory_address = get_dtfactory_address(self._config.address_file, web3=self._web3) dtfactory = DTFactory(self._web3, dtfactory_address) token_registered_log = dtfactory.get_token_registered_event( 0, self._web3.eth.block_number, data_token) assert (token_registered_log ), f"No token with '{data_token}' address was created before." from_block = token_registered_log.blockNumber fre = self._exchange_contract() filter_args = {"dataToken": data_token} logs = fre.get_event_logs( event_name="ExchangeCreated", from_block=from_block, to_block=self._web3.eth.block_number, filters=filter_args, ) return logs
def _get_all_liquidity_records(self, action, web3, pool_address, block_number=None, to_block=None, token_address=None, raw_result=True): action_to_fn = { 'join': 'get_join_logs', 'exit': 'get_exit_logs', 'swap': 'get_swap_logs' } current_block = to_block if to_block is not None else web3.eth.blockNumber pool = BPool(pool_address) dt_address = token_address or self.get_token_address( pool_address, pool) factory = DTFactory(get_dtfactory_address()) if block_number is None: block_number = factory.get_token_registered_event( 0, current_block, token_address=dt_address).blockNumber logs = getattr(pool, action_to_fn[action])(web3, block_number, current_block) if raw_result: return logs _all = [] for l in logs: if action == 'join': record = (l.args.caller, l.args.tokenIn, l.args.tokenAmountIn, 0, 0, l.blockNumber, l.transactionHash, 'join') elif action == 'exit': record = (l.args.caller, l.args.tokenOut, l.args.tokenAmountOut, 0, 0, l.blockNumber, l.transactionHash, 'exit') else: assert action == 'swap', f'Unknown pool action {action}' record = (l.args.caller, l.args.tokenIn, l.args.tokenAmountIn, l.args.tokenOut, l.args.tokenAmountOut, l.blockNumber, l.transactionHash, 'swap') _all.append(record) return _all
def test_data_token_event_registered( web3, alice_wallet, dtfactory_address, alice_ocean ): """Tests that a token registration event is created and can be retrieved.""" dtfactory = DTFactory(web3, dtfactory_address) dt_address = dtfactory.createToken( "foo_blob", "DT1", "DT1", to_wei(1000), from_wallet=alice_wallet ) dt = DataToken(web3, dtfactory.get_token_address(dt_address)) block = alice_ocean.web3.eth.block_number # with explicit address block_confirmations = alice_ocean.config.block_confirmations.value registered_event = dtfactory.get_token_registered_event( block - (block_confirmations + 1), block, token_address=dt.address ) assert registered_event.args.tokenAddress == dt.address
def get_dtfactory_address(network=None): return DTFactory.configured_address( network or Web3Helper.get_network_name(), ConfigProvider.get_config().address_file, )
def test_get_token_address_fails(dtfactory_address): """Tests the failure case for get_token_address.""" dtfactory = DTFactory(dtfactory_address) assert dtfactory.get_token_address("") == ""
def dtfactory_address(config): return DTFactory.configured_address(_NETWORK, config.address_file)
def _get_all_liquidity_records( self, action, web3, pool_address, block_number=None, to_block=None, token_address=None, raw_result=True, ): action_to_fn = { "join": "get_join_logs", "exit": "get_exit_logs", "swap": "get_swap_logs", } current_block = to_block if to_block is not None else web3.eth.blockNumber pool = BPool(pool_address) dt_address = token_address or self.get_token_address( pool_address, pool) factory = DTFactory(get_dtfactory_address()) if block_number is None: block_number = factory.get_token_registered_event( 0, current_block, token_address=dt_address).blockNumber logs = getattr(pool, action_to_fn[action])(web3, block_number, current_block) if raw_result: return logs _all = [] for lg in logs: if action == "join": record = ( lg.args.caller, lg.args.tokenIn, lg.args.tokenAmountIn, 0, 0, lg.blockNumber, lg.transactionHash, "join", ) elif action == "exit": record = ( lg.args.caller, lg.args.tokenOut, lg.args.tokenAmountOut, 0, 0, lg.blockNumber, lg.transactionHash, "exit", ) else: assert action == "swap", f"Unknown pool action {action}" record = ( lg.args.caller, lg.args.tokenIn, lg.args.tokenAmountIn, lg.args.tokenOut, lg.args.tokenAmountOut, lg.blockNumber, lg.transactionHash, "swap", ) _all.append(record) return _all
def create( self, metadata: dict, publisher_wallet: Wallet, services: Optional[list] = None, owner_address: Optional[str] = None, data_token_address: Optional[str] = None, provider_uri: Optional[str] = None, dt_name: Optional[str] = None, dt_symbol: Optional[str] = None, dt_blob: Optional[str] = None, dt_cap: Optional[int] = None, encrypt: Optional[bool] = False, ) -> Optional[V3Asset]: """Register an asset on-chain. Creating/deploying a DataToken contract and in the Metadata store (Aquarius). :param metadata: dict conforming to the Metadata accepted by Ocean Protocol. :param publisher_wallet: Wallet of the publisher registering this asset :param services: list of Service objects. :param owner_address: hex str the ethereum address to assign asset ownership to. After registering the asset on-chain, the ownership is transferred to this address :param data_token_address: hex str the address of the data token smart contract. The new asset will be associated with this data token address. :param provider_uri: str URL of service provider. This will be used as base to construct the serviceEndpoint for the `access` (download) service :param dt_name: str name of DataToken if creating a new one :param dt_symbol: str symbol of DataToken if creating a new one :param dt_blob: str blob of DataToken if creating a new one. A `blob` is any text to be stored with the ERC20 DataToken contract for any purpose. :param dt_cap: int amount of DataTokens to mint, denoted in wei :return: DDO instance """ assert isinstance( metadata, dict ), f"Expected metadata of type dict, got {type(metadata)}" # copy metadata so we don't change the original metadata_copy = copy.deepcopy(metadata) asset_type = metadata_copy["main"]["type"] assert asset_type in ( "dataset", "algorithm", ), f"Invalid/unsupported asset type {asset_type}" validation_result, validation_errors = self.validate(metadata) if not validation_result: msg = f"Metadata has validation errors: {validation_errors}" logger.error(msg) raise ValueError(msg) urls = [item["url"] for item in metadata["main"]["files"]] if not provider_uri: provider_uri = DataServiceProvider.get_url(self._config) for url in urls: if not DataServiceProvider.check_single_file_info(url, provider_uri): msg = f"The URL of this service can not be accessed: {url}." logger.error(msg) raise ValueError(msg) services = services or [] services = self._add_defaults( services, metadata_copy, provider_uri, publisher_wallet ) checksum_dict = dict() for service in services: checksum_dict[str(service.index)] = checksum(service.main) # Create a DDO object asset = V3Asset() # Adding proof to the ddo. asset.add_proof(checksum_dict, publisher_wallet) ################# # DataToken address = DTFactory.configured_address( get_network_name(web3=self._web3), self._config.address_file ) dtfactory = DTFactory(self._web3, address) if not data_token_address: blob = dt_blob or "" name = dt_name or metadata["main"]["name"] symbol = dt_symbol or name # register on-chain _cap = dt_cap if dt_cap else DataToken.DEFAULT_CAP tx_id = dtfactory.createToken( blob, name, symbol, _cap, from_wallet=publisher_wallet ) data_token = DataToken(self._web3, dtfactory.get_token_address(tx_id)) if not data_token: logger.warning("Creating new data token failed.") return None data_token_address = data_token.address logger.info( f"Successfully created data token with address " f"{data_token.address} for new dataset asset." ) # owner_address is set as minter only if creating new data token. So if # `data_token_address` is set `owner_address` has no effect. if owner_address: data_token.proposeMinter(owner_address, from_wallet=publisher_wallet) else: if not dtfactory.verify_data_token(data_token_address): raise ContractNotFound( f"datatoken address {data_token_address} is not found in the DTFactory events." ) # verify data_token_address dt = DataToken(self._web3, data_token_address) minter = dt.contract.caller.minter() if not minter: raise AssertionError( f"datatoken address {data_token_address} does not seem to be a valid DataToken contract." ) elif minter.lower() != publisher_wallet.address.lower(): raise AssertionError( f"Minter of datatoken {data_token_address} is not the same as the publisher." ) assert ( data_token_address ), "data_token_address is required for publishing a dataset asset." # Generating the did and adding to the ddo. did = f"did:op:{remove_0x_prefix(data_token_address)}" asset.did = did logger.debug(f"Using datatoken address as did: {did}") # Check if it's already registered first! if self._get_aquarius().ddo_exists(did): raise AquariusError( f"Asset id {did} is already registered to another asset." ) for service in services: if service.type == ServiceTypes.METADATA: ddo_service_endpoint = service.service_endpoint if "{did}" in ddo_service_endpoint: ddo_service_endpoint = ddo_service_endpoint.replace("{did}", did) service.service_endpoint = ddo_service_endpoint asset.add_service(service) asset.proof["signatureValue"] = sign_hash( encode_defunct(text=asset.asset_id), publisher_wallet ) # Setup metadata service # First compute files_encrypted assert metadata_copy["main"][ "files" ], "files is required in the metadata main attributes." logger.debug("Encrypting content urls in the metadata.") publisher_signature = self._data_provider.sign_message( publisher_wallet, asset.asset_id, provider_uri=provider_uri ) _, encrypt_endpoint = self._data_provider.build_encrypt_endpoint(provider_uri) files_encrypted = self._data_provider.encrypt_files_dict( metadata_copy["main"]["files"], encrypt_endpoint, asset.asset_id, publisher_wallet.address, publisher_signature, ) # only assign if the encryption worked if files_encrypted: logger.debug(f"Content urls encrypted successfully {files_encrypted}") index = 0 for file in metadata_copy["main"]["files"]: file["index"] = index index = index + 1 del file["url"] metadata_copy["encryptedFiles"] = files_encrypted else: raise AssertionError("Encrypting the files failed.") logger.debug( f"Generated asset and services, DID is {asset.did}," f" metadata service @{ddo_service_endpoint}." ) # Set datatoken address in the asset asset.data_token_address = data_token_address flags, asset_contents = self._build_asset_contents(asset, encrypt) try: # publish the new ddo in ocean-db/Aquarius ddo_registry = self.ddo_registry() tx_id = ddo_registry.create( asset.asset_id, flags, asset_contents, publisher_wallet ) if not ddo_registry.verify_tx(tx_id): raise VerifyTxFailed( f"create DDO on-chain failed, transaction status is 0. Transaction hash is {tx_id}" ) logger.info("Asset/ddo published on-chain successfully.") except ValueError as ve: raise ValueError(f"Invalid value to publish in the metadata: {str(ve)}") except Exception as e: logger.error(f"Publish asset on-chain failed: {str(e)}") raise return asset
def get_registered_ddo(client, wallet, metadata, service_descriptor): aqua = Aquarius('http://localhost:5000') ddo_service_endpoint = aqua.get_service_endpoint() metadata_store_url = json.dumps({'t': 1, 'url': ddo_service_endpoint}) # Create new data token contract addresses = get_contracts_addresses(get_address_file()) dt_address = addresses.get(DTFactory.CONTRACT_NAME) if dt_address: factory_contract = DTFactory(dt_address) else: factory_contract = new_factory_contract() ddo_contract_address = addresses.get(MetadataContract.CONTRACT_NAME) metadata_contract = MetadataContract(ddo_contract_address) tx_id = factory_contract.createToken(metadata_store_url, 'DataToken1', 'DT1', to_base_18(1000000), wallet) dt_contract = DataToken(factory_contract.get_token_address(tx_id)) if not dt_contract: raise AssertionError('Creation of data token contract failed.') ddo = Asset() ddo.data_token_address = dt_contract.address metadata_service_desc = ServiceDescriptor.metadata_service_descriptor( metadata, ddo_service_endpoint) service_descriptors = list([ ServiceDescriptor.authorization_service_descriptor( 'http://localhost:12001') ]) service_descriptors.append(service_descriptor) service_type = service_descriptor[0] service_descriptors = [metadata_service_desc] + service_descriptors services = ServiceFactory.build_services(service_descriptors) checksums = dict() for service in services: checksums[str(service.index)] = checksum(service.main) # Adding proof to the ddo. ddo.add_proof(checksums, wallet) did = ddo.assign_did(f'did:op:{remove_0x_prefix(ddo.data_token_address)}') ddo_service_endpoint.replace('{did}', did) services[0].set_service_endpoint(ddo_service_endpoint) stype_to_service = {s.type: s for s in services} _service = stype_to_service[service_type] for service in services: ddo.add_service(service) # ddo.proof['signatureValue'] = ocean_lib.sign_hash( # did_to_id_bytes(did), account) ddo.add_public_key(did, wallet.address) ddo.add_authentication(did, PUBLIC_KEY_TYPE_RSA) # if not plecos.is_valid_dict_local(ddo.metadata): # print(f'invalid metadata: {plecos.validate_dict_local(ddo.metadata)}') # assert False, f'invalid metadata: {plecos.validate_dict_local(ddo.metadata)}' files_list_str = json.dumps(metadata['main']['files']) encrypted_files = encrypt_document(client, did, files_list_str, wallet) # encrypted_files = do_encrypt(files_list_str, provider_wallet) # only assign if the encryption worked if encrypted_files: index = 0 for file in metadata['main']['files']: file['index'] = index index = index + 1 del file['url'] metadata['encryptedFiles'] = encrypted_files web3 = Web3Provider.get_web3() block = web3.eth.blockNumber try: data = lzma.compress(web3.toBytes(text=ddo.as_text())) tx_id = metadata_contract.create(ddo.asset_id, bytes([1]), data, wallet) if not metadata_contract.verify_tx(tx_id): raise AssertionError( f'create DDO on-chain failed, transaction status is 0. Transaction hash is {tx_id}' ) except Exception as e: print(f'error publishing ddo {ddo.did} in Aquarius: {e}') raise log = metadata_contract.get_event_log( metadata_contract.EVENT_METADATA_CREATED, block, ddo.asset_id, 30) assert log, f'no ddo created event.' ddo = wait_for_ddo(aqua, ddo.did) assert ddo, f'resolve did {ddo.did} failed.' return ddo
def main(): network = 'ganache' private_key = os.getenv('EVENTS_TESTS_PRIVATE_KEY') network_rpc = os.getenv('EVENTS_RPC', 'http://127.0.0.1:8545') config = Config(os.getenv('CONFIG_FILE')) ConfigProvider.set_config(config) # artifacts_path = os.getenv('ARTIFACTS_PATH', ) artifacts_path = config.artifacts_path address_file = Path( os.getenv('ADDRESS_FILE', os.path.join(artifacts_path, 'address.json'))).expanduser().resolve() print(f'deploying contracts and saving addresses in {address_file}') Web3Provider.init_web3(provider=get_web3_connection_provider(network_rpc)) ContractHandler.set_artifacts_path(artifacts_path) web3 = Web3Provider.get_web3() addresses = dict() if os.path.exists(address_file): with open(address_file) as f: network_addresses = json.load(f) else: network_addresses = {network: {}} _addresses = network_addresses[network] # ****SET ENVT**** # grab vars factory_deployer_private_key = private_key # ****SEE FUNDS**** print( "Keys:\n%s\n" % Wallet(web3=web3, private_key=factory_deployer_private_key).keysStr()) # ****DEPLOY**** deployer_wallet = Wallet(web3, private_key=factory_deployer_private_key) minter_addr = deployer_wallet.address cap = 2**255 print("****Deploy DataTokenTemplate: begin****") dt_address = DataToken.deploy(web3, deployer_wallet, artifacts_path, 'Template Contract', 'TEMPLATE', minter_addr, DataToken.DEFAULT_CAP_BASE, DTFactory.FIRST_BLOB, minter_addr) addresses[DataToken.CONTRACT_NAME] = dt_address print("****Deploy DataTokenTemplate: done****\n") print("****Deploy DTFactory: begin****") dtfactory = DTFactory( DTFactory.deploy(web3, deployer_wallet, artifacts_path, dt_address, minter_addr)) addresses[DTFactory.CONTRACT_NAME] = dtfactory.address print("****Deploy DTFactory: done****\n") print("****Deploy BPool: begin****") bpool_address = BPool.deploy(web3, deployer_wallet, artifacts_path) bpool_template = BPool(bpool_address) addresses[BPool.CONTRACT_NAME] = bpool_address print("****Deploy BPool: done****\n") print("****Deploy 'BFactory': begin****") bfactory_address = BFactory.deploy(web3, deployer_wallet, artifacts_path, bpool_template.address) bfactory = BFactory(bfactory_address) addresses[BFactory.CONTRACT_NAME] = bfactory_address print("****Deploy 'BFactory': done****\n") print("****Deploy 'FixedRateExchange': begin****") addresses[FixedRateExchange.CONTRACT_NAME] = FixedRateExchange.deploy( web3, deployer_wallet, artifacts_path) print("****Deploy 'FixedRateExchange': done****\n") print("****Deploy 'Metadata': begin****") addresses[MetadataContract.CONTRACT_NAME] = MetadataContract.deploy( web3, deployer_wallet, artifacts_path) print("****Deploy 'Metadata': done****\n") if network == 'ganache' and 'Ocean' not in _addresses: print("****Deploy fake OCEAN: begin****") # For simplicity, hijack DataTokenTemplate. minter_addr = deployer_wallet.address OCEAN_cap = 1410 * 10**6 # 1.41B OCEAN_cap_base = to_base_18(float(OCEAN_cap)) OCEAN_token = DataToken( DataToken.deploy(web3, deployer_wallet, artifacts_path, 'Ocean', 'OCEAN', minter_addr, OCEAN_cap_base, '', minter_addr)) addresses["Ocean"] = OCEAN_token.address print("****Deploy fake OCEAN: done****\n") print("****Mint fake OCEAN: begin****") OCEAN_token.mint(minter_addr, OCEAN_cap_base, from_wallet=deployer_wallet) print("****Mint fake OCEAN: done****\n") print("****Distribute fake OCEAN: begin****") amt_distribute = 1000 amt_distribute_base = to_base_18(float(amt_distribute)) for key_label in [ 'EVENTS_TESTS_PRIVATE_KEY', 'EVENTS_TESTS_PRIVATE_KEY2' ]: key = os.environ.get(key_label) if not key: continue dst_address = privateKeyToAddress(key) try: OCEAN_token.transfer(dst_address, amt_distribute_base, from_wallet=deployer_wallet) except ValueError: # handle nonce issue time.sleep(3) OCEAN_token.transfer(dst_address, amt_distribute_base, from_wallet=deployer_wallet) print("****Distribute fake OCEAN: done****\n") network_addresses[network].update(addresses) with open(address_file, 'w') as f: json.dump(network_addresses, f, indent=2) print(f'contracts deployed: {network_addresses}') return addresses
def create( self, metadata: dict, publisher_wallet: Wallet, service_descriptors: list = None, owner_address: str = None, data_token_address: str = None, provider_uri=None, dt_name: str = None, dt_symbol: str = None, dt_blob: str = None, dt_cap: float = None, ) -> (Asset, None): """ Register an asset on-chain by creating/deploying a DataToken contract and in the Metadata store (Aquarius). :param metadata: dict conforming to the Metadata accepted by Ocean Protocol. :param publisher_wallet: Wallet of the publisher registering this asset :param service_descriptors: list of ServiceDescriptor tuples of length 2. The first item must be one of ServiceTypes and the second item is a dict of parameters and values required by the service :param owner_address: hex str the ethereum address to assign asset ownership to. After registering the asset on-chain, the ownership is transferred to this address :param data_token_address: hex str the address of the data token smart contract. The new asset will be associated with this data token address. :param provider_uri: str URL of service provider. This will be used as base to construct the serviceEndpoint for the `access` (download) service :param dt_name: str name of DataToken if creating a new one :param dt_symbol: str symbol of DataToken if creating a new one :param dt_blob: str blob of DataToken if creating a new one. A `blob` is any text to be stored with the ERC20 DataToken contract for any purpose. :param dt_cap: float :return: DDO instance """ assert isinstance( metadata, dict), f"Expected metadata of type dict, got {type(metadata)}" assert service_descriptors is None or isinstance( service_descriptors, list ), f"bad type of `service_descriptors` {type(service_descriptors)}" # copy metadata so we don't change the original metadata_copy = copy.deepcopy(metadata) asset_type = metadata_copy["main"]["type"] assert asset_type in ( "dataset", "algorithm", ), f"Invalid/unsupported asset type {asset_type}" if not plecos.is_valid_dict_local(metadata_copy): errors = plecos.list_errors_dict_local(metadata_copy) msg = f"Metadata has validation errors: {errors}" logger.error(msg) raise ValueError(msg) service_descriptors = service_descriptors or [] services = self._process_service_descriptors(service_descriptors, metadata_copy, provider_uri, publisher_wallet) stype_to_service = {s.type: s for s in services} checksum_dict = dict() for service in services: checksum_dict[str(service.index)] = checksum(service.main) # Create a DDO object asset = Asset() # Adding proof to the ddo. asset.add_proof(checksum_dict, publisher_wallet) ################# # DataToken address = DTFactory.configured_address(Web3Helper.get_network_name(), self._config.address_file) dtfactory = DTFactory(address) if not data_token_address: blob = dt_blob or "" name = dt_name or metadata["main"]["name"] symbol = dt_symbol or name # register on-chain _cap = dt_cap if dt_cap else DataToken.DEFAULT_CAP tx_id = dtfactory.createToken(blob, name, symbol, to_base_18(_cap), from_wallet=publisher_wallet) data_token = DataToken(dtfactory.get_token_address(tx_id)) if not data_token: logger.warning("Creating new data token failed.") return None data_token_address = data_token.address logger.info(f"Successfully created data token with address " f"{data_token.address} for new dataset asset.") # owner_address is set as minter only if creating new data token. So if # `data_token_address` is set `owner_address` has no effect. if owner_address: data_token.proposeMinter(owner_address, from_wallet=publisher_wallet) else: # verify data_token_address dt = DataToken(data_token_address) minter = dt.contract_concise.minter() if not minter: raise AssertionError( f"datatoken address {data_token_address} does not seem to be a valid DataToken contract." ) elif minter.lower() != publisher_wallet.address.lower(): raise AssertionError( f"Minter of datatoken {data_token_address} is not the same as the publisher." ) elif not dtfactory.verify_data_token(data_token_address): raise AssertionError( f"datatoken address {data_token_address} is not found in the DTFactory events." ) assert ( data_token_address ), "data_token_address is required for publishing a dataset asset." # Generating the did and adding to the ddo. did = asset.assign_did( f"did:op:{remove_0x_prefix(data_token_address)}") logger.debug(f"Using datatoken address as did: {did}") # Check if it's already registered first! if did in self._get_aquarius().list_assets(): raise OceanDIDAlreadyExist( f"Asset id {did} is already registered to another asset.") md_service = stype_to_service[ServiceTypes.METADATA] ddo_service_endpoint = md_service.service_endpoint if "{did}" in ddo_service_endpoint: ddo_service_endpoint = ddo_service_endpoint.replace("{did}", did) md_service.set_service_endpoint(ddo_service_endpoint) # Populate the ddo services asset.add_service(md_service) access_service = stype_to_service.get(ServiceTypes.ASSET_ACCESS, None) compute_service = stype_to_service.get(ServiceTypes.CLOUD_COMPUTE, None) if access_service: asset.add_service(access_service) if compute_service: asset.add_service(compute_service) asset.proof["signatureValue"] = Web3Helper.sign_hash( add_ethereum_prefix_and_hash_msg(asset.asset_id), publisher_wallet) # Add public key and authentication asset.add_public_key(did, publisher_wallet.address) asset.add_authentication(did, PUBLIC_KEY_TYPE_RSA) # Setup metadata service # First compute files_encrypted assert metadata_copy["main"][ "files"], "files is required in the metadata main attributes." logger.debug("Encrypting content urls in the metadata.") publisher_signature = self._data_provider.sign_message( publisher_wallet, asset.asset_id, self._config) _, encrypt_endpoint = self._data_provider.build_encrypt_endpoint( provider_uri) files_encrypted = self._data_provider.encrypt_files_dict( metadata_copy["main"]["files"], encrypt_endpoint, asset.asset_id, publisher_wallet.address, publisher_signature, ) # only assign if the encryption worked if files_encrypted: logger.debug( f"Content urls encrypted successfully {files_encrypted}") index = 0 for file in metadata_copy["main"]["files"]: file["index"] = index index = index + 1 del file["url"] metadata_copy["encryptedFiles"] = files_encrypted else: raise AssertionError("Encrypting the files failed.") logger.debug(f"Generated asset and services, DID is {asset.did}," f" metadata service @{ddo_service_endpoint}.") # Set datatoken address in the asset asset.data_token_address = data_token_address try: # publish the new ddo in ocean-db/Aquarius ddo_registry = self.ddo_registry() web3 = Web3Provider.get_web3() tx_id = ddo_registry.create( asset.asset_id, bytes([1]), lzma.compress(web3.toBytes(text=asset.as_text())), publisher_wallet, ) if not ddo_registry.verify_tx(tx_id): raise AssertionError( f"create DDO on-chain failed, transaction status is 0. Transaction hash is {tx_id}" ) logger.info("Asset/ddo published on-chain successfully.") except ValueError as ve: raise ValueError( f"Invalid value to publish in the metadata: {str(ve)}") except Exception as e: logger.error(f"Publish asset on-chain failed: {str(e)}") raise return asset
def get_dtfactory(self, dtfactory_address: str = "") -> DTFactory: dtf_address = dtfactory_address or DTFactory.configured_address( Web3Helper.get_network_name(), self._config.address_file) return DTFactory(dtf_address)
def test_ddo_on_chain(): config = ConfigProvider.get_config() ddo_address = get_contracts_addresses( "ganache", config)[MetadataContract.CONTRACT_NAME] dtfactory_address = get_contracts_addresses( "ganache", config)[DTFactory.CONTRACT_NAME] ddo_registry = MetadataContract(ddo_address) wallet = get_publisher_wallet() web3 = Web3Provider.get_web3() dtfactory = DTFactory(dtfactory_address) tx_id = dtfactory.createToken("", "dt1", "dt1", 1000, wallet) dt = DataToken(dtfactory.get_token_address(tx_id)) # test create ddo asset = get_ddo_sample(dt.address) old_name = asset.metadata["main"]["name"] txid = ddo_registry.create( asset.asset_id, b"", lzma.compress(web3.toBytes(text=asset.as_text())), wallet) assert ddo_registry.verify_tx(txid), f"create ddo failed: txid={txid}" logs = ddo_registry.event_MetadataCreated.processReceipt( ddo_registry.get_tx_receipt(txid)) assert logs, f"no logs found for create ddo tx {txid}" log = logs[0] assert add_0x_prefix(log.args.dataToken) == asset.asset_id # read back the asset ddo from the event log ddo_text = web3.toText(lzma.decompress(log.args.data)) assert ddo_text == asset.as_text(), "ddo text does not match original." _asset = Asset(json_text=ddo_text) assert _asset.did == asset.did, "did does not match." name = _asset.metadata["main"]["name"] assert name == old_name, f"name does not match: {name} != {old_name}" # test_update ddo asset.metadata["main"]["name"] = "updated name for test" txid = ddo_registry.update( asset.asset_id, b"", lzma.compress(web3.toBytes(text=asset.as_text())), wallet) assert ddo_registry.verify_tx(txid), f"update ddo failed: txid={txid}" logs = ddo_registry.event_MetadataUpdated.processReceipt( ddo_registry.get_tx_receipt(txid)) assert logs, f"no logs found for update ddo tx {txid}" log = logs[0] assert add_0x_prefix(log.args.dataToken) == asset.asset_id # read back the asset ddo from the event log ddo_text = web3.toText(lzma.decompress(log.args.data)) assert ddo_text == asset.as_text(), "ddo text does not match original." _asset = Asset(json_text=ddo_text) assert (_asset.metadata["main"]["name"] == "updated name for test" ), "name does not seem to be updated." assert DataToken(asset.asset_id).contract_concise.isMinter(wallet.address) # test update fails from wallet other than the original publisher bob = get_consumer_wallet() try: txid = ddo_registry.update( asset.asset_id, b"", lzma.compress(web3.toBytes(text=asset.as_text())), bob) assert ddo_registry.verify_tx( txid) is False, f"update ddo failed: txid={txid}" logs = ddo_registry.event_MetadataUpdated.processReceipt( ddo_registry.get_tx_receipt(txid)) assert ( not logs ), f"should be no logs for MetadataUpdated, but seems there are some logs: tx {txid}, logs {logs}" except ValueError: print("as expected, only owner can update a published ddo.") # test ddoOwner assert DataToken(asset.asset_id).contract_concise.isMinter( wallet.address ), (f"ddo owner does not match the expected publisher address {wallet.address}, " f"owner is {DataToken(asset.asset_id).contract_concise.minter(wallet.address)}" )
def deploy(network, addresses_file): config = ExampleConfig.get_config() ConfigProvider.set_config(config) Web3Provider.init_web3( provider=get_web3_connection_provider(config.network_url)) ContractHandler.set_artifacts_path(config.artifacts_path) artifacts_path = ContractHandler.artifacts_path if not addresses_file: addresses_file = config.address_file else: addresses_file = Path(addresses_file).expanduser().resolve() ocean = get_publisher_ocean_instance() web3 = ocean.web3 addresses = dict() if os.path.exists(addresses_file): with open(addresses_file) as f: network_addresses = json.load(f) else: network_addresses = {network: {}} if network == "ganache" and network not in network_addresses: network = "development" _addresses = network_addresses[network] # ****SET ENVT**** # grab vars factory_deployer_private_key = get_ganache_wallet().private_key # corner cases if invalidKey(factory_deployer_private_key): print("Need valid FACTORY_DEPLOYER_PRIVATE_KEY") sys.exit(0) # ****SEE FUNDS**** print("Keys:\n%s" % Wallet( web3=get_web3(), private_key=factory_deployer_private_key).keysStr()) print("") # ****DEPLOY**** deployer_wallet = Wallet(web3, private_key=factory_deployer_private_key) minter_addr = deployer_wallet.address # cap = 2 ** 255 not used if DTFactory.CONTRACT_NAME not in _addresses: print("****Deploy DataTokenTemplate: begin****") dt_address = DataToken.deploy( web3, deployer_wallet, artifacts_path, "Template Contract", "TEMPLATE", minter_addr, DataToken.DEFAULT_CAP_BASE, DTFactory.FIRST_BLOB, minter_addr, ) addresses[DataToken.CONTRACT_NAME] = dt_address print("****Deploy DataTokenTemplate: done****\n") print("****Deploy DTFactory: begin****") dtfactory = DTFactory( DTFactory.deploy(web3, deployer_wallet, artifacts_path, dt_address, minter_addr)) addresses[DTFactory.CONTRACT_NAME] = dtfactory.address print("****Deploy DTFactory: done****\n") if BFactory.CONTRACT_NAME not in _addresses: print("****Deploy BPool: begin****") bpool_address = BPool.deploy(web3, deployer_wallet, artifacts_path) bpool_template = BPool(bpool_address) addresses[BPool.CONTRACT_NAME] = bpool_address print("****Deploy BPool: done****\n") print("****Deploy 'BFactory': begin****") bfactory_address = BFactory.deploy(web3, deployer_wallet, artifacts_path, bpool_template.address) _ = BFactory(bfactory_address) addresses[BFactory.CONTRACT_NAME] = bfactory_address print("****Deploy 'BFactory': done****\n") if FixedRateExchange.CONTRACT_NAME not in _addresses: print("****Deploy 'FixedRateExchange': begin****") addresses[FixedRateExchange.CONTRACT_NAME] = FixedRateExchange.deploy( web3, deployer_wallet, artifacts_path) print("****Deploy 'FixedRateExchange': done****\n") if MetadataContract.CONTRACT_NAME not in _addresses: print("****Deploy 'Metadata': begin****") addresses[MetadataContract.CONTRACT_NAME] = MetadataContract.deploy( web3, deployer_wallet, artifacts_path) print("****Deploy 'Metadata': done****\n") if network in ("ganache", "development"): print("****Deploy fake OCEAN: begin****") # For simplicity, hijack DataTokenTemplate. minter_addr = deployer_wallet.address OCEAN_cap = 1410 * 10**6 # 1.41B OCEAN_cap_base = util.to_base_18(float(OCEAN_cap)) OCEAN_token = DataToken( DataToken.deploy( web3, deployer_wallet, artifacts_path, "Ocean", "OCEAN", minter_addr, OCEAN_cap_base, "", minter_addr, )) addresses["Ocean"] = OCEAN_token.address print("****Deploy fake OCEAN: done****\n") print("****Mint fake OCEAN: begin****") OCEAN_token.mint(minter_addr, OCEAN_cap_base, from_wallet=deployer_wallet) print("****Mint fake OCEAN: done****\n") print("****Distribute fake OCEAN: begin****") amt_distribute = 1000 amt_distribute_base = util.to_base_18(float(amt_distribute)) for key_label in ["TEST_PRIVATE_KEY1", "TEST_PRIVATE_KEY2"]: key = os.environ.get(key_label) if not key: continue dst_address = privateKeyToAddress(key) OCEAN_token.transfer(dst_address, amt_distribute_base, from_wallet=deployer_wallet) print("****Distribute fake OCEAN: done****\n") network_addresses[network].update(addresses) with open(addresses_file, "w") as f: json.dump(network_addresses, f, indent=2) return addresses
def dtfactory_address(): return DTFactory.configured_address( _NETWORK, ConfigProvider.get_config().address_file)
def _get_all_liquidity_records( self, action, pool_address, block_number=None, to_block=None, token_address=None, raw_result=True, ): current_block = to_block if to_block is not None else self.web3.eth.block_number pool = BPool(self.web3, pool_address) dt_address = token_address or self.get_token_address(pool_address, pool) factory = DTFactory(self.web3, self.dtfactory_address) if block_number is None: block_number = factory.get_token_registered_event( 0, current_block, token_address=dt_address ).blockNumber log_args = (block_number, current_block) if action == "join": logs = pool.get_join_logs(*log_args) elif action == "exit": logs = pool.get_exit_logs(*log_args) elif action == "swap": logs = pool.get_swap_logs(*log_args) else: raise ValueError( f"Invalid action: {action}. Expected 'join', 'exit', or 'swap'." ) if raw_result: return logs _all = [] for lg in logs: if action == "join": record = ( lg.args.caller, lg.args.tokenIn, lg.args.tokenAmountIn, 0, 0, lg.blockNumber, lg.transactionHash, "join", ) elif action == "exit": record = ( lg.args.caller, lg.args.tokenOut, lg.args.tokenAmountOut, 0, 0, lg.blockNumber, lg.transactionHash, "exit", ) else: assert action == "swap", f"Unknown pool action {action}" record = ( lg.args.caller, lg.args.tokenIn, lg.args.tokenAmountIn, lg.args.tokenOut, lg.args.tokenAmountOut, lg.blockNumber, lg.transactionHash, "swap", ) _all.append(record) return _all