From 8aee41836b15391e519aeca44d2f807172545e4c Mon Sep 17 00:00:00 2001 From: rykci Date: Fri, 27 Jan 2023 02:35:57 -0500 Subject: [PATCH 01/25] upload folder function --- mcs/api/bucket_api.py | 49 ++++++++++++++++++++++++++++++------------- 1 file changed, 34 insertions(+), 15 deletions(-) diff --git a/mcs/api/bucket_api.py b/mcs/api/bucket_api.py index e6843c9..4f1fd43 100644 --- a/mcs/api/bucket_api.py +++ b/mcs/api/bucket_api.py @@ -4,6 +4,7 @@ from queue import Queue import os, threading import urllib.request +import time from mcs.common.utils import object_to_filename from mcs.object.bucket_storage import Bucket, File @@ -163,21 +164,39 @@ def upload_file(self, bucket_name, object_name, file_path): print("\033[31mError:File already existed\033[0m") return None - # def upload_folder(self, bucket_id, folder_path, prefix=''): - # path = os.path.basename(folder_path) - # folder_name = os.path.splitext(path)[0] - # self.create_folder(folder_name, bucket_id, prefix) - # files = os.listdir(folder_path) - # success = [] - # for f in files: - # f_path = os.path.join(folder_path, f) - # if os.path.isdir(f_path): - # success.extend(self.upload_folder(bucket_id, f_path, os.path.join(prefix, folder_name))) - # else: - # self.upload_to_bucket(bucket_id, f_path, os.path.join(prefix, folder_name)) - # time.sleep(0.5) - # success.append(f_path) - # return success + def upload_to_bucket(self, bucket_name, file_path, prefix=''): + if os.path.isdir(file_path): + return self.upload_folder(bucket_name, file_path, prefix) + else: + file_name = os.path.basename(file_path) + return self.upload_file(bucket_name, os.path.join(prefix,file_name), file_path) + + def upload_folder(self, bucket_name, folder_path, prefix=''): + # path = os.path.basename(folder_path) + # folder_name = os.path.splitext(path)[0] + # self.create_folder(bucket_name, folder_path, prefix) + # files = os.listdir(folder_path) + # success = [] + # for f in files: + # f_path = os.path.join(folder_path, f) + # if os.path.isdir(f_path): + # success.extend(self.upload_folder(bucket_name, f_path, os.path.join(prefix, folder_name))) + # else: + # self.upload_file(bucket_name, os.path.join(prefix, f_path), f_path,) + # time.sleep(0.5) + # success.append(f_path) + # return success + folder_name = os.path.basename(folder_path) + self.create_folder(bucket_name, folder_name, prefix) + res = [] + files = os.listdir(folder_path) + for f in files: + f_path = os.path.join(folder_path, f) + upload = self.upload_to_bucket(bucket_name, f_path, os.path.join(prefix, folder_name)) + res.append(upload) + + return res + def download_file(self, bucket_name, object_name, local_filename): file = self.get_file(bucket_name, object_name) From 4fabd97e4d1a5d3e32f610382360c53f77d0987b Mon Sep 17 00:00:00 2001 From: rykci Date: Fri, 27 Jan 2023 15:14:54 -0500 Subject: [PATCH 02/25] handle None error --- mcs/api/bucket_api.py | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/mcs/api/bucket_api.py b/mcs/api/bucket_api.py index 4f1fd43..87c9eb0 100644 --- a/mcs/api/bucket_api.py +++ b/mcs/api/bucket_api.py @@ -29,7 +29,6 @@ def list_buckets(self): bucket_info: Bucket = Bucket(bucket) bucket_info_list.append(bucket_info) - # print(bucket_info_list) return bucket_info_list def create_bucket(self, bucket_name): @@ -74,6 +73,9 @@ def get_bucket(self, bucket_name='', bucket_id=''): def get_file(self, bucket_name, object_name): prefix, file_name = object_to_filename(object_name) file_list = self._get_full_file_list(bucket_name, prefix) + if file_list is None: + print("\033[31mError: Can't find this bucket\033[0m") + return for file in file_list: if file.name == file_name: return file @@ -84,6 +86,9 @@ def create_folder(self, bucket_name, folder_name, prefix=''): bucket_id = self._get_bucket_id(bucket_name) params = {"file_name": folder_name, "prefix": prefix, "bucket_uid": bucket_id} result = self.api_client._request_with_params(POST, CREATE_FOLDER, self.MCS_API, params, self.token, None) + if result is None: + print("\033[31mError: Can't create this folder") + return if result['status'] == 'success': print("\033[32mFolder created successfully\033[0m") return True @@ -94,6 +99,9 @@ def create_folder(self, bucket_name, folder_name, prefix=''): def delete_file(self, bucket_name, object_name): prefix, file_name = object_to_filename(object_name) file_list = self._get_full_file_list(bucket_name, prefix) + if file_list is None: + print("\033[31mError: Can't find this bucket\033[0m") + return file_id = '' for file in file_list: if file.name == file_name: @@ -164,7 +172,7 @@ def upload_file(self, bucket_name, object_name, file_path): print("\033[31mError:File already existed\033[0m") return None - def upload_to_bucket(self, bucket_name, file_path, prefix=''): + def _upload_to_bucket(self, bucket_name, file_path, prefix=''): if os.path.isdir(file_path): return self.upload_folder(bucket_name, file_path, prefix) else: @@ -192,7 +200,7 @@ def upload_folder(self, bucket_name, folder_path, prefix=''): files = os.listdir(folder_path) for f in files: f_path = os.path.join(folder_path, f) - upload = self.upload_to_bucket(bucket_name, f_path, os.path.join(prefix, folder_name)) + upload = self._upload_to_bucket(bucket_name, f_path, os.path.join(prefix, folder_name)) res.append(upload) return res From 1e6b6dfb4efab09cb70322c2fdc77b4459e5d913 Mon Sep 17 00:00:00 2001 From: rykci Date: Fri, 27 Jan 2023 16:08:29 -0500 Subject: [PATCH 03/25] check chain_name --- mcs/api_client.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/mcs/api_client.py b/mcs/api_client.py index 8464927..e9e04b9 100644 --- a/mcs/api_client.py +++ b/mcs/api_client.py @@ -29,9 +29,9 @@ def get_price_rate(self): def api_key_login(self): params = {'apikey': self.api_key, 'access_token': self.access_token, 'network': self.chain_name} - if params.get('apikey') == '' or params.get('access_token') == '': - print("\033[31mAPIkey or access token does not exist\033[0m") - return False + if params.get('apikey') == '' or params.get('access_token') == '' or params.get('chain_name') == '': + print("\033[31mAPIkey, access token, or chain name does not exist\033[0m") + return result = self._request_with_params(POST, APIKEY_LOGIN, self.MCS_API, params, None, None) if result is None: print("\033[31mRequest Error\033[0m") From e4c79a3cd082661c5949a8451c6d700043810700 Mon Sep 17 00:00:00 2001 From: rykci Date: Mon, 30 Jan 2023 12:06:28 -0500 Subject: [PATCH 04/25] replace print with logging --- mcs/api/bucket_api.py | 175 +++++++++++++++++++++--------------------- mcs/api_client.py | 23 +++--- 2 files changed, 98 insertions(+), 100 deletions(-) diff --git a/mcs/api/bucket_api.py b/mcs/api/bucket_api.py index 87c9eb0..a667219 100644 --- a/mcs/api/bucket_api.py +++ b/mcs/api/bucket_api.py @@ -1,10 +1,11 @@ +from aiohttp import request from mcs.api_client import APIClient from mcs.common.constants import * from hashlib import md5 from queue import Queue import os, threading import urllib.request -import time +import logging from mcs.common.utils import object_to_filename from mcs.object.bucket_storage import Bucket, File @@ -19,38 +20,45 @@ def __init__(self, api_client=None): self.token = self.api_client.token def list_buckets(self): - result = self.api_client._request_without_params(GET, BUCKET_LIST, self.MCS_API, self.token) - bucket_info_list = [] - if result['status'] != 'success': - print("\033[31mError: " + result['message'] + "\033[0m" ) + try: + result = self.api_client._request_without_params(GET, BUCKET_LIST, self.MCS_API, self.token) + bucket_info_list = [] + data = result['data'] + for bucket in data: + bucket_info: Bucket = Bucket(bucket) + bucket_info_list.append(bucket_info) + return bucket_info_list + except: + logging.error("\033[31m" + result['message'] + "\033[0m") return - data = result['data'] - for bucket in data: - bucket_info: Bucket = Bucket(bucket) - bucket_info_list.append(bucket_info) - - return bucket_info_list + def create_bucket(self, bucket_name): params = {'bucket_name': bucket_name} - result = self.api_client._request_with_params(POST, CREATE_BUCKET, self.MCS_API, params, self.token, None) - if result is None: - print("\033[31mError: This bucket already exists\033[0m") - return False - if result['status'] == 'success': - print("\033[32mBucket created successfully\033[0m") - return True + try: + result = self.api_client._request_with_params(POST, CREATE_BUCKET, self.MCS_API, params, self.token, None) + if result['status'] == 'success': + logging.info("\033[32mBucket created successfully\033[0m") + return True + else: + logging.error("\033[31m" + result['message'] + "\033[0m") + except: + logging.error("\033[31mThis bucket already exists\033[0m") + + return False def delete_bucket(self, bucket_name): - bucket_id = self._get_bucket_id(bucket_name) - params = {'bucket_uid': bucket_id} - result = self.api_client._request_with_params(GET, DELETE_BUCKET, self.MCS_API, params, self.token, None) - if result is None: - print("\033[31mError: Can't find this bucket\033[0m") - return False - if result['status'] == 'success': - print("\033[32mBucket delete successfully\033[0m") - return True + try: + bucket_id = self._get_bucket_id(bucket_name) + params = {'bucket_uid': bucket_id} + result = self.api_client._request_with_params(GET, DELETE_BUCKET, self.MCS_API, params, self.token, None) + if result['status'] == 'success': + logging.info("\033[32mBucket delete successfully\033[0m") + return True + except: + if result is None: + logging.error("\033[31mCan't find this bucket\033[0m") + return False def get_bucket(self, bucket_name='', bucket_id=''): bucketlist = self.list_buckets() @@ -66,57 +74,62 @@ def get_bucket(self, bucket_name='', bucket_id=''): for bucket in bucketlist: if bucket.bucket_uid == bucket_id: return bucket - print("\033[31mError: User does not have this bucket\033[0m") + logging.error("\033[31mUser does not have this bucket\033[0m") return None # object name def get_file(self, bucket_name, object_name): - prefix, file_name = object_to_filename(object_name) - file_list = self._get_full_file_list(bucket_name, prefix) - if file_list is None: - print("\033[31mError: Can't find this bucket\033[0m") + try: + prefix, file_name = object_to_filename(object_name) + file_list = self._get_full_file_list(bucket_name, prefix) + + for file in file_list: + if file.name == file_name: + return file + logging.error("\033[31mCan't find this object\033[0m") + return None + except: + logging.error("\033[31mCan't find this bucket\033[0m") return - for file in file_list: - if file.name == file_name: - return file - print("\033[31mError: Can't find this object\033[0m") - return None def create_folder(self, bucket_name, folder_name, prefix=''): - bucket_id = self._get_bucket_id(bucket_name) - params = {"file_name": folder_name, "prefix": prefix, "bucket_uid": bucket_id} - result = self.api_client._request_with_params(POST, CREATE_FOLDER, self.MCS_API, params, self.token, None) - if result is None: - print("\033[31mError: Can't create this folder") + try: + bucket_id = self._get_bucket_id(bucket_name) + params = {"file_name": folder_name, "prefix": prefix, "bucket_uid": bucket_id} + result = self.api_client._request_with_params(POST, CREATE_FOLDER, self.MCS_API, params, self.token, None) + if result['status'] == 'success': + logging.info("\033[31mFolder created successfully\033[0m") + return True + else: + logging.error("\033[31m" + result['message']+ "\033[0m") + return False + except: + logging.error("\033[31mCan't create this folder") return - if result['status'] == 'success': - print("\033[32mFolder created successfully\033[0m") - return True - else: - print("\033[31mError: " + result['message']+ "\033[0m") - return False def delete_file(self, bucket_name, object_name): - prefix, file_name = object_to_filename(object_name) - file_list = self._get_full_file_list(bucket_name, prefix) - if file_list is None: - print("\033[31mError: Can't find this bucket\033[0m") + try: + prefix, file_name = object_to_filename(object_name) + file_list = self._get_full_file_list(bucket_name, prefix) + + file_id = '' + for file in file_list: + if file.name == file_name: + file_id = file.id + params = {'file_id': file_id} + if file_id == '': + logging.error("\033[31mCan't find the file\033[0m") + return False + result = self.api_client._request_with_params(GET, DELETE_FILE, self.MCS_API, params, self.token, None) + if result['status'] == 'success': + logging.info("\033[32mFile delete successfully\033[0m") + return True + else: + logging.error("\033[31mCan't delete the file\033[0m") + return False + except: + logging.error("\033[31mCan't find this bucket\033[0m") return - file_id = '' - for file in file_list: - if file.name == file_name: - file_id = file.id - params = {'file_id': file_id} - if file_id == '': - print("\033[31mError: Can't find the file\033[0m") - return False - result = self.api_client._request_with_params(GET, DELETE_FILE, self.MCS_API, params, self.token, None) - if result['status'] == 'success': - print("\033[32mFile delete successfully\033[0m") - return True - else: - print("\033[31mError: Can't delete the file\033[0m") - return False def list_files(self, bucket_name, prefix='', limit='10', offset="0"): bucket_id = self._get_bucket_id(bucket_name) @@ -130,7 +143,7 @@ def list_files(self, bucket_name, prefix='', limit='10', offset="0"): file_list.append(file_info) return file_list else: - print("\033[31mError: " + result['message'] + "\033[0m") + logging.error("\033[31m" + result['message'] + "\033[0m") return False @@ -138,14 +151,14 @@ def upload_file(self, bucket_name, object_name, file_path): prefix, file_name = object_to_filename(object_name) bucket_id = self._get_bucket_id(bucket_name) if os.stat(file_path).st_size == 0: - print("\033[31mError:File size cannot be 0\033[0m") + logging.error("\033[31mFile size cannot be 0\033[0m") return None file_size = os.stat(file_path).st_size with open(file_path, 'rb') as file: file_hash = md5(file.read()).hexdigest() result = self._check_file(bucket_id, file_hash, file_name, prefix) if result is None: - print("\033[31mError:Cannot found bucket\033[0m") + logging.error("\033[31mCan't find this bucket\033[0m") return if not (result['data']['file_is_exist']): if not (result['data']['ipfs_is_exist']): @@ -167,9 +180,9 @@ def upload_file(self, bucket_name, object_name, file_path): result = self._merge_file(bucket_id, file_hash, file_name, prefix) file_id = result['data']['file_id'] file_info = self._get_file_info(file_id) - print("\033[32mFile upload successfully\033[0m") + logging.info("\033[32mFile upload successfully\033[0m") return file_info - print("\033[31mError:File already existed\033[0m") + logging.error("\033[31mFile already exists\033[0m") return None def _upload_to_bucket(self, bucket_name, file_path, prefix=''): @@ -180,20 +193,6 @@ def _upload_to_bucket(self, bucket_name, file_path, prefix=''): return self.upload_file(bucket_name, os.path.join(prefix,file_name), file_path) def upload_folder(self, bucket_name, folder_path, prefix=''): - # path = os.path.basename(folder_path) - # folder_name = os.path.splitext(path)[0] - # self.create_folder(bucket_name, folder_path, prefix) - # files = os.listdir(folder_path) - # success = [] - # for f in files: - # f_path = os.path.join(folder_path, f) - # if os.path.isdir(f_path): - # success.extend(self.upload_folder(bucket_name, f_path, os.path.join(prefix, folder_name))) - # else: - # self.upload_file(bucket_name, os.path.join(prefix, f_path), f_path,) - # time.sleep(0.5) - # success.append(f_path) - # return success folder_name = os.path.basename(folder_path) self.create_folder(bucket_name, folder_name, prefix) res = [] @@ -213,9 +212,9 @@ def download_file(self, bucket_name, object_name, local_filename): with open(local_filename, 'wb') as f: data = urllib.request.urlopen(ipfs_url) f.write(data.read()) - print("\033[32mFile download successfully\033[0m") + logging.info("\033[32mFile download successfully\033[0m") return True - print('\033[31mError: File does not exist\033[0m') + logging.error('\033[31mFile does not exist\033[0m') return False def _check_file(self, bucket_id, file_hash, file_name, prefix=''): diff --git a/mcs/api_client.py b/mcs/api_client.py index e9e04b9..83605b3 100644 --- a/mcs/api_client.py +++ b/mcs/api_client.py @@ -2,6 +2,7 @@ from mcs.common.params import Params import requests import json +import logging from mcs.common import utils, exceptions from mcs.common import constants as c from requests_toolbelt.multipart.encoder import MultipartEncoder, MultipartEncoderMonitor @@ -29,20 +30,18 @@ def get_price_rate(self): def api_key_login(self): params = {'apikey': self.api_key, 'access_token': self.access_token, 'network': self.chain_name} - if params.get('apikey') == '' or params.get('access_token') == '' or params.get('chain_name') == '': - print("\033[31mAPIkey, access token, or chain name does not exist\033[0m") - return - result = self._request_with_params(POST, APIKEY_LOGIN, self.MCS_API, params, None, None) - if result is None: - print("\033[31mRequest Error\033[0m") - return - if result['status'] != "success": - print("\033[31mError: " + result['message'] + ". \nPlease check your APIkey and access token, or " + # if params.get('apikey') == '' or params.get('access_token') == '' or params.get('chain_name') == '': + # logging.error("\033[31mAPIkey, access token, or chain name does not exist\033[0m") + # return + try: + result = self._request_with_params(POST, APIKEY_LOGIN, self.MCS_API, params, None, None) + self.token = result['data']['jwt_token'] + logging.info("\033[32mLogin successful\033[0m") + return self.token + except: + logging.error("\033[31m Please check your APIkey and access token, or " "check whether the current network environment corresponds to the APIkey.\033[0m") return - self.token = result['data']['jwt_token'] - print("\033[32mLogin successful\033[0m") - return self.token def _request(self, method, request_path, mcs_api, params, token, files=False): if method == c.GET: From 076b06335faaa3e194a6b097c13c73bcc886abc3 Mon Sep 17 00:00:00 2001 From: rykci Date: Thu, 2 Feb 2023 12:58:45 -0500 Subject: [PATCH 05/25] get file by object name --- mcs/api/bucket_api.py | 19 +++++++++---------- mcs/common/constants.py | 1 + 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/mcs/api/bucket_api.py b/mcs/api/bucket_api.py index a667219..a9cc733 100644 --- a/mcs/api/bucket_api.py +++ b/mcs/api/bucket_api.py @@ -29,7 +29,7 @@ def list_buckets(self): bucket_info_list.append(bucket_info) return bucket_info_list except: - logging.error("\033[31m" + result['message'] + "\033[0m") + logging.error("\033[31m" + 'error' + "\033[0m") return @@ -80,17 +80,16 @@ def get_bucket(self, bucket_name='', bucket_id=''): # object name def get_file(self, bucket_name, object_name): try: - prefix, file_name = object_to_filename(object_name) - file_list = self._get_full_file_list(bucket_name, prefix) + bucket_id = self._get_bucket_id(bucket_name) + params = {"bucket_uid": bucket_id, "object_name": object_name} + + result = self.api_client._request_with_params(GET, GET_FILE, self.MCS_API, params, self.token, None) - for file in file_list: - if file.name == file_name: - return file - logging.error("\033[31mCan't find this object\033[0m") - return None + if result: + return File(result['data']) except: - logging.error("\033[31mCan't find this bucket\033[0m") - return + print('error') + return def create_folder(self, bucket_name, folder_name, prefix=''): try: diff --git a/mcs/common/constants.py b/mcs/common/constants.py index 18b4f48..ecade99 100644 --- a/mcs/common/constants.py +++ b/mcs/common/constants.py @@ -29,6 +29,7 @@ UPLOAD_CHUNK = "/api/v2/oss_file/upload" MERGE_FILE = "/api/v2/oss_file/merge" FILE_LIST = "/api/v2/oss_file/get_file_list" +GET_FILE = "/api/v2/oss_file/get_file_by_object_name" # contract USDC_ABI = "ERC20.json" SWAN_PAYMENT_ABI = "SwanPayment.json" From 91bc5f47dad402b3fc054ea074a92eff75945bf5 Mon Sep 17 00:00:00 2001 From: rykci Date: Tue, 7 Feb 2023 15:54:03 -0500 Subject: [PATCH 06/25] onchain upload mint pay --- mcs/api/onchain_api.py | 168 +++++++++++++++++++++++++++++----- mcs/contract/mcs_contract.py | 80 ---------------- mcs/object/onchain_storage.py | 66 +++++++++++++ 3 files changed, 211 insertions(+), 103 deletions(-) delete mode 100644 mcs/contract/mcs_contract.py create mode 100644 mcs/object/onchain_storage.py diff --git a/mcs/api/onchain_api.py b/mcs/api/onchain_api.py index 6593893..83156f7 100644 --- a/mcs/api/onchain_api.py +++ b/mcs/api/onchain_api.py @@ -1,21 +1,116 @@ from mcs.api_client import APIClient +from mcs.contract import ContractClient from mcs.common.constants import * +from mcs.common.utils import get_contract_abi, get_amount +from web3 import Web3 +from web3.middleware import geth_poa_middleware +from eth_account import Account import json +import logging + +from mcs.object.onchain_storage import Upload, Deal, Payment class OnchainAPI(object): - def __init__(self, api_client=None): + def __init__(self, api_client=None, private_key=None, rpc_url='https://polygon-rpc.com/'): + if private_key is None: + logging.error("Please provide private_key to use MCS Onchain Storage.") if api_client is None: api_client = APIClient() self.api_client = api_client self.MCS_API = api_client.MCS_API self.token = self.api_client.token + + self.w3 = Web3(Web3.HTTPProvider(rpc_url)) + self.w3.middleware_onion.inject(geth_poa_middleware, layer=0) + self.account = Account.from_key(private_key) + if self._map_chain_name(api_client.chain_name) != self.w3.eth.chain_id: + logging.error(f"\033[31mRPC Chain ID ({self.w3.eth.chain_id}) does not match SDK chain name ({api_client.chain_name})\033[0m") + + self.params = api_client.get_params()["data"] + self.token_contract = self.w3.eth.contract(self.params['usdc_address'], abi=get_contract_abi(USDC_ABI)) + self.payment_contract = self.w3.eth.contract(self.params['payment_contract_address'], abi=get_contract_abi(SWAN_PAYMENT_ABI)) + self.mint_contract = self.w3.eth.contract(self.params['mint_contract_address'], abi=get_contract_abi(MINT_ABI)) + + + def upload(self, file_path, pay=False, params={}): + params['duration'] = '525' + params['storage_copy'] = '5' + params['file'] = (file_path, open(file_path, 'rb')) + upload = self.api_client._request_stream_upload(UPLOAD_FILE, self.MCS_API, params, self.token) + data = upload["data"] + return Upload(data) + + + def pay(self, source_file_upload_id, file_size, amount=''): + payment_info = self.get_payment_info(source_file_upload_id) + + if not amount: + amount = get_amount(float(file_size), self.params["filecoin_price"]) + + decimals = self.token_contract.functions.decimals().call() + contract_amount = int(amount * (10 ** decimals)) + + hash = self._approve_usdc(int(contract_amount * float(self.params['pay_multiply_factor']))) + print(hash) + + receipt = '' + + while not receipt: + receipt = self.w3.eth.get_transaction_receipt(hash) + + nonce = self.w3.eth.getTransactionCount(self.account.address) + decimals = self.token_contract.functions.decimals().call() + lock_obj = { + 'id': payment_info.w_cid, + 'minPayment': contract_amount, + 'amount': int(contract_amount * float(self.params['pay_multiply_factor'])), + 'lockTime': 86400 * self.params['lock_time'], + 'recipient': self.params['payment_recipient_address'], + 'size': file_size, + 'copyLimit': 5, + } + + tx = self.payment_contract.functions.lockTokenPayment(lock_obj).buildTransaction({ + 'from': self.account.address, + 'nonce': nonce + }) + signed_tx = self.w3.eth.account.signTransaction(tx, self.account._private_key) + tx_hash = self.w3.eth.sendRawTransaction(signed_tx.rawTransaction) + self.w3.eth.wait_for_transaction_receipt(tx_hash, timeout=CONTRACT_TIME_OUT) + + return self.w3.toHex(tx_hash) + + def mint(self, source_file_upload_id, nft_name, image_url, size, description=''): + metadata = self._upload_nft_metadata(source_file_upload_id, nft_name, image_url, size, description) + # print(metadata) + + nonce = self.w3.eth.getTransactionCount(self.account.address) + option_obj = { + 'from': self.account.address, + 'nonce': nonce + } + tx = self.mint_contract.functions.mintUnique(self.account.address, str(metadata["data"]["ipfs_url"])).buildTransaction(option_obj) + signed_tx = self.w3.eth.account.signTransaction(tx, self.account._private_key) + tx_hash = self.w3.eth.sendRawTransaction(signed_tx.rawTransaction) + receipt = self.w3.eth.wait_for_transaction_receipt(tx_hash, timeout=CONTRACT_TIME_OUT) + result = self.mint_contract.events.TransferSingle().processReceipt(receipt) + id = result[0]['args']['id'] + token_id = int(id) + + self._post_mint_info(source_file_upload_id, self.w3.toHex(tx_hash), token_id, self.mint_contract.address) + + return self.w3.toHex(tx_hash), token_id def get_payment_info(self, source_file_upload_id): params = {} if source_file_upload_id: params['source_file_upload_id'] = source_file_upload_id - return self.api_client._request_with_params(GET, PAYMENT_INFO, self.MCS_API, params, self.token, None) + payment_data = self.api_client._request_with_params(GET, PAYMENT_INFO, self.MCS_API, params, self.token, None) + if not payment_data: + logging.error(f"\033[31mpayment info for id {source_file_upload_id} not found \033[0m") + return + return Payment(payment_data["data"]) def get_user_tasks_deals(self, page_number=None, page_size=None, file_name=None, status=None): params = {} @@ -29,8 +124,8 @@ def get_user_tasks_deals(self, page_number=None, page_size=None, file_name=None, params['status'] = status return self.api_client._request_with_params(GET, TASKS_DEALS, self.MCS_API, params, self.token, None) - def get_mint_info(self, source_file_upload_id, payload_cid, tx_hash, token_id, mint_address): - params = {'source_file_upload_id': source_file_upload_id, 'payload_cid': payload_cid, 'tx_hash': tx_hash, + def _post_mint_info(self, source_file_upload_id, tx_hash, token_id, mint_address): + params = {'source_file_upload_id': source_file_upload_id, 'tx_hash': tx_hash, 'token_id': int(token_id), 'mint_address': mint_address} return self.api_client._request_with_params(POST, MINT_INFO, self.MCS_API, params, self.token, None) @@ -45,25 +140,52 @@ def get_deal_detail(self, source_file_upload_id, deal_id='0'): params = {} if source_file_upload_id: params['source_file_upload_id'] = source_file_upload_id - return self.api_client._request_with_params(GET, DEAL_DETAIL + deal_id, self.MCS_API, params, self.token, None) + deal = self.api_client._request_with_params(GET, DEAL_DETAIL + deal_id, self.MCS_API, params, self.token, None) + return Deal(deal["data"]["source_file_upload_deal"]) - def upload_nft_metadata(self, address, file_name, image_url, tx_hash, size): + def _upload_nft_metadata(self, source_file_upload_id, nft_name, image_url, size, description): params = {} - if address: - params['duration'] = '525' - params['file_type'] = '1' - params['wallet_address'] = address - file_url = {} - if image_url: - file_url['name'] = file_name - file_url['image'] = image_url - file_url['tx_hash'] = tx_hash - file_url['attributes'] = [ - { - "trait_type": "Size", - "value": size - } - ] - file_url['external_url'] = image_url - files = {"fileName": "test", "file": json.dumps(file_url)} + params['duration'] = '525' + params['file_type'] = '1' + params['wallet_address'] = self.account.address + + payment_info = self.get_payment_info(source_file_upload_id) + + nft = {} + nft['name'] = nft_name + nft['description'] = description + nft['image'] = image_url + nft['tx_hash'] = payment_info.pay_tx_hash + nft['attributes'] = [ + { + "trait_type": "Size", + "value": size + } + ] + nft['external_url'] = image_url + # params['file'] = (nft_name, json.dumps(nft)) + files = {"fileName": nft_name, "file": json.dumps(nft)} return self.api_client._request_with_params(POST, UPLOAD_FILE, self.MCS_API, params, self.token, files) + + # upload = self.api_client._request_stream_upload(UPLOAD_FILE, self.MCS_API, params, self.token) + # data = upload["data"] + # print(data) + # return Upload(data) + + def _approve_usdc(self, amount): + nonce = self.w3.eth.getTransactionCount(self.account.address) + tx = self.token_contract.functions.approve(self.payment_contract.address, amount).buildTransaction({ + 'from': self.account.address, + 'nonce': nonce + }) + signed_tx = self.w3.eth.account.signTransaction(tx, self.account._private_key) + tx_hash = self.w3.eth.sendRawTransaction(signed_tx.rawTransaction) + self.w3.eth.wait_for_transaction_receipt(tx_hash, timeout=CONTRACT_TIME_OUT) + return self.w3.toHex(tx_hash) + + def _map_chain_name(self, chain_name): + if chain_name == 'polygon.mainnet': + return 137 + elif chain_name == 'polygon.mumbai': + return 80001 + return -1 diff --git a/mcs/contract/mcs_contract.py b/mcs/contract/mcs_contract.py deleted file mode 100644 index b249e5c..0000000 --- a/mcs/contract/mcs_contract.py +++ /dev/null @@ -1,80 +0,0 @@ -from web3 import Web3 -from mcs.common.constants import * -from mcs.common.params import Params -from mcs.common.utils import get_contract_abi, get_amount -from web3.middleware import geth_poa_middleware -from mcs.api_client import APIClient - - -class ContractClient(): - def __init__(self, rpc_endpoint, chain_name): - self.rpc_endpoint = rpc_endpoint - self.w3 = Web3(Web3.HTTPProvider(rpc_endpoint)) - self.w3.middleware_onion.inject(geth_poa_middleware, layer=0) - data = APIClient(None, None, chain_name, False).get_params()['data'] - self.SWAN_PAYMENT_ADDRESS = data['payment_contract_address'] - self.USDC_TOKEN = data['usdc_address'] - self.MINT_ADDRESS = data['mint_contract_address'] - - def approve_usdc(self, wallet_address, private_key, amount): - nonce = self.w3.eth.getTransactionCount(wallet_address) - usdc_abi = get_contract_abi(USDC_ABI) - token = self.w3.eth.contract(self.USDC_TOKEN, abi=usdc_abi) - decimals = token.functions.decimals().call() - amount = int(amount * (10 ** decimals)) - usdc_balance = token.functions.balanceOf(wallet_address).call() - if int(usdc_balance) < int(amount): - print("Insufficient balance") - return - tx = token.functions.approve(self.SWAN_PAYMENT_ADDRESS, amount).buildTransaction({ - 'from': wallet_address, - 'nonce': nonce - }) - signed_tx = self.w3.eth.account.signTransaction(tx, private_key) - tx_hash = self.w3.eth.sendRawTransaction(signed_tx.rawTransaction) - self.w3.eth.wait_for_transaction_receipt(tx_hash, timeout=CONTRACT_TIME_OUT) - return self.w3.toHex(tx_hash) - - def upload_file_pay(self, wallet_address, private_key, file_size, w_cid, rate, params): - amount = get_amount(file_size, rate) - nonce = self.w3.eth.getTransactionCount(wallet_address) - swan_payment_abi = get_contract_abi(SWAN_PAYMENT_ABI) - swan_payment = self.w3.eth.contract(self.SWAN_PAYMENT_ADDRESS, abi=swan_payment_abi) - usdc_abi = get_contract_abi(USDC_ABI) - token = self.w3.eth.contract(self.USDC_TOKEN, abi=usdc_abi) - decimals = token.functions.decimals().call() - lock_obj = { - 'id': w_cid, - 'minPayment': int(amount * (10 ** decimals)), - 'amount': int(amount * (10 ** decimals) * float(params['pay_multiply_factor'])), - 'lockTime': 86400 * params['lock_time'], - 'recipient': params['payment_recipient_address'], - 'size': file_size, - 'copyLimit': 5, - } - options_obj = { - 'from': wallet_address, - 'nonce': nonce - } - tx = swan_payment.functions.lockTokenPayment(lock_obj).buildTransaction(options_obj) - signed_tx = self.w3.eth.account.signTransaction(tx, private_key) - tx_hash = self.w3.eth.sendRawTransaction(signed_tx.rawTransaction) - self.w3.eth.wait_for_transaction_receipt(tx_hash, timeout=CONTRACT_TIME_OUT) - return self.w3.toHex(tx_hash) - - def mint_nft(self, wallet_address, private_key, nft_meta_uri): - nonce = self.w3.eth.getTransactionCount(wallet_address) - mint_abi = get_contract_abi(MINT_ABI) - mint_contract = self.w3.eth.contract(self.MINT_ADDRESS, abi=mint_abi) - option_obj = { - 'from': wallet_address, - 'nonce': nonce - } - tx = mint_contract.functions.mintUnique(wallet_address, str(nft_meta_uri)).buildTransaction(option_obj) - signed_tx = self.w3.eth.account.signTransaction(tx, private_key) - tx_hash = self.w3.eth.sendRawTransaction(signed_tx.rawTransaction) - receipt = self.w3.eth.wait_for_transaction_receipt(tx_hash, timeout=CONTRACT_TIME_OUT) - result = mint_contract.events.TransferSingle().processReceipt(receipt) - id = result[0]['args']['id'] - token_id = int(id) - return self.w3.toHex(tx_hash), token_id diff --git a/mcs/object/onchain_storage.py b/mcs/object/onchain_storage.py new file mode 100644 index 0000000..39e9295 --- /dev/null +++ b/mcs/object/onchain_storage.py @@ -0,0 +1,66 @@ +import json + + +class Upload: + def __init__(self, upload_data): + self.source_file_upload_id = upload_data["source_file_upload_id"] + self.payload_cid = upload_data["payload_cid"] + self.ipfs_url = upload_data["ipfs_url"] + self.file_size = upload_data["file_size"] + self.w_cid = upload_data["w_cid"] + self.status = upload_data["status"] + + def pay(self, amount=''): + pass + + def to_json(self): + return json.dumps(self, default=lambda o: o.__dict__, + sort_keys=True, indent=4) + + +class Deal: + def __init__(self, deal_data): + self.deal_id = deal_data["deal_id"] + self.message_cid = deal_data["message_cid"] + self.deal_cid = deal_data["deal_cid"] + self.height = deal_data["height"] + self.piece_cid = deal_data["piece_cid"] + self.verified_deal = deal_data["verified_deal"] + self.storage_price_per_epoch = deal_data["storage_price_per_epoch"] + self.signature = deal_data["signature"] + self.signature_type = deal_data["signature_type"] + self.created_at = deal_data["created_at"] + self.piece_size_format = deal_data["piece_size_format"] + self.start_height = deal_data["start_height"] + self.end_height = deal_data["end_height"] + self.client = deal_data["client"] + self.client_collateral_format = deal_data["client_collateral_format"] + self.provider = deal_data["provider"] + self.provider_tag = deal_data["provider_tag"] + self.verified_provider = deal_data["verified_provider"] + self.provider_collateral_format = deal_data["provider_collateral_format"] + self.status = deal_data["status"] + self.network_name = deal_data["network_name"] + self.storage_price = deal_data["storage_price"] + self.ipfs_url = deal_data["ipfs_url"] + self.file_name = deal_data["file_name"] + self.w_cid = deal_data["w_cid"] + self.car_file_payload_cid = deal_data["car_file_payload_cid"] + self.locked_at = deal_data["locked_at"] + self.locked_fee = deal_data["locked_fee"] + self.unlocked = deal_data["unlocked"] + + def to_json(self): + return json.dumps(self, default=lambda o: o.__dict__, + sort_keys=True, indent=4) + +class Payment: + def __init__(self, payment_data): + self.w_cid = payment_data["w_cid"] + self.pay_amount = payment_data["pay_amount"] + self.pay_tx_hash = payment_data["pay_tx_hash"] + self.token_address = payment_data["token_address"] + + def to_json(self): + return json.dumps(self, default=lambda o: o.__dict__, + sort_keys=True, indent=4) \ No newline at end of file From 86ebeae85de51d5d6c6dcf55aa9c17ad96876b97 Mon Sep 17 00:00:00 2001 From: Zihang Chen Date: Wed, 8 Feb 2023 09:35:55 -0500 Subject: [PATCH 07/25] file sub --- mcs/api/bucket_api.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/mcs/api/bucket_api.py b/mcs/api/bucket_api.py index a667219..2af0959 100644 --- a/mcs/api/bucket_api.py +++ b/mcs/api/bucket_api.py @@ -147,7 +147,7 @@ def list_files(self, bucket_name, prefix='', limit='10', offset="0"): return False - def upload_file(self, bucket_name, object_name, file_path): + def upload_file(self, bucket_name, object_name, file_path, replace=False): prefix, file_name = object_to_filename(object_name) bucket_id = self._get_bucket_id(bucket_name) if os.stat(file_path).st_size == 0: @@ -160,6 +160,10 @@ def upload_file(self, bucket_name, object_name, file_path): if result is None: logging.error("\033[31mCan't find this bucket\033[0m") return + # Replace file if already existed + if result[['data']['file_is_exist']] and replace: + self.delete_file(bucket_name, object_name) + result = self._check_file(bucket_id, file_hash, file_name, prefix) if not (result['data']['file_is_exist']): if not (result['data']['ipfs_is_exist']): with open(file_path, 'rb') as file: From e7b503ef03c74abd9920e5e828b6d18ba8188a8e Mon Sep 17 00:00:00 2001 From: rykci Date: Wed, 15 Feb 2023 10:21:43 -0500 Subject: [PATCH 08/25] collection factory mint --- mcs/__init__.py | 3 +- mcs/api/onchain_api.py | 30 +- mcs/api_client.py | 2 +- mcs/common/constants.py | 2 +- mcs/contract/abi/CollectionFactory.json | 241 ++++++++++ mcs/contract/abi/SwanNFT.json | 584 ------------------------ 6 files changed, 254 insertions(+), 608 deletions(-) create mode 100644 mcs/contract/abi/CollectionFactory.json delete mode 100644 mcs/contract/abi/SwanNFT.json diff --git a/mcs/__init__.py b/mcs/__init__.py index f337bb0..c92e0cd 100644 --- a/mcs/__init__.py +++ b/mcs/__init__.py @@ -1,4 +1,3 @@ from mcs.api_client import APIClient from mcs.api import OnchainAPI -from mcs.api import BucketAPI -from mcs.contract import ContractClient \ No newline at end of file +from mcs.api import BucketAPI \ No newline at end of file diff --git a/mcs/api/onchain_api.py b/mcs/api/onchain_api.py index 83156f7..6fdcd93 100644 --- a/mcs/api/onchain_api.py +++ b/mcs/api/onchain_api.py @@ -1,9 +1,9 @@ from mcs.api_client import APIClient -from mcs.contract import ContractClient from mcs.common.constants import * from mcs.common.utils import get_contract_abi, get_amount from web3 import Web3 from web3.middleware import geth_poa_middleware +from web3.logs import DISCARD from eth_account import Account import json import logging @@ -30,7 +30,7 @@ def __init__(self, api_client=None, private_key=None, rpc_url='https://polygon-r self.params = api_client.get_params()["data"] self.token_contract = self.w3.eth.contract(self.params['usdc_address'], abi=get_contract_abi(USDC_ABI)) self.payment_contract = self.w3.eth.contract(self.params['payment_contract_address'], abi=get_contract_abi(SWAN_PAYMENT_ABI)) - self.mint_contract = self.w3.eth.contract(self.params['mint_contract_address'], abi=get_contract_abi(MINT_ABI)) + self.mint_contract = self.w3.eth.contract(self.params['nft_collection_factory_address'], abi=get_contract_abi(MINT_ABI)) def upload(self, file_path, pay=False, params={}): @@ -81,8 +81,10 @@ def pay(self, source_file_upload_id, file_size, amount=''): return self.w3.toHex(tx_hash) - def mint(self, source_file_upload_id, nft_name, image_url, size, description=''): - metadata = self._upload_nft_metadata(source_file_upload_id, nft_name, image_url, size, description) + def mint(self, source_file_upload_id, nft, collection_address = '', quantity = 1): + if not collection_address: + collection_address = self.params["default_nft_collection_address"] + metadata = self._upload_nft_metadata(source_file_upload_id, nft) # print(metadata) nonce = self.w3.eth.getTransactionCount(self.account.address) @@ -90,11 +92,11 @@ def mint(self, source_file_upload_id, nft_name, image_url, size, description='') 'from': self.account.address, 'nonce': nonce } - tx = self.mint_contract.functions.mintUnique(self.account.address, str(metadata["data"]["ipfs_url"])).buildTransaction(option_obj) + tx = self.mint_contract.functions.mint(collection_address, self.account.address, quantity, str(metadata["data"]["ipfs_url"])).buildTransaction(option_obj) signed_tx = self.w3.eth.account.signTransaction(tx, self.account._private_key) tx_hash = self.w3.eth.sendRawTransaction(signed_tx.rawTransaction) receipt = self.w3.eth.wait_for_transaction_receipt(tx_hash, timeout=CONTRACT_TIME_OUT) - result = self.mint_contract.events.TransferSingle().processReceipt(receipt) + result = self.mint_contract.events.TransferSingle().processReceipt(receipt, errors=DISCARD) id = result[0]['args']['id'] token_id = int(id) @@ -143,7 +145,7 @@ def get_deal_detail(self, source_file_upload_id, deal_id='0'): deal = self.api_client._request_with_params(GET, DEAL_DETAIL + deal_id, self.MCS_API, params, self.token, None) return Deal(deal["data"]["source_file_upload_deal"]) - def _upload_nft_metadata(self, source_file_upload_id, nft_name, image_url, size, description): + def _upload_nft_metadata(self, source_file_upload_id, nft): params = {} params['duration'] = '525' params['file_type'] = '1' @@ -151,20 +153,8 @@ def _upload_nft_metadata(self, source_file_upload_id, nft_name, image_url, size, payment_info = self.get_payment_info(source_file_upload_id) - nft = {} - nft['name'] = nft_name - nft['description'] = description - nft['image'] = image_url - nft['tx_hash'] = payment_info.pay_tx_hash - nft['attributes'] = [ - { - "trait_type": "Size", - "value": size - } - ] - nft['external_url'] = image_url # params['file'] = (nft_name, json.dumps(nft)) - files = {"fileName": nft_name, "file": json.dumps(nft)} + files = {"fileName": nft["name"], "file": json.dumps(nft)} return self.api_client._request_with_params(POST, UPLOAD_FILE, self.MCS_API, params, self.token, files) # upload = self.api_client._request_stream_upload(UPLOAD_FILE, self.MCS_API, params, self.token) diff --git a/mcs/api_client.py b/mcs/api_client.py index 8464927..cffd475 100644 --- a/mcs/api_client.py +++ b/mcs/api_client.py @@ -22,7 +22,7 @@ def __init__(self, api_key, access_token, chain_name=None, login=True): self.api_key_login() def get_params(self): - return self._request_without_params(GET, MCS_PARAMS, self.MCS_API, None) + return self._request_without_params(GET, MCS_PARAMS, self.MCS_API, self.token) def get_price_rate(self): return self._request_without_params(GET, PRICE_RATE, self.MCS_API, self.token) diff --git a/mcs/common/constants.py b/mcs/common/constants.py index 18b4f48..aa629f3 100644 --- a/mcs/common/constants.py +++ b/mcs/common/constants.py @@ -32,6 +32,6 @@ # contract USDC_ABI = "ERC20.json" SWAN_PAYMENT_ABI = "SwanPayment.json" -MINT_ABI = "SwanNFT.json" +MINT_ABI = "CollectionFactory.json" CONTRACT_TIME_OUT = 300 diff --git a/mcs/contract/abi/CollectionFactory.json b/mcs/contract/abi/CollectionFactory.json new file mode 100644 index 0000000..b27aac6 --- /dev/null +++ b/mcs/contract/abi/CollectionFactory.json @@ -0,0 +1,241 @@ +[ + { + "inputs": [ + { + "internalType": "address", + "name": "defaultCollection", + "type": "address" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "collectionOwner", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "collectionAddress", + "type": "address" + } + ], + "name": "CreateCollection", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "previousOwner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "OwnershipTransferred", + "type": "event" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "collectionAddress", + "type": "address" + } + ], + "name": "changeDefaultCollection", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "string", + "name": "contractURI", + "type": "string" + } + ], + "name": "createCollection", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "defaultCollectionAddress", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "user", + "type": "address" + } + ], + "name": "getCollections", + "outputs": [ + { + "internalType": "address[]", + "name": "", + "type": "address[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "collection", + "type": "address" + }, + { + "internalType": "address", + "name": "recipient", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "internalType": "string", + "name": "uri", + "type": "string" + } + ], + "name": "mint", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "string", + "name": "contractURI", + "type": "string" + }, + { + "internalType": "address", + "name": "recipient", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "internalType": "string", + "name": "uri", + "type": "string" + } + ], + "name": "mintToNewCollection", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "owner", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "renounceOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "transferOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "operator", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "id", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "value", + "type": "uint256" + } + ], + "name": "TransferSingle", + "type": "event" + } +] diff --git a/mcs/contract/abi/SwanNFT.json b/mcs/contract/abi/SwanNFT.json deleted file mode 100644 index 4752d5b..0000000 --- a/mcs/contract/abi/SwanNFT.json +++ /dev/null @@ -1,584 +0,0 @@ -[ - { - "inputs": [], - "stateMutability": "nonpayable", - "type": "constructor" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "account", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "operator", - "type": "address" - }, - { - "indexed": false, - "internalType": "bool", - "name": "approved", - "type": "bool" - } - ], - "name": "ApprovalForAll", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint8", - "name": "version", - "type": "uint8" - } - ], - "name": "Initialized", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "previousOwner", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "newOwner", - "type": "address" - } - ], - "name": "OwnershipTransferred", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "operator", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "from", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "to", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256[]", - "name": "ids", - "type": "uint256[]" - }, - { - "indexed": false, - "internalType": "uint256[]", - "name": "values", - "type": "uint256[]" - } - ], - "name": "TransferBatch", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "operator", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "from", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "to", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "id", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "value", - "type": "uint256" - } - ], - "name": "TransferSingle", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "string", - "name": "value", - "type": "string" - }, - { - "indexed": true, - "internalType": "uint256", - "name": "id", - "type": "uint256" - } - ], - "name": "URI", - "type": "event" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "account", - "type": "address" - }, - { - "internalType": "uint256", - "name": "id", - "type": "uint256" - } - ], - "name": "balanceOf", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address[]", - "name": "accounts", - "type": "address[]" - }, - { - "internalType": "uint256[]", - "name": "ids", - "type": "uint256[]" - } - ], - "name": "balanceOfBatch", - "outputs": [ - { - "internalType": "uint256[]", - "name": "", - "type": "uint256[]" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "contractURI", - "outputs": [ - { - "internalType": "string", - "name": "", - "type": "string" - } - ], - "stateMutability": "pure", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "id", - "type": "uint256" - } - ], - "name": "exists", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "idCount", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "initialize", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "account", - "type": "address" - }, - { - "internalType": "address", - "name": "operator", - "type": "address" - } - ], - "name": "isApprovedForAll", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "name": "isUnique", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "account", - "type": "address" - }, - { - "internalType": "uint256", - "name": "amount", - "type": "uint256" - }, - { - "internalType": "bytes", - "name": "data", - "type": "bytes" - } - ], - "name": "mint", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "account", - "type": "address" - }, - { - "internalType": "uint256", - "name": "id", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "amount", - "type": "uint256" - }, - { - "internalType": "bytes", - "name": "data", - "type": "bytes" - } - ], - "name": "mintMore", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "account", - "type": "address" - }, - { - "internalType": "string", - "name": "newUri", - "type": "string" - } - ], - "name": "mintUnique", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "account", - "type": "address" - }, - { - "internalType": "string", - "name": "newUri", - "type": "string" - }, - { - "internalType": "bytes", - "name": "data", - "type": "bytes" - } - ], - "name": "mintUniqueWithData", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "owner", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "renounceOwnership", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "from", - "type": "address" - }, - { - "internalType": "address", - "name": "to", - "type": "address" - }, - { - "internalType": "uint256[]", - "name": "ids", - "type": "uint256[]" - }, - { - "internalType": "uint256[]", - "name": "amounts", - "type": "uint256[]" - }, - { - "internalType": "bytes", - "name": "data", - "type": "bytes" - } - ], - "name": "safeBatchTransferFrom", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "from", - "type": "address" - }, - { - "internalType": "address", - "name": "to", - "type": "address" - }, - { - "internalType": "uint256", - "name": "id", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "amount", - "type": "uint256" - }, - { - "internalType": "bytes", - "name": "data", - "type": "bytes" - } - ], - "name": "safeTransferFrom", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "operator", - "type": "address" - }, - { - "internalType": "bool", - "name": "approved", - "type": "bool" - } - ], - "name": "setApprovalForAll", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "id", - "type": "uint256" - }, - { - "internalType": "string", - "name": "newUri", - "type": "string" - } - ], - "name": "setURI", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes4", - "name": "interfaceId", - "type": "bytes4" - } - ], - "name": "supportsInterface", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "id", - "type": "uint256" - } - ], - "name": "totalSupply", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "newOwner", - "type": "address" - } - ], - "name": "transferOwnership", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "tokenId", - "type": "uint256" - } - ], - "name": "uri", - "outputs": [ - { - "internalType": "string", - "name": "", - "type": "string" - } - ], - "stateMutability": "view", - "type": "function" - } -] From 2277fbb359b13aa8f40837bf2253a7f3f16d46d3 Mon Sep 17 00:00:00 2001 From: rykci Date: Wed, 15 Feb 2023 12:12:33 -0500 Subject: [PATCH 09/25] create collection --- mcs/api/onchain_api.py | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/mcs/api/onchain_api.py b/mcs/api/onchain_api.py index 6fdcd93..e5ca3df 100644 --- a/mcs/api/onchain_api.py +++ b/mcs/api/onchain_api.py @@ -84,7 +84,7 @@ def pay(self, source_file_upload_id, file_size, amount=''): def mint(self, source_file_upload_id, nft, collection_address = '', quantity = 1): if not collection_address: collection_address = self.params["default_nft_collection_address"] - metadata = self._upload_nft_metadata(source_file_upload_id, nft) + metadata = self._upload_nft_metadata(nft) # print(metadata) nonce = self.w3.eth.getTransactionCount(self.account.address) @@ -104,6 +104,24 @@ def mint(self, source_file_upload_id, nft, collection_address = '', quantity = 1 return self.w3.toHex(tx_hash), token_id + def create_collection(self, collection_metadata): + metadata = self._upload_nft_metadata(collection_metadata) + # print(metadata) + + nonce = self.w3.eth.getTransactionCount(self.account.address) + option_obj = { + 'from': self.account.address, + 'nonce': nonce + } + tx = self.mint_contract.functions.createCollection(str(metadata["data"]["ipfs_url"])).buildTransaction(option_obj) + signed_tx = self.w3.eth.account.signTransaction(tx, self.account._private_key) + tx_hash = self.w3.eth.sendRawTransaction(signed_tx.rawTransaction) + receipt = self.w3.eth.wait_for_transaction_receipt(tx_hash, timeout=CONTRACT_TIME_OUT) + result = self.mint_contract.events.CreateCollection().processReceipt(receipt, errors=DISCARD) + collection_address = result[0]['args']['collectionAddress'] + + return self.w3.toHex(tx_hash), collection_address + def get_payment_info(self, source_file_upload_id): params = {} if source_file_upload_id: @@ -145,14 +163,12 @@ def get_deal_detail(self, source_file_upload_id, deal_id='0'): deal = self.api_client._request_with_params(GET, DEAL_DETAIL + deal_id, self.MCS_API, params, self.token, None) return Deal(deal["data"]["source_file_upload_deal"]) - def _upload_nft_metadata(self, source_file_upload_id, nft): + def _upload_nft_metadata(self, nft): params = {} params['duration'] = '525' params['file_type'] = '1' params['wallet_address'] = self.account.address - payment_info = self.get_payment_info(source_file_upload_id) - # params['file'] = (nft_name, json.dumps(nft)) files = {"fileName": nft["name"], "file": json.dumps(nft)} return self.api_client._request_with_params(POST, UPLOAD_FILE, self.MCS_API, params, self.token, files) From 15bbfefc26610446f2a549a3bde7effa5d6d0687 Mon Sep 17 00:00:00 2001 From: rykci Date: Wed, 15 Feb 2023 14:31:38 -0500 Subject: [PATCH 10/25] get collections --- mcs/api/onchain_api.py | 6 +++++- mcs/common/constants.py | 1 + mcs/object/onchain_storage.py | 13 +++++++++++++ 3 files changed, 19 insertions(+), 1 deletion(-) diff --git a/mcs/api/onchain_api.py b/mcs/api/onchain_api.py index e5ca3df..07882ae 100644 --- a/mcs/api/onchain_api.py +++ b/mcs/api/onchain_api.py @@ -8,7 +8,7 @@ import json import logging -from mcs.object.onchain_storage import Upload, Deal, Payment +from mcs.object.onchain_storage import * class OnchainAPI(object): @@ -163,6 +163,10 @@ def get_deal_detail(self, source_file_upload_id, deal_id='0'): deal = self.api_client._request_with_params(GET, DEAL_DETAIL + deal_id, self.MCS_API, params, self.token, None) return Deal(deal["data"]["source_file_upload_deal"]) + def get_collections(self): + res = self.api_client._request_without_params(GET, COLLECTIONS, self.MCS_API, self.token) + return list(map(lambda collection: Collection(collection) ,res["data"])) + def _upload_nft_metadata(self, nft): params = {} params['duration'] = '525' diff --git a/mcs/common/constants.py b/mcs/common/constants.py index aa629f3..387ef14 100644 --- a/mcs/common/constants.py +++ b/mcs/common/constants.py @@ -18,6 +18,7 @@ USER_LOGIN = "/api/v1/user/login_by_metamask_signature" GENERATE_APIKEY = "/api/v1/user/generate_api_key" APIKEY_LOGIN = "/api/v1/user/login_by_api_key" +COLLECTIONS = "/api/v1/storage/mint/nft_collections" # bucket api CREATE_BUCKET = "/api/v2/bucket/create" BUCKET_LIST = "/api/v2/bucket/get_bucket_list" diff --git a/mcs/object/onchain_storage.py b/mcs/object/onchain_storage.py index 39e9295..88afc91 100644 --- a/mcs/object/onchain_storage.py +++ b/mcs/object/onchain_storage.py @@ -54,6 +54,19 @@ def to_json(self): return json.dumps(self, default=lambda o: o.__dict__, sort_keys=True, indent=4) +class Collection: + def __init__(self, collection_data): + self.id = collection_data["id"] + self.address = collection_data["address"] + self.wallet_id = collection_data["wallet_id"] + self.tx_hash = collection_data["tx_hash"] + self.create_at = collection_data["create_at"] + self.update_at = collection_data["update_at"] + + def to_json(self): + return json.dumps(self, default=lambda o: o.__dict__, + sort_keys=True, indent=4) + class Payment: def __init__(self, payment_data): self.w_cid = payment_data["w_cid"] From c9eb23fa8a8df1c461a97e4c0babcb88ba9c22a8 Mon Sep 17 00:00:00 2001 From: rykci Date: Thu, 23 Feb 2023 11:54:41 -0500 Subject: [PATCH 11/25] update test case --- mcs/api/onchain_api.py | 77 +++++++++++------ mcs/common/constants.py | 1 + mcs/contract/abi/CollectionFactory.json | 10 +++ mcs/object/onchain_storage.py | 35 +++++++- mcs/upload/__init__.py | 0 mcs/upload/onchain_upload.py | 68 --------------- test/test_bucket_api.py | 105 +++++++++++------------- test/test_onchain_api.py | 72 ++++++++++------ 8 files changed, 193 insertions(+), 175 deletions(-) delete mode 100644 mcs/upload/__init__.py delete mode 100644 mcs/upload/onchain_upload.py diff --git a/mcs/api/onchain_api.py b/mcs/api/onchain_api.py index 07882ae..e24fe0d 100644 --- a/mcs/api/onchain_api.py +++ b/mcs/api/onchain_api.py @@ -52,14 +52,12 @@ def pay(self, source_file_upload_id, file_size, amount=''): contract_amount = int(amount * (10 ** decimals)) hash = self._approve_usdc(int(contract_amount * float(self.params['pay_multiply_factor']))) - print(hash) - receipt = '' while not receipt: receipt = self.w3.eth.get_transaction_receipt(hash) - nonce = self.w3.eth.getTransactionCount(self.account.address) + nonce = self.w3.eth.get_transaction_count(self.account.address) decimals = self.token_contract.functions.decimals().call() lock_obj = { 'id': payment_info.w_cid, @@ -71,12 +69,12 @@ def pay(self, source_file_upload_id, file_size, amount=''): 'copyLimit': 5, } - tx = self.payment_contract.functions.lockTokenPayment(lock_obj).buildTransaction({ + tx = self.payment_contract.functions.lockTokenPayment(lock_obj).build_transaction({ 'from': self.account.address, 'nonce': nonce }) - signed_tx = self.w3.eth.account.signTransaction(tx, self.account._private_key) - tx_hash = self.w3.eth.sendRawTransaction(signed_tx.rawTransaction) + signed_tx = self.w3.eth.account.sign_transaction(tx, self.account._private_key) + tx_hash = self.w3.eth.send_raw_transaction(signed_tx.rawTransaction) self.w3.eth.wait_for_transaction_receipt(tx_hash, timeout=CONTRACT_TIME_OUT) return self.w3.toHex(tx_hash) @@ -87,40 +85,54 @@ def mint(self, source_file_upload_id, nft, collection_address = '', quantity = 1 metadata = self._upload_nft_metadata(nft) # print(metadata) - nonce = self.w3.eth.getTransactionCount(self.account.address) + nonce = self.w3.eth.get_transaction_count(self.account.address) option_obj = { 'from': self.account.address, 'nonce': nonce } - tx = self.mint_contract.functions.mint(collection_address, self.account.address, quantity, str(metadata["data"]["ipfs_url"])).buildTransaction(option_obj) - signed_tx = self.w3.eth.account.signTransaction(tx, self.account._private_key) - tx_hash = self.w3.eth.sendRawTransaction(signed_tx.rawTransaction) + tx = self.mint_contract.functions.mint(collection_address, self.account.address, quantity, str(metadata["data"]["ipfs_url"])).build_transaction(option_obj) + signed_tx = self.w3.eth.account.sign_transaction(tx, self.account._private_key) + tx_hash = self.w3.eth.send_raw_transaction(signed_tx.rawTransaction) receipt = self.w3.eth.wait_for_transaction_receipt(tx_hash, timeout=CONTRACT_TIME_OUT) result = self.mint_contract.events.TransferSingle().processReceipt(receipt, errors=DISCARD) id = result[0]['args']['id'] token_id = int(id) - self._post_mint_info(source_file_upload_id, self.w3.toHex(tx_hash), token_id, self.mint_contract.address) + self._post_mint_info(source_file_upload_id, self.w3.toHex(tx_hash), token_id, self.mint_contract.address, nft.get("name", ""), nft.get("description", "")) - return self.w3.toHex(tx_hash), token_id + return {"hash": self.w3.toHex(tx_hash), "tx_hash": self.w3.toHex(tx_hash), "token_id": token_id, "id": token_id } - def create_collection(self, collection_metadata): + def create_collection(self, collection_name, collection_metadata): metadata = self._upload_nft_metadata(collection_metadata) - # print(metadata) - nonce = self.w3.eth.getTransactionCount(self.account.address) + nonce = self.w3.eth.get_transaction_count(self.account.address) option_obj = { 'from': self.account.address, 'nonce': nonce } - tx = self.mint_contract.functions.createCollection(str(metadata["data"]["ipfs_url"])).buildTransaction(option_obj) - signed_tx = self.w3.eth.account.signTransaction(tx, self.account._private_key) - tx_hash = self.w3.eth.sendRawTransaction(signed_tx.rawTransaction) + tx = self.mint_contract.functions.createCollection(collection_name, str(metadata["data"]["ipfs_url"])).build_transaction(option_obj) + signed_tx = self.w3.eth.account.sign_transaction(tx, self.account._private_key) + tx_hash = self.w3.eth.send_raw_transaction(signed_tx.rawTransaction) receipt = self.w3.eth.wait_for_transaction_receipt(tx_hash, timeout=CONTRACT_TIME_OUT) result = self.mint_contract.events.CreateCollection().processReceipt(receipt, errors=DISCARD) collection_address = result[0]['args']['collectionAddress'] - return self.w3.toHex(tx_hash), collection_address + collection_info = collection_metadata + collection_info['address'] = collection_address + + result = self._post_collection_info(collection_info) + + return {"hash": self.w3.toHex(tx_hash), "tx_hash": self.w3.toHex(tx_hash), "address": collection_address, "collection_address": collection_address} + + def get_mint_info(self, source_file_upload_id): + params = {} + if source_file_upload_id: + params['source_file_upload_id'] = source_file_upload_id + mint_info = self.api_client._request_with_params(GET, MINT_INFO, self.MCS_API, params, self.token, None) + if not mint_info: + logging.error(f"\033[31mmint info for id {source_file_upload_id} not found \033[0m") + return + # return Payment(payment_data["data"]) def get_payment_info(self, source_file_upload_id): params = {} @@ -142,13 +154,26 @@ def get_user_tasks_deals(self, page_number=None, page_size=None, file_name=None, params['file_name'] = file_name if status: params['status'] = status - return self.api_client._request_with_params(GET, TASKS_DEALS, self.MCS_API, params, self.token, None) + deal_response = self.api_client._request_with_params(GET, TASKS_DEALS, self.MCS_API, params, self.token, None) + deals = deal_response["data"]["source_file_upload"] + + deal_list = [] - def _post_mint_info(self, source_file_upload_id, tx_hash, token_id, mint_address): + for deal_info in deals: + deal_list.append(SourceFile(deal_info)) + return deal_list + + def _post_mint_info(self, source_file_upload_id, tx_hash, token_id, mint_address, name, description): params = {'source_file_upload_id': source_file_upload_id, 'tx_hash': tx_hash, - 'token_id': int(token_id), 'mint_address': mint_address} + 'token_id': int(token_id), 'mint_address': mint_address, + 'name': name, 'description': description} return self.api_client._request_with_params(POST, MINT_INFO, self.MCS_API, params, self.token, None) + def _post_collection_info(self, collection_info): + collection_info['seller_fee'] = collection_info.get('seller_fee', 0) + return self.api_client._request_with_params(POST, COLLECTION, self.MCS_API, collection_info, self.token, None) + + def stream_upload_file(self, file_path): params = {} params['duration'] = '525' @@ -183,13 +208,13 @@ def _upload_nft_metadata(self, nft): # return Upload(data) def _approve_usdc(self, amount): - nonce = self.w3.eth.getTransactionCount(self.account.address) - tx = self.token_contract.functions.approve(self.payment_contract.address, amount).buildTransaction({ + nonce = self.w3.eth.get_transaction_count(self.account.address) + tx = self.token_contract.functions.approve(self.payment_contract.address, amount).build_transaction({ 'from': self.account.address, 'nonce': nonce }) - signed_tx = self.w3.eth.account.signTransaction(tx, self.account._private_key) - tx_hash = self.w3.eth.sendRawTransaction(signed_tx.rawTransaction) + signed_tx = self.w3.eth.account.sign_transaction(tx, self.account._private_key) + tx_hash = self.w3.eth.send_raw_transaction(signed_tx.rawTransaction) self.w3.eth.wait_for_transaction_receipt(tx_hash, timeout=CONTRACT_TIME_OUT) return self.w3.toHex(tx_hash) diff --git a/mcs/common/constants.py b/mcs/common/constants.py index e781a25..c8a20ad 100644 --- a/mcs/common/constants.py +++ b/mcs/common/constants.py @@ -19,6 +19,7 @@ GENERATE_APIKEY = "/api/v1/user/generate_api_key" APIKEY_LOGIN = "/api/v1/user/login_by_api_key" COLLECTIONS = "/api/v1/storage/mint/nft_collections" +COLLECTION = "/api/v1/storage/mint/nft_collection" # bucket api CREATE_BUCKET = "/api/v2/bucket/create" BUCKET_LIST = "/api/v2/bucket/get_bucket_list" diff --git a/mcs/contract/abi/CollectionFactory.json b/mcs/contract/abi/CollectionFactory.json index b27aac6..9322f60 100644 --- a/mcs/contract/abi/CollectionFactory.json +++ b/mcs/contract/abi/CollectionFactory.json @@ -63,6 +63,11 @@ }, { "inputs": [ + { + "internalType": "string", + "name": "collectionName", + "type": "string" + }, { "internalType": "string", "name": "contractURI", @@ -142,6 +147,11 @@ }, { "inputs": [ + { + "internalType": "string", + "name": "collectionName", + "type": "string" + }, { "internalType": "string", "name": "contractURI", diff --git a/mcs/object/onchain_storage.py b/mcs/object/onchain_storage.py index 88afc91..7340b0d 100644 --- a/mcs/object/onchain_storage.py +++ b/mcs/object/onchain_storage.py @@ -20,8 +20,8 @@ def to_json(self): class Deal: def __init__(self, deal_data): - self.deal_id = deal_data["deal_id"] - self.message_cid = deal_data["message_cid"] + self.deal_id = deal_data.get("deal_id", None) + self.message_cid = deal_data.get("message_cid", None) self.deal_cid = deal_data["deal_cid"] self.height = deal_data["height"] self.piece_cid = deal_data["piece_cid"] @@ -54,11 +54,42 @@ def to_json(self): return json.dumps(self, default=lambda o: o.__dict__, sort_keys=True, indent=4) +class SourceFile: + def __init__(self, file_data): + self.source_file_upload_id = file_data["source_file_upload_id"] + self.file_name = file_data["file_name"] + self.file_size = file_data["file_size"] + self.upload_at = file_data["upload_at"] + self.duration = file_data["duration"] + self.ipfs_url = file_data["ipfs_url"] + self.pin_status = file_data["pin_status"] + self.pay_amount = file_data["pay_amount"] + self.status = file_data["status"] + self.note = file_data["note"] + self.is_free = file_data["is_free"] + self.is_minted = file_data["is_minted"] + self.refunded_by_self = file_data["refunded_by_self"] + self.offline_deal = file_data["offline_deal"] + + def to_json(self): + return json.dumps(self, default=lambda o: o.__dict__, + sort_keys=True, indent=4) + class Collection: def __init__(self, collection_data): self.id = collection_data["id"] self.address = collection_data["address"] + + self.name = collection_data["name"] + self.description = collection_data["description"] + self.image_url = collection_data["image_url"] + self.external_link = collection_data["external_link"] + self.seller_fee = collection_data["seller_fee"] self.wallet_id = collection_data["wallet_id"] + self.wallet_id_recipient = collection_data["wallet_id_recipient"] + self.wallet_recipient = collection_data["wallet_recipient"] + self.is_default = collection_data["is_default"] + self.tx_hash = collection_data["tx_hash"] self.create_at = collection_data["create_at"] self.update_at = collection_data["update_at"] diff --git a/mcs/upload/__init__.py b/mcs/upload/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/mcs/upload/onchain_upload.py b/mcs/upload/onchain_upload.py deleted file mode 100644 index d1f62df..0000000 --- a/mcs/upload/onchain_upload.py +++ /dev/null @@ -1,68 +0,0 @@ -from mcs import APIClient -from mcs.contract import ContractClient -from mcs.common.utils import get_amount -from mcs.api import OnchainAPI -import logging -from web3 import Web3 - - -class OnchainUpload(): - def __init__(self, chain_name, private_key, rpc_endpoint, api_key, access_token, file_path): - self.chain_name = chain_name - self.private_key = private_key - self.rpc_endpoint = rpc_endpoint - self.api_key = api_key - self.access_token = access_token - self.wallet_address = Web3(Web3.HTTPProvider(self.rpc_endpoint)) \ - .eth.account.privateKeyToAccount(self.private_key).address - self.file_path = file_path - self.api = APIClient(self.api_key, self.access_token, self.chain_name) - self.onchain = OnchainAPI(self.api) - self.w3_api = ContractClient(self.rpc_endpoint, self.chain_name) - - def approve_token(self, amount): - return self.w3_api.approve_usdc(self.wallet_address, self.private_key, amount) - - def simple_upload(self, amount): - self.approve_token(amount) - self.stream_upload() - payment_hash = self.pay() - return payment_hash - - def stream_upload(self): - upload_file = self.onchain.stream_upload_file(self.wallet_address, self.file_path) - file_data = upload_file["data"] - self.upload_response = file_data - - def estimate_amount(self): - file_size = self.upload_response['file_size'] - rate = self.api.get_price_rate()["data"] - amount = get_amount(file_size, rate) - return amount - - def pay(self): - file_size, w_cid = self.upload_response['file_size'], self.upload_response['w_cid'] - params = self.api.get_params()["data"] - rate = self.api.get_price_rate()["data"] - # payment - try: - self.payment_tx_hash = self.w3_api.upload_file_pay(self.wallet_address, self.private_key, - file_size, w_cid, rate, params) - except Exception as e: - logging.error(str(e)) - return 'payment failed: ' + str(e) - - return self.payment_tx_hash - - def mint(self, file_name): - file_data = self.upload_response - source_file_upload_id, nft_uri, file_size = file_data['source_file_upload_id'], file_data['ipfs_url'], \ - file_data['file_size'] - meta_url = \ - self.onchain.upload_nft_metadata(self.wallet_address, file_name, nft_uri, self.payment_tx_hash, file_size)[ - 'data'][ - 'ipfs_url'] - tx_hash, token_id = self.w3_api.mint_nft(self.wallet_address, self.private_key, meta_url) - response = self.onchain.get_mint_info(source_file_upload_id, None, - tx_hash, token_id, self.api.get_params()["data"]['mint_contract_address']) - return tx_hash, token_id, response diff --git a/test/test_bucket_api.py b/test/test_bucket_api.py index ea09fcd..5d85d5c 100644 --- a/test/test_bucket_api.py +++ b/test/test_bucket_api.py @@ -5,84 +5,77 @@ from mcs import BucketAPI, APIClient import time -chain_name = "polygon.mumbai" - - -def test_info(): +def login(): load_dotenv(".env_test") - wallet_info = { - 'api_key': os.getenv('api_key'), - 'access_token': os.getenv('access_token') - } - return wallet_info - - -def test_user_register(): - info = test_info() - api = BucketAPI(APIClient(info['api_key'], info['access_token'], chain_name)) - print(api.token) + api_key = os.getenv('api_key') + access_token = os.getenv('access_token') + chain_name = os.getenv("chain_name") + api = BucketAPI(APIClient(api_key, access_token, chain_name)) + + assert api + return api +def test_delete_bucket(): + api = login() + print(api.delete_bucket('test-bucket')) def test_list_buckets(): - info = test_info() - api = BucketAPI(APIClient(info['api_key'], info['access_token'], chain_name)) - for i in api.list_buckets(): - print(i.to_json()) - + api = login() + assert api.list_buckets() is not None def test_create_bucket(): - info = test_info() - api = BucketAPI(APIClient(info['api_key'], info['access_token'], chain_name)) - print(api.create_bucket('33333')) - - -def test_delete_bucket(): - info = test_info() - api = BucketAPI(APIClient(info['api_key'], info['access_token'], chain_name)) - print(api.delete_bucket('33333')) - + api = login() + create = api.create_bucket('test-bucket') + assert create == True def test_get_bucket(): - info = test_info() - api = BucketAPI(APIClient(info['api_key'], info['access_token'], chain_name)) - print(api.get_bucket('123121')) + api = login() + bucket = api.get_bucket('test-bucket') + assert bucket.bucket_name == 'test-bucket' def test_create_folder(): - info = test_info() - api = BucketAPI(APIClient(info['api_key'], info['access_token'], chain_name)) - print(api.create_folder('12312', '55555', '44444')) - + api = login() + create = api.create_folder('test-bucket', 'folder1') -def test_delete_file(): - info = test_info() - api = BucketAPI(APIClient(info['api_key'], info['access_token'], chain_name)) - print(api.delete_file('12312', '44444/55555/log_mcs.png')) + assert create == True +# def test_create_folder_with_same_name(): +# api = login() +# create = api.create_folder('test-bucket', 'folder1') +# print(create) def test_upload_file(): - info = test_info() - api = BucketAPI(APIClient(info['api_key'], info['access_token'], chain_name)) + api = login() filepath = "/images/log_mcs.png" parentpath = os.path.abspath(os.path.dirname(__file__)) - print(api.upload_file('12312', "44444/55555/log_mcs.png", parentpath + filepath).to_json()) - + file = api.upload_file('test-bucket', "folder1/mcs-logo.png", parentpath + filepath) + assert file.name == "mcs-logo.png" def test_get_file(): - info = test_info() - api = BucketAPI(APIClient(info['api_key'], info['access_token'], chain_name)) - print(api.get_file('12312', '44444/55555/log_mcs.png').to_json()) + api = login() + file = api.get_file('test-bucket', 'folder1/mcs-logo.png') + + assert file.name == "mcs-logo.png" def test_get_file_list(): - info = test_info() - api = BucketAPI(APIClient(info['api_key'], info['access_token'], chain_name)) - for i in api.list_files(12312, '44444/55555', 100, '0'): - print(i.to_json()) + api = login() + list = api.list_files('test-bucket', 'folder1') + + assert len(list) == 1 + assert list[0].name == 'mcs-logo.png' def test_download_file(): - info = test_info() - api = BucketAPI(APIClient(info['api_key'], info['access_token'], chain_name)) - result = api.download_file('12312', '44444/55555/log_mcs.png', "aaaa.png") - print(result) + api = login() + result = api.download_file('test-bucket', 'folder1/mcs-logo.png', "aaaa.png") + + assert result == True + + +def test_delete_file(): + api = login() + delete = api.delete_file('test-bucket', 'folder1/mcs-logo.png') + + assert delete == True diff --git a/test/test_onchain_api.py b/test/test_onchain_api.py index e51a6fe..e8b6e27 100644 --- a/test/test_onchain_api.py +++ b/test/test_onchain_api.py @@ -4,36 +4,62 @@ from mcs.common.params import Params from mcs import OnchainAPI, APIClient -chain_name = 'polygon.mumbai' -load_dotenv('.env_test') -api_key = os.getenv('api_key') -access_token = os.getenv('access_token') -@pytest.mark.asyncio -async def test_get_params(): - mcs_api = APIClient(api_key, access_token, chain_name) - print(mcs_api.get_params()) +def login(): + load_dotenv(".env_test") + api_key = os.getenv('api_key') + access_token = os.getenv('access_token') + chain_name = os.getenv("chain_name") + private_key = os.getenv("private_key") + rpc_endpoint = os.getenv("rpc_endpoint") -@pytest.mark.asyncio -async def test_user_register(): - mcs_api = APIClient(api_key, access_token, chain_name) - print(mcs_api.token) + api = OnchainAPI(APIClient(api_key, access_token, chain_name), private_key, rpc_endpoint) + # print(api.token) + assert api + return api -@pytest.mark.asyncio -async def test_get_price_rate(): - mcs_api = APIClient(api_key, access_token, chain_name) - print(mcs_api.get_price_rate()) +def test_upload_file(): + api = login() + filepath = "/images/log_mcs.png" + parentpath = os.path.abspath(os.path.dirname(__file__)) + file = api.upload(parentpath + filepath) + pytest.file = file + assert file -@pytest.mark.asyncio -async def test_upload_file(): - filepath = "/images/log_mcs.png" - parent_path = os.path.abspath(os.path.dirname(__file__)) +def test_pay_file(): + api = login() + payment = api.pay(pytest.file.source_file_upload_id, pytest.file.file_size) + print(payment) + +def test_create_collection(): + api = login() + + num_collections = len(api.get_collections()) + collection = api.create_collection('test-collection-' + str(num_collections), {"name": 'test-collection-'+str(num_collections)}) + pytest.collection_address = collection["address"] + + assert len(api.get_collections()) == num_collections + 1 + +def test_mint(): + api = login() + + mint = api.mint(pytest.file.source_file_upload_id, {"name": 'test-nft', 'image': pytest.file.ipfs_url}, pytest.collection_address) + + assert mint["id"] == 1 + +def test_get_uploads(): + api = login() + deals = api.get_user_tasks_deals() - mcs_api = APIClient(api_key, access_token, chain_name) - onchain_api = OnchainAPI(mcs_api) - print(onchain_api.upload_file(parent_path + filepath)) + file_ids = [deal.source_file_upload_id for deal in deals] + + assert pytest.file.source_file_upload_id in file_ids +def test_get_deal_detail(): + api = login() + detail = api.get_deal_detail(pytest.file.source_file_upload_id) + assert detail From 17c5542b3c23c3d8abe53981a8d6f90c011939e8 Mon Sep 17 00:00:00 2001 From: rykci Date: Thu, 23 Feb 2023 12:27:24 -0500 Subject: [PATCH 12/25] fix post mint info --- mcs/api/onchain_api.py | 20 ++++-- test/test_onchain_upload.py | 133 ------------------------------------ test/test_simple_upload.py | 19 ------ 3 files changed, 16 insertions(+), 156 deletions(-) delete mode 100644 test/test_onchain_upload.py delete mode 100644 test/test_simple_upload.py diff --git a/mcs/api/onchain_api.py b/mcs/api/onchain_api.py index e24fe0d..efd0a71 100644 --- a/mcs/api/onchain_api.py +++ b/mcs/api/onchain_api.py @@ -98,10 +98,22 @@ def mint(self, source_file_upload_id, nft, collection_address = '', quantity = 1 id = result[0]['args']['id'] token_id = int(id) - self._post_mint_info(source_file_upload_id, self.w3.toHex(tx_hash), token_id, self.mint_contract.address, nft.get("name", ""), nft.get("description", "")) + collection_id = self._get_collection_id(collection_address) + + self._post_mint_info(source_file_upload_id, self.w3.toHex(tx_hash), token_id, collection_address, collection_id, nft.get("name", ""), nft.get("description", "")) return {"hash": self.w3.toHex(tx_hash), "tx_hash": self.w3.toHex(tx_hash), "token_id": token_id, "id": token_id } + def _get_collection_id(self, collection_address): + collections = self.get_collections() + result = [collection.id for collection in collections if collection.address.lower() == collection_address] + if len(result) == 0: + logging.error(f"\033[31mCollection address {collection_address} not found \033[0m") + return + else: + return result[0] + + def create_collection(self, collection_name, collection_metadata): metadata = self._upload_nft_metadata(collection_metadata) @@ -163,10 +175,10 @@ def get_user_tasks_deals(self, page_number=None, page_size=None, file_name=None, deal_list.append(SourceFile(deal_info)) return deal_list - def _post_mint_info(self, source_file_upload_id, tx_hash, token_id, mint_address, name, description): + def _post_mint_info(self, source_file_upload_id, tx_hash, token_id, collection_address, collection_id, name, description): params = {'source_file_upload_id': source_file_upload_id, 'tx_hash': tx_hash, - 'token_id': int(token_id), 'mint_address': mint_address, - 'name': name, 'description': description} + 'token_id': int(token_id), 'mint_address': collection_address, + 'nft_collection_id': collection_id, 'name': name, 'description': description} return self.api_client._request_with_params(POST, MINT_INFO, self.MCS_API, params, self.token, None) def _post_collection_info(self, collection_info): diff --git a/test/test_onchain_upload.py b/test/test_onchain_upload.py deleted file mode 100644 index 96facb4..0000000 --- a/test/test_onchain_upload.py +++ /dev/null @@ -1,133 +0,0 @@ -import os - -import web3 -from web3 import Web3 -from dotenv import load_dotenv -from mcs import APIClient, OnchainAPI -from mcs.common.params import Params -from mcs.contract import ContractClient -from mcs.common.utils import get_amount - -chain_name = "polygon.mumbai" - - -def test_info(): - load_dotenv(".env_test") - wallet_info = { - 'wallet_address': os.getenv('wallet_address'), - 'private_key': os.getenv('private_key'), - 'rpc_endpoint': os.getenv('rpc_endpoint'), - 'api_key': os.getenv('api_key'), - 'access_token': os.getenv('access_token') - } - return wallet_info - - -def test_approve_usdc(): - info = test_info() - wallet_address = info['wallet_address'] - private_key = info['private_key'] - rpc_endpoint = info['rpc_endpoint'] - w3_api = ContractClient(rpc_endpoint, chain_name) - w3_api.approve_usdc(wallet_address, private_key, 1) - - -def test_upload_file_pay(): - info = test_info() - wallet_address = info['wallet_address'] - private_key = info['private_key'] - rpc_endpoint = info['rpc_endpoint'] - api_key = info['api_key'] - access_token = info['access_token'] - - w3_api = ContractClient(rpc_endpoint, chain_name) - onchain_api = OnchainAPI(APIClient(api_key, access_token, chain_name)) - # upload file to mcs - filepath = "/images/log_mcs.png" - parent_path = os.path.abspath(os.path.dirname(__file__)) - upload_file = onchain_api.stream_upload_file(parent_path + filepath) - print(upload_file) - # test upload file - assert upload_file['status'] == 'success' - file_data = upload_file["data"] - payload_cid, source_file_upload_id, nft_uri, file_size, w_cid = file_data['payload_cid'], file_data[ - 'source_file_upload_id'], file_data['ipfs_url'], file_data['file_size'], file_data['w_cid'] - # get the global variable - params = onchain_api.api_client.get_params()["data"] - # test get params api - assert onchain_api.api_client.get_params()['status'] == 'success' - # get filcoin price - rate = onchain_api.api_client.get_price_rate()["data"] - # test get price rate api - assert onchain_api.api_client.get_price_rate()['status'] == 'success' - amount = get_amount(file_size, rate) - approve_amount = int(web3.Web3.toWei(amount, 'ether') * float(params['pay_multiply_factor'])) - w3_api.approve_usdc(wallet_address, private_key, approve_amount) - # test upload_file_pay contract - w3_api.upload_file_pay(wallet_address, private_key, file_size, w_cid, rate, params) - # test get payment info api - payment_info = onchain_api.get_payment_info(source_file_upload_id) - assert payment_info['status'] == 'success' - assert payment_info['data']['w_cid'] == w_cid - # test get deal detail - deal_detail = onchain_api.get_deal_detail(source_file_upload_id) - assert deal_detail['status'] == 'success' - assert deal_detail['data'] != None - - -def test_mint_nft(): - info = test_info() - wallet_address = info['wallet_address'] - private_key = info['private_key'] - rpc_endpoint = info['rpc_endpoint'] - api_key = info['api_key'] - access_token = info['access_token'] - - w3_api = ContractClient(rpc_endpoint, chain_name) - onchain_api = OnchainAPI(APIClient(api_key, access_token, chain_name)) - w3 = Web3(Web3.HTTPProvider(rpc_endpoint)) - - # upload file to mcs - filepath = "/images/log_mcs.png" - filename = "log_mcs.png" - parent_path = os.path.abspath(os.path.dirname(__file__)) - upload_file = onchain_api.stream_upload_file(parent_path + filepath) - # test upload file - assert upload_file['status'] == 'success' - file_data = upload_file["data"] - payload_cid, source_file_upload_id, nft_uri, file_size, w_cid = file_data['payload_cid'], file_data[ - 'source_file_upload_id'], file_data['ipfs_url'], file_data['file_size'], file_data['w_cid'] - # get the global variable - params = onchain_api.api_client.get_params()["data"] - # test get params api - assert onchain_api.api_client.get_params()['status'] == 'success' - # get filcoin price - rate = onchain_api.api_client.get_price_rate()["data"] - # test get price rate api - assert onchain_api.api_client.get_price_rate()['status'] == 'success' - amount = get_amount(file_size, rate) - approve_amount = int(w3.toWei(amount, 'ether') * float(params['pay_multiply_factor'])) - w3_api.approve_usdc(wallet_address, private_key, approve_amount) - # test upload_file_pay contract - tx_hash = w3_api.upload_file_pay(wallet_address, private_key, file_size, w_cid, rate, params) - print(tx_hash) - # upload nft metadata - nft_metadata = onchain_api.upload_nft_metadata(wallet_address, filename, nft_uri, tx_hash, file_size) - # test upload nft metadata - assert nft_metadata['status'] == 'success' - meta_url = nft_metadata['data']['ipfs_url'] - print(meta_url) - # test mint nft contract - tx_hash, token_id = w3_api.mint_nft(wallet_address, - private_key, meta_url) - print(tx_hash) - - # update mint info - mint_address = params['mint_contract_address'] - mint_info = onchain_api.get_mint_info(source_file_upload_id, None, tx_hash, token_id, mint_address) - # test update mint info - assert mint_info['status'] == 'success' - assert mint_info['data']['source_file_upload_id'] == source_file_upload_id - assert mint_info['data']['nft_tx_hash'] == tx_hash - assert mint_info['data']['token_id'] == int(token_id) - assert mint_info['data']['mint_address'] == mint_address diff --git a/test/test_simple_upload.py b/test/test_simple_upload.py deleted file mode 100644 index 84e4be5..0000000 --- a/test/test_simple_upload.py +++ /dev/null @@ -1,19 +0,0 @@ -import os -from dotenv import load_dotenv -from mcs.upload.onchain_upload import OnchainUpload - -chain_name = "polygon.mumbai" - -def test_auto_upload(): - load_dotenv(".env_test") - private_key = os.getenv('private_key') - rpc_endpoint = os.getenv('rpc_endpoint') - api_key = os.getenv('api_key') - access_token = os.getenv('access_token') - - filepath = "/images/log_mcs.png" - parent_path = os.path.abspath(os.path.dirname(__file__)) - - up = OnchainUpload(chain_name, private_key, rpc_endpoint, api_key, access_token, parent_path+filepath) - hash = up.simple_upload(1) - return hash \ No newline at end of file From 560b29a53d7b9e30f76bce625f8354013682762a Mon Sep 17 00:00:00 2001 From: rykci Date: Thu, 23 Feb 2023 15:39:07 -0500 Subject: [PATCH 13/25] bugfix: post create collection --- mcs/api/onchain_api.py | 1 + 1 file changed, 1 insertion(+) diff --git a/mcs/api/onchain_api.py b/mcs/api/onchain_api.py index efd0a71..eb43531 100644 --- a/mcs/api/onchain_api.py +++ b/mcs/api/onchain_api.py @@ -131,6 +131,7 @@ def create_collection(self, collection_name, collection_metadata): collection_info = collection_metadata collection_info['address'] = collection_address + collection_info['tx_hash'] = self.w3.toHex(tx_hash) result = self._post_collection_info(collection_info) From 3f68995b9e17383c962b52edac9e8fca636ca54b Mon Sep 17 00:00:00 2001 From: rykci Date: Fri, 24 Feb 2023 16:37:35 -0500 Subject: [PATCH 14/25] file sub --- mcs/api/bucket_api.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/mcs/api/bucket_api.py b/mcs/api/bucket_api.py index 2840192..9642b67 100644 --- a/mcs/api/bucket_api.py +++ b/mcs/api/bucket_api.py @@ -149,9 +149,9 @@ def list_files(self, bucket_name, prefix='', limit='10', offset="0"): def upload_file(self, bucket_name, object_name, file_path, replace=False): prefix, file_name = object_to_filename(object_name) bucket_id = self._get_bucket_id(bucket_name) - if os.stat(file_path).st_size == 0: - logging.error("\033[31mFile size cannot be 0\033[0m") - return None + # if os.stat(file_path).st_size == 0: + # logging.error("\033[31mFile size cannot be 0\033[0m") + # return None file_size = os.stat(file_path).st_size with open(file_path, 'rb') as file: file_hash = md5(file.read()).hexdigest() @@ -160,7 +160,7 @@ def upload_file(self, bucket_name, object_name, file_path, replace=False): logging.error("\033[31mCan't find this bucket\033[0m") return # Replace file if already existed - if result[['data']['file_is_exist']] and replace: + if result['data']['file_is_exist'] and replace: self.delete_file(bucket_name, object_name) result = self._check_file(bucket_id, file_hash, file_name, prefix) if not (result['data']['file_is_exist']): From f7f552404ffed3282f4976f071fc02ae76ec0bc4 Mon Sep 17 00:00:00 2001 From: rykci Date: Fri, 24 Feb 2023 16:52:37 -0500 Subject: [PATCH 15/25] download 0 byte file --- mcs/api/bucket_api.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/mcs/api/bucket_api.py b/mcs/api/bucket_api.py index 9642b67..d68d132 100644 --- a/mcs/api/bucket_api.py +++ b/mcs/api/bucket_api.py @@ -213,8 +213,9 @@ def download_file(self, bucket_name, object_name, local_filename): if file is not None: ipfs_url = file.ipfs_url with open(local_filename, 'wb') as f: - data = urllib.request.urlopen(ipfs_url) - f.write(data.read()) + if file.size > 0: + data = urllib.request.urlopen(ipfs_url) + f.write(data.read()) logging.info("\033[32mFile download successfully\033[0m") return True logging.error('\033[31mFile does not exist\033[0m') From 3a1d48cfe0b2238555998aff0110cd8b8a7d494c Mon Sep 17 00:00:00 2001 From: rykci Date: Fri, 24 Feb 2023 17:03:27 -0500 Subject: [PATCH 16/25] support 0 byte upload and download --- mcs/api/bucket_api.py | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/mcs/api/bucket_api.py b/mcs/api/bucket_api.py index e6843c9..f4c70fd 100644 --- a/mcs/api/bucket_api.py +++ b/mcs/api/bucket_api.py @@ -128,9 +128,6 @@ def list_files(self, bucket_name, prefix='', limit='10', offset="0"): def upload_file(self, bucket_name, object_name, file_path): prefix, file_name = object_to_filename(object_name) bucket_id = self._get_bucket_id(bucket_name) - if os.stat(file_path).st_size == 0: - print("\033[31mError:File size cannot be 0\033[0m") - return None file_size = os.stat(file_path).st_size with open(file_path, 'rb') as file: file_hash = md5(file.read()).hexdigest() @@ -184,8 +181,9 @@ def download_file(self, bucket_name, object_name, local_filename): if file is not None: ipfs_url = file.ipfs_url with open(local_filename, 'wb') as f: - data = urllib.request.urlopen(ipfs_url) - f.write(data.read()) + if file.size > 0: + data = urllib.request.urlopen(ipfs_url) + f.write(data.read()) print("\033[32mFile download successfully\033[0m") return True print('\033[31mError: File does not exist\033[0m') From d3a70b3bee525bf8323876ff8eb3fdc6ec5b3d8e Mon Sep 17 00:00:00 2001 From: rykci Date: Tue, 7 Mar 2023 15:58:14 -0500 Subject: [PATCH 17/25] after upload, build the object for UI --- mcs/api/bucket_api.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/mcs/api/bucket_api.py b/mcs/api/bucket_api.py index d68d132..a33a8ef 100644 --- a/mcs/api/bucket_api.py +++ b/mcs/api/bucket_api.py @@ -183,10 +183,19 @@ def upload_file(self, bucket_name, object_name, file_path, replace=False): result = self._merge_file(bucket_id, file_hash, file_name, prefix) file_id = result['data']['file_id'] file_info = self._get_file_info(file_id) + self._create_folders(bucket_name, prefix) logging.info("\033[32mFile upload successfully\033[0m") return file_info logging.error("\033[31mFile already exists\033[0m") return None + + def _create_folders(self, bucket_name, path): + bucket_id = self._get_bucket_id(bucket_name) + path, folder_name = object_to_filename(path) + while folder_name: + params = {"file_name": folder_name, "prefix": path, "bucket_uid": bucket_id} + self.api_client._request_with_params(POST, CREATE_FOLDER, self.MCS_API, params, self.token, None) + path, folder_name = object_to_filename(path) def _upload_to_bucket(self, bucket_name, file_path, prefix=''): if os.path.isdir(file_path): From 93525287690b4348ff45baaf23699e0b6d920f51 Mon Sep 17 00:00:00 2001 From: rykci Date: Tue, 7 Mar 2023 16:00:24 -0500 Subject: [PATCH 18/25] upload ipfs folder and custom gateway --- mcs/api/bucket_api.py | 56 ++++++++++++++++++++++++++++++++---- mcs/common/constants.py | 4 ++- mcs/object/bucket_storage.py | 7 +++-- 3 files changed, 59 insertions(+), 8 deletions(-) diff --git a/mcs/api/bucket_api.py b/mcs/api/bucket_api.py index d68d132..9983d01 100644 --- a/mcs/api/bucket_api.py +++ b/mcs/api/bucket_api.py @@ -6,6 +6,8 @@ import os, threading import urllib.request import logging +import glob +import shutil from mcs.common.utils import object_to_filename from mcs.object.bucket_storage import Bucket, File @@ -18,6 +20,7 @@ def __init__(self, api_client=None): self.api_client = api_client self.MCS_API = api_client.MCS_API self.token = self.api_client.token + self.gateway = self.get_gateway()[0] def list_buckets(self): try: @@ -84,9 +87,9 @@ def get_file(self, bucket_name, object_name): params = {"bucket_uid": bucket_id, "object_name": object_name} result = self.api_client._request_with_params(GET, GET_FILE, self.MCS_API, params, self.token, None) - + if result: - return File(result['data']) + return File(result['data'], self.gateway) except: print('error') return @@ -138,7 +141,7 @@ def list_files(self, bucket_name, prefix='', limit='10', offset="0"): files = result['data']['file_list'] file_list = [] for file in files: - file_info: File = File(file) + file_info: File = File(file, self.gateway) file_list.append(file_info) return file_list else: @@ -206,6 +209,24 @@ def upload_folder(self, bucket_name, folder_path, prefix=''): res.append(upload) return res + + def upload_ipfs_folder(self, bucket_name, object_name, folder_path): + folder_name = os.path.basename(object_name) or os.path.basename(folder_path) + prefix = os.path.normpath(os.path.dirname(object_name)) if os.path.dirname(object_name) else '' + bucket_uid = self._get_bucket_id(bucket_name) + files = self._read_files(folder_path) + print(files) + + form_data = {"folder_name": folder_name, "prefix": prefix, "bucket_uid": bucket_uid} + print(form_data) + + res = self.api_client._request_with_params(POST, PIN_IPFS, self.MCS_API, form_data, self.token, files) + + if res: + folder = (File(res["data"], self.gateway)) + return folder + else: + logging.error("\033[31mIPFS Folder Upload Error\033[0m") def download_file(self, bucket_name, object_name, local_filename): @@ -264,12 +285,37 @@ def _get_full_file_list(self, bucket_name, prefix=''): self.api_client._request_with_params(GET, FILE_LIST, self.MCS_API, params, self.token, None)['data'][ 'file_list'] for file in result: - file_info: File = File(file) + file_info: File = File(file, self.gateway) file_list.append(file_info) return file_list def _get_file_info(self, file_id): params = {'file_id': file_id} result = self.api_client._request_with_params(GET, FILE_INFO, self.MCS_API, params, self.token, None) - file_info = File(result['data']) + file_info = File(result['data'], self.gateway) return file_info + + def get_gateway(self): + result = self.api_client._request_without_params(GET, GET_GATEWAY, self.MCS_API, self.token) + return result['data'] + + def _read_files(self, root_folder): + # Create an empty list to store the file tuples + file_dict = [] + + # Use glob to retrieve the file paths in the directory and its subdirectories + file_paths = glob.glob(os.path.join(root_folder, '**', '*'), recursive=True) + + # Loop through each file path and read the contents of the file + for file_path in file_paths: + if os.path.isfile(file_path): + # Get the relative path from the root folder + rel_path = os.path.relpath(file_path, root_folder) + + # Use the relative path as the file name + filename = os.path.normpath(rel_path).replace(os.sep, '/') + + # Read the contents of the file in binary mode + file_dict.append(('files', open(file_path, 'rb'))) + + return file_dict \ No newline at end of file diff --git a/mcs/common/constants.py b/mcs/common/constants.py index c8a20ad..9e6aea2 100644 --- a/mcs/common/constants.py +++ b/mcs/common/constants.py @@ -1,5 +1,5 @@ MCS_POLYGON_MAIN_API = "https://api.multichain.storage" -MCS_POLYGON_MUMBAI_API = "https://calibration-mcs-api.filswan.com" +MCS_POLYGON_MUMBAI_API = "http://192.168.88.41:8889" MCS_BSC_API = 'https://calibration-mcs-bsc.filswan.com' GET = "GET" POST = "POST" @@ -32,6 +32,8 @@ MERGE_FILE = "/api/v2/oss_file/merge" FILE_LIST = "/api/v2/oss_file/get_file_list" GET_FILE = "/api/v2/oss_file/get_file_by_object_name" +GET_GATEWAY = "/api/v2/gateway/get_gateway" +PIN_IPFS = "/api/v2/oss_file/pin_files_to_ipfs" # contract USDC_ABI = "ERC20.json" SWAN_PAYMENT_ABI = "SwanPayment.json" diff --git a/mcs/object/bucket_storage.py b/mcs/object/bucket_storage.py index 582f960..135ad87 100644 --- a/mcs/object/bucket_storage.py +++ b/mcs/object/bucket_storage.py @@ -22,7 +22,7 @@ def to_json(self): class File: - def __init__(self, file_data): + def __init__(self, file_data, gateway=''): self.name = file_data["name"] self.address = file_data["address"] self.bucket_uid = file_data["bucket_uid"] @@ -30,7 +30,7 @@ def __init__(self, file_data): self.prefix = file_data["prefix"] self.size = file_data["size"] self.payloadCid = file_data["payload_cid"] - self.ipfs_url = file_data["ipfs_url"] + self.ipfs_url = gateway + '/ipfs/' + file_data["payload_cid"] self.pin_status = file_data["pin_status"] self.is_deleted = file_data["is_deleted"] self.is_folder = file_data["is_folder"] @@ -39,6 +39,9 @@ def __init__(self, file_data): self.created_at = file_data["created_at"] self.deleted_at = file_data["deleted_at"] + self.object_name = file_data["object_name"] + self.type = file_data["type"] + def to_json(self): return json.dumps(self, default=lambda o: o.__dict__, sort_keys=True, indent=4) From 50ad4149e630d965fd924b500437d7f872e5fb31 Mon Sep 17 00:00:00 2001 From: rykci Date: Wed, 8 Mar 2023 10:52:13 -0500 Subject: [PATCH 19/25] post tx hash --- mcs/api/onchain_api.py | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/mcs/api/onchain_api.py b/mcs/api/onchain_api.py index eb43531..90f253a 100644 --- a/mcs/api/onchain_api.py +++ b/mcs/api/onchain_api.py @@ -114,7 +114,8 @@ def _get_collection_id(self, collection_address): return result[0] - def create_collection(self, collection_name, collection_metadata): + def create_collection(self, collection_metadata): + collection_name = collection_metadata["name"] metadata = self._upload_nft_metadata(collection_metadata) nonce = self.w3.eth.get_transaction_count(self.account.address) @@ -125,17 +126,18 @@ def create_collection(self, collection_name, collection_metadata): tx = self.mint_contract.functions.createCollection(collection_name, str(metadata["data"]["ipfs_url"])).build_transaction(option_obj) signed_tx = self.w3.eth.account.sign_transaction(tx, self.account._private_key) tx_hash = self.w3.eth.send_raw_transaction(signed_tx.rawTransaction) - receipt = self.w3.eth.wait_for_transaction_receipt(tx_hash, timeout=CONTRACT_TIME_OUT) - result = self.mint_contract.events.CreateCollection().processReceipt(receipt, errors=DISCARD) - collection_address = result[0]['args']['collectionAddress'] + # receipt = self.w3.eth.wait_for_transaction_receipt(tx_hash, timeout=CONTRACT_TIME_OUT) + # result = self.mint_contract.events.CreateCollection().processReceipt(receipt, errors=DISCARD) + # collection_address = result[0]['args']['collectionAddress'] collection_info = collection_metadata - collection_info['address'] = collection_address + # collection_info['address'] = collection_address collection_info['tx_hash'] = self.w3.toHex(tx_hash) result = self._post_collection_info(collection_info) - - return {"hash": self.w3.toHex(tx_hash), "tx_hash": self.w3.toHex(tx_hash), "address": collection_address, "collection_address": collection_address} + result["tx_hash"] = self.w3.toHex(tx_hash) + + return result def get_mint_info(self, source_file_upload_id): params = {} From 846501291f7cb479e1dae8c532c203a81631bbf4 Mon Sep 17 00:00:00 2001 From: daniel Date: Wed, 8 Mar 2023 12:22:21 -0500 Subject: [PATCH 20/25] fix upload --- mcs/api/bucket_api.py | 46 +++++++++++++++++-------------------------- 1 file changed, 18 insertions(+), 28 deletions(-) diff --git a/mcs/api/bucket_api.py b/mcs/api/bucket_api.py index 9983d01..7080efd 100644 --- a/mcs/api/bucket_api.py +++ b/mcs/api/bucket_api.py @@ -34,7 +34,6 @@ def list_buckets(self): except: logging.error("\033[31m" + 'error' + "\033[0m") return - def create_bucket(self, bucket_name): params = {'bucket_name': bucket_name} @@ -47,7 +46,7 @@ def create_bucket(self, bucket_name): logging.error("\033[31m" + result['message'] + "\033[0m") except: logging.error("\033[31mThis bucket already exists\033[0m") - + return False def delete_bucket(self, bucket_name): @@ -103,17 +102,17 @@ def create_folder(self, bucket_name, folder_name, prefix=''): logging.info("\033[31mFolder created successfully\033[0m") return True else: - logging.error("\033[31m" + result['message']+ "\033[0m") + logging.error("\033[31m" + result['message'] + "\033[0m") return False except: logging.error("\033[31mCan't create this folder") - return + return def delete_file(self, bucket_name, object_name): try: prefix, file_name = object_to_filename(object_name) file_list = self._get_full_file_list(bucket_name, prefix) - + file_id = '' for file in file_list: if file.name == file_name: @@ -148,7 +147,6 @@ def list_files(self, bucket_name, prefix='', limit='10', offset="0"): logging.error("\033[31m" + result['message'] + "\033[0m") return False - def upload_file(self, bucket_name, object_name, file_path, replace=False): prefix, file_name = object_to_filename(object_name) bucket_id = self._get_bucket_id(bucket_name) @@ -196,7 +194,7 @@ def _upload_to_bucket(self, bucket_name, file_path, prefix=''): return self.upload_folder(bucket_name, file_path, prefix) else: file_name = os.path.basename(file_path) - return self.upload_file(bucket_name, os.path.join(prefix,file_name), file_path) + return self.upload_file(bucket_name, os.path.join(prefix, file_name), file_path) def upload_folder(self, bucket_name, folder_path, prefix=''): folder_name = os.path.basename(folder_path) @@ -207,28 +205,22 @@ def upload_folder(self, bucket_name, folder_path, prefix=''): f_path = os.path.join(folder_path, f) upload = self._upload_to_bucket(bucket_name, f_path, os.path.join(prefix, folder_name)) res.append(upload) - + return res - + def upload_ipfs_folder(self, bucket_name, object_name, folder_path): folder_name = os.path.basename(object_name) or os.path.basename(folder_path) prefix = os.path.normpath(os.path.dirname(object_name)) if os.path.dirname(object_name) else '' bucket_uid = self._get_bucket_id(bucket_name) - files = self._read_files(folder_path) - print(files) - + files = self._read_files(folder_path, folder_name) form_data = {"folder_name": folder_name, "prefix": prefix, "bucket_uid": bucket_uid} - print(form_data) - res = self.api_client._request_with_params(POST, PIN_IPFS, self.MCS_API, form_data, self.token, files) - if res: folder = (File(res["data"], self.gateway)) return folder - else: + else: logging.error("\033[31mIPFS Folder Upload Error\033[0m") - def download_file(self, bucket_name, object_name, local_filename): file = self.get_file(bucket_name, object_name) if file is not None: @@ -294,13 +286,15 @@ def _get_file_info(self, file_id): result = self.api_client._request_with_params(GET, FILE_INFO, self.MCS_API, params, self.token, None) file_info = File(result['data'], self.gateway) return file_info - + def get_gateway(self): result = self.api_client._request_without_params(GET, GET_GATEWAY, self.MCS_API, self.token) return result['data'] - def _read_files(self, root_folder): - # Create an empty list to store the file tuples + def _read_files(self, root_folder, folder_name): + + print(root_folder, folder_name) + # Create an empty list to store the file tuples file_dict = [] # Use glob to retrieve the file paths in the directory and its subdirectories @@ -310,12 +304,8 @@ def _read_files(self, root_folder): for file_path in file_paths: if os.path.isfile(file_path): # Get the relative path from the root folder - rel_path = os.path.relpath(file_path, root_folder) - - # Use the relative path as the file name - filename = os.path.normpath(rel_path).replace(os.sep, '/') - - # Read the contents of the file in binary mode - file_dict.append(('files', open(file_path, 'rb'))) + upload_path = folder_name + "/" + os.path.relpath(file_path, root_folder) + file_dict.append(('files', ( + upload_path, open(file_path, 'rb')))) - return file_dict \ No newline at end of file + return file_dict From 91f699316cd4aeb5ee1c1761db7b5553c42d834f Mon Sep 17 00:00:00 2001 From: rykci Date: Wed, 8 Mar 2023 14:12:43 -0500 Subject: [PATCH 21/25] update test case, and domain --- mcs/api/bucket_api.py | 7 ++++--- mcs/api_client.py | 5 +++++ mcs/common/constants.py | 1 + mcs/common/utils.py | 1 + mcs/object/bucket_storage.py | 6 +++--- test/test_bucket_api.py | 6 ++++++ test/test_onchain_api.py | 11 +++++------ 7 files changed, 25 insertions(+), 12 deletions(-) diff --git a/mcs/api/bucket_api.py b/mcs/api/bucket_api.py index e4375a3..98e88a7 100644 --- a/mcs/api/bucket_api.py +++ b/mcs/api/bucket_api.py @@ -18,6 +18,7 @@ def __init__(self, api_client=None): self.api_client = api_client self.MCS_API = api_client.MCS_API self.token = self.api_client.token + self.gateway = api_client.get_gateway() def list_buckets(self): try: @@ -138,7 +139,7 @@ def list_files(self, bucket_name, prefix='', limit='10', offset="0"): files = result['data']['file_list'] file_list = [] for file in files: - file_info: File = File(file) + file_info: File = File(file, self.gateway) file_list.append(file_info) return file_list else: @@ -275,12 +276,12 @@ def _get_full_file_list(self, bucket_name, prefix=''): self.api_client._request_with_params(GET, FILE_LIST, self.MCS_API, params, self.token, None)['data'][ 'file_list'] for file in result: - file_info: File = File(file) + file_info: File = File(file, self.gateway) file_list.append(file_info) return file_list def _get_file_info(self, file_id): params = {'file_id': file_id} result = self.api_client._request_with_params(GET, FILE_INFO, self.MCS_API, params, self.token, None) - file_info = File(result['data']) + file_info = File(result['data'], self.gateway) return file_info diff --git a/mcs/api_client.py b/mcs/api_client.py index 99db175..737c759 100644 --- a/mcs/api_client.py +++ b/mcs/api_client.py @@ -27,6 +27,11 @@ def get_params(self): def get_price_rate(self): return self._request_without_params(GET, PRICE_RATE, self.MCS_API, self.token) + + def get_gateway(self): + res = self._request_without_params(GET, GET_GATEWAY, self.MCS_API, self.token) + gateway = res["data"][0] + return gateway def api_key_login(self): params = {'apikey': self.api_key, 'access_token': self.access_token, 'network': self.chain_name} diff --git a/mcs/common/constants.py b/mcs/common/constants.py index c8a20ad..0ba476e 100644 --- a/mcs/common/constants.py +++ b/mcs/common/constants.py @@ -32,6 +32,7 @@ MERGE_FILE = "/api/v2/oss_file/merge" FILE_LIST = "/api/v2/oss_file/get_file_list" GET_FILE = "/api/v2/oss_file/get_file_by_object_name" +GET_GATEWAY = "/api/v2/gateway/get_gateway" # contract USDC_ABI = "ERC20.json" SWAN_PAYMENT_ABI = "SwanPayment.json" diff --git a/mcs/common/utils.py b/mcs/common/utils.py index 859fbf5..c668459 100644 --- a/mcs/common/utils.py +++ b/mcs/common/utils.py @@ -42,3 +42,4 @@ def object_to_filename(object_name): prefix = object_name[0:index] file_name = object_name[index + 1:] return prefix, file_name + diff --git a/mcs/object/bucket_storage.py b/mcs/object/bucket_storage.py index 582f960..8340626 100644 --- a/mcs/object/bucket_storage.py +++ b/mcs/object/bucket_storage.py @@ -22,15 +22,15 @@ def to_json(self): class File: - def __init__(self, file_data): + def __init__(self, file_data, gateway = 'https://ipfs.io'): self.name = file_data["name"] self.address = file_data["address"] self.bucket_uid = file_data["bucket_uid"] self.filehash = file_data["file_hash"] self.prefix = file_data["prefix"] self.size = file_data["size"] - self.payloadCid = file_data["payload_cid"] - self.ipfs_url = file_data["ipfs_url"] + self.payload_cid = file_data["payload_cid"] + self.ipfs_url = file_data.get("ipfs_url", gateway + '/ipfs/' + file_data["payload_cid"]) self.pin_status = file_data["pin_status"] self.is_deleted = file_data["is_deleted"] self.is_folder = file_data["is_folder"] diff --git a/test/test_bucket_api.py b/test/test_bucket_api.py index 5d85d5c..4851dd7 100644 --- a/test/test_bucket_api.py +++ b/test/test_bucket_api.py @@ -79,3 +79,9 @@ def test_delete_file(): delete = api.delete_file('test-bucket', 'folder1/mcs-logo.png') assert delete == True + +# def test_upload_ipfs_folder(): +# api = login() +# res = api.upload_ipfs_folder('test-bucket', 'ipfs-folder', 'images') + +# print(res) \ No newline at end of file diff --git a/test/test_onchain_api.py b/test/test_onchain_api.py index e8b6e27..c862e84 100644 --- a/test/test_onchain_api.py +++ b/test/test_onchain_api.py @@ -38,17 +38,16 @@ def test_create_collection(): api = login() num_collections = len(api.get_collections()) - collection = api.create_collection('test-collection-' + str(num_collections), {"name": 'test-collection-'+str(num_collections)}) - pytest.collection_address = collection["address"] + collection = api.create_collection({"name": 'test-collection-'+str(num_collections)}) assert len(api.get_collections()) == num_collections + 1 -def test_mint(): - api = login() +# def test_mint(): +# api = login() - mint = api.mint(pytest.file.source_file_upload_id, {"name": 'test-nft', 'image': pytest.file.ipfs_url}, pytest.collection_address) +# mint = api.mint(pytest.file.source_file_upload_id, {"name": 'test-nft', 'image': pytest.file.ipfs_url}, pytest.collection_address) - assert mint["id"] == 1 +# assert mint["id"] == 1 def test_get_uploads(): api = login() From 805a67aa02d759941211eb70b11597b6ed403ea1 Mon Sep 17 00:00:00 2001 From: rykci Date: Wed, 8 Mar 2023 14:19:29 -0500 Subject: [PATCH 22/25] dev2 --- mcs/api/bucket_api.py | 2 -- mcs/common/constants.py | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/mcs/api/bucket_api.py b/mcs/api/bucket_api.py index 7080efd..578e8d1 100644 --- a/mcs/api/bucket_api.py +++ b/mcs/api/bucket_api.py @@ -292,8 +292,6 @@ def get_gateway(self): return result['data'] def _read_files(self, root_folder, folder_name): - - print(root_folder, folder_name) # Create an empty list to store the file tuples file_dict = [] diff --git a/mcs/common/constants.py b/mcs/common/constants.py index 9e6aea2..f6f29ee 100644 --- a/mcs/common/constants.py +++ b/mcs/common/constants.py @@ -1,5 +1,5 @@ MCS_POLYGON_MAIN_API = "https://api.multichain.storage" -MCS_POLYGON_MUMBAI_API = "http://192.168.88.41:8889" +MCS_POLYGON_MUMBAI_API = "https://calibration-mcs-api.filswan.com" MCS_BSC_API = 'https://calibration-mcs-bsc.filswan.com' GET = "GET" POST = "POST" From 6b5828c7389adf6d918cc19168e469e83ea96051 Mon Sep 17 00:00:00 2001 From: rykci Date: Wed, 8 Mar 2023 14:24:07 -0500 Subject: [PATCH 23/25] fix gateway url, add ipfs folder upload test --- mcs/api/bucket_api.py | 4 ++-- test/test_bucket_api.py | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/mcs/api/bucket_api.py b/mcs/api/bucket_api.py index 35c78cc..b559550 100644 --- a/mcs/api/bucket_api.py +++ b/mcs/api/bucket_api.py @@ -20,7 +20,7 @@ def __init__(self, api_client=None): self.api_client = api_client self.MCS_API = api_client.MCS_API self.token = self.api_client.token - self.gateway = self.get_gateway()[0] + self.gateway = self.get_gateway() def list_buckets(self): try: @@ -300,7 +300,7 @@ def _get_file_info(self, file_id): def get_gateway(self): result = self.api_client._request_without_params(GET, GET_GATEWAY, self.MCS_API, self.token) - return result['data'] + return 'https://' + result['data'][0] def _read_files(self, root_folder, folder_name): # Create an empty list to store the file tuples diff --git a/test/test_bucket_api.py b/test/test_bucket_api.py index 4851dd7..29bf44b 100644 --- a/test/test_bucket_api.py +++ b/test/test_bucket_api.py @@ -80,8 +80,8 @@ def test_delete_file(): assert delete == True -# def test_upload_ipfs_folder(): -# api = login() -# res = api.upload_ipfs_folder('test-bucket', 'ipfs-folder', 'images') +def test_upload_ipfs_folder(): + api = login() + res = api.upload_ipfs_folder('test-bucket', 'ipfs-folder', 'images') -# print(res) \ No newline at end of file + print(res) \ No newline at end of file From 3ee2d53cb567f151aaa5bbc9080b514e5b8cfb16 Mon Sep 17 00:00:00 2001 From: daniel Date: Wed, 8 Mar 2023 18:59:25 -0500 Subject: [PATCH 24/25] fix --- mcs/api/bucket_api.py | 24 ++++++++++++------------ mcs/object/bucket_storage.py | 4 ++-- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/mcs/api/bucket_api.py b/mcs/api/bucket_api.py index 7080efd..fe8b6fe 100644 --- a/mcs/api/bucket_api.py +++ b/mcs/api/bucket_api.py @@ -208,18 +208,18 @@ def upload_folder(self, bucket_name, folder_path, prefix=''): return res - def upload_ipfs_folder(self, bucket_name, object_name, folder_path): - folder_name = os.path.basename(object_name) or os.path.basename(folder_path) - prefix = os.path.normpath(os.path.dirname(object_name)) if os.path.dirname(object_name) else '' - bucket_uid = self._get_bucket_id(bucket_name) - files = self._read_files(folder_path, folder_name) - form_data = {"folder_name": folder_name, "prefix": prefix, "bucket_uid": bucket_uid} - res = self.api_client._request_with_params(POST, PIN_IPFS, self.MCS_API, form_data, self.token, files) - if res: - folder = (File(res["data"], self.gateway)) - return folder - else: - logging.error("\033[31mIPFS Folder Upload Error\033[0m") + # def upload_ipfs_folder(self, bucket_name, object_name, folder_path): + # folder_name = os.path.basename(object_name) or os.path.basename(folder_path) + # prefix = os.path.normpath(os.path.dirname(object_name)) if os.path.dirname(object_name) else '' + # bucket_uid = self._get_bucket_id(bucket_name) + # files = self._read_files(folder_path, folder_name) + # form_data = {"folder_name": folder_name, "prefix": prefix, "bucket_uid": bucket_uid} + # res = self.api_client._request_with_params(POST, PIN_IPFS, self.MCS_API, form_data, self.token, files) + # if res: + # folder = (File(res["data"], self.gateway)) + # return folder + # else: + # logging.error("\033[31mIPFS Folder Upload Error\033[0m") def download_file(self, bucket_name, object_name, local_filename): file = self.get_file(bucket_name, object_name) diff --git a/mcs/object/bucket_storage.py b/mcs/object/bucket_storage.py index 135ad87..9697bfb 100644 --- a/mcs/object/bucket_storage.py +++ b/mcs/object/bucket_storage.py @@ -30,7 +30,7 @@ def __init__(self, file_data, gateway=''): self.prefix = file_data["prefix"] self.size = file_data["size"] self.payloadCid = file_data["payload_cid"] - self.ipfs_url = gateway + '/ipfs/' + file_data["payload_cid"] + self.ipfs_url = "http://" + gateway + '/ipfs/' + file_data["payload_cid"] self.pin_status = file_data["pin_status"] self.is_deleted = file_data["is_deleted"] self.is_folder = file_data["is_folder"] @@ -38,7 +38,7 @@ def __init__(self, file_data, gateway=''): self.updated_at = file_data["updated_at"] self.created_at = file_data["created_at"] self.deleted_at = file_data["deleted_at"] - + self.gateway = gateway self.object_name = file_data["object_name"] self.type = file_data["type"] From 3e6c05b5b9f4e0301ddaf9d02dd8c705e7cb8d77 Mon Sep 17 00:00:00 2001 From: daniel Date: Wed, 8 Mar 2023 19:11:21 -0500 Subject: [PATCH 25/25] fix bugs --- mcs/object/bucket_storage.py | 2 +- setup.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/mcs/object/bucket_storage.py b/mcs/object/bucket_storage.py index a400a20..2014813 100644 --- a/mcs/object/bucket_storage.py +++ b/mcs/object/bucket_storage.py @@ -30,7 +30,7 @@ def __init__(self, file_data, gateway = 'https://ipfs.io'): self.prefix = file_data["prefix"] self.size = file_data["size"] self.payloadCid = file_data["payload_cid"] - self.ipfs_url = "http://" + gateway + '/ipfs/' + file_data["payload_cid"] + self.ipfs_url = gateway + '/ipfs/' + file_data["payload_cid"] self.pin_status = file_data["pin_status"] self.is_deleted = file_data["is_deleted"] self.is_folder = file_data["is_folder"] diff --git a/setup.py b/setup.py index 1328e9f..c47cb4a 100644 --- a/setup.py +++ b/setup.py @@ -5,11 +5,11 @@ long_description = (this_directory / "PipReleaseDoc.md").read_text() setup(name="python-mcs-sdk", - version="0.2.1", + version="0.2.15", author="daniel8088", author_email="danilew8088@gmail.com", install_requires=["web3==5.31.1", "requests==2.28.1", "requests_toolbelt==0.10.1", "tqdm==4.64.1"], - packages=["mcs", "mcs.api", "mcs.contract", "mcs.contract.abi", "mcs.common", "mcs.upload", "mcs.object"], + packages=["mcs", "mcs.api", "mcs.contract", "mcs.contract.abi", "mcs.common", "mcs.object"], license="MIT", include_package_data=True, description="A python software development kit for the Multi-Chain Storage",