├── examples ├── script │ ├── __init__.py │ └── script_c.py ├── README.MD ├── get_domains_not_on_sale.py ├── get_domains_on_sale.py ├── accept_offers_over_threshold.py ├── remove_all_domains_from_selling.py ├── edit_domain_description.py ├── consent_offers.py ├── send_domains.py └── sell_domains.py ├── requirements.txt ├── namebase_marketplace ├── __init__.py ├── __pycache__ │ ├── enums.cpython-37.pyc │ ├── enums.cpython-39.pyc │ ├── utils.cpython-37.pyc │ ├── utils.cpython-39.pyc │ ├── __init__.cpython-37.pyc │ ├── __init__.cpython-39.pyc │ ├── marketplace.cpython-37.pyc │ └── marketplace.cpython-39.pyc ├── enums.py ├── utils.py └── marketplace.py ├── docs └── deploy ├── setup.cfg ├── .gitignore ├── LICENSE ├── setup.py ├── test └── test.py └── README.md /examples/script/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | requests -------------------------------------------------------------------------------- /namebase_marketplace/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /docs/deploy: -------------------------------------------------------------------------------- 1 | python setup.py sdist 2 | twine upload dist/* -------------------------------------------------------------------------------- /setup.cfg: -------------------------------------------------------------------------------- 1 | # Inside of setup.cfg 2 | [metadata] 3 | description-file = README.md -------------------------------------------------------------------------------- /namebase_marketplace/__pycache__/enums.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robertprp/namebase-marketplace/HEAD/namebase_marketplace/__pycache__/enums.cpython-37.pyc -------------------------------------------------------------------------------- /namebase_marketplace/__pycache__/enums.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robertprp/namebase-marketplace/HEAD/namebase_marketplace/__pycache__/enums.cpython-39.pyc -------------------------------------------------------------------------------- /namebase_marketplace/__pycache__/utils.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robertprp/namebase-marketplace/HEAD/namebase_marketplace/__pycache__/utils.cpython-37.pyc -------------------------------------------------------------------------------- /namebase_marketplace/__pycache__/utils.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robertprp/namebase-marketplace/HEAD/namebase_marketplace/__pycache__/utils.cpython-39.pyc -------------------------------------------------------------------------------- /namebase_marketplace/__pycache__/__init__.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robertprp/namebase-marketplace/HEAD/namebase_marketplace/__pycache__/__init__.cpython-37.pyc -------------------------------------------------------------------------------- /namebase_marketplace/__pycache__/__init__.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robertprp/namebase-marketplace/HEAD/namebase_marketplace/__pycache__/__init__.cpython-39.pyc -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | venv/ 2 | .idea/ 3 | namebase_marketplace.egg-info/ 4 | dist/ 5 | setup.cfg 6 | /namebase_marketplace.egg-info 7 | /.idea 8 | /venv 9 | .github/ 10 | /.github 11 | -------------------------------------------------------------------------------- /namebase_marketplace/__pycache__/marketplace.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robertprp/namebase-marketplace/HEAD/namebase_marketplace/__pycache__/marketplace.cpython-37.pyc -------------------------------------------------------------------------------- /namebase_marketplace/__pycache__/marketplace.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robertprp/namebase-marketplace/HEAD/namebase_marketplace/__pycache__/marketplace.cpython-39.pyc -------------------------------------------------------------------------------- /examples/README.MD: -------------------------------------------------------------------------------- 1 | ## Premade scripts to be launcehd on console. 2 | 3 | Launch these premade scripts on console. 4 | 5 | ### Help 6 | > python3 <> --help 7 | 8 | ###### Only cookie auth is allowed on these scripts. 9 | 10 | ### Donations 11 | 12 | I have made this library open-sourced and free to use. However, if you consider this library has helped you, or you just want to sponsor me, donations are welcomed to one of my HANDSHAKE addresses. 13 | 14 | > hs1qynh72cuj7lawdcmvjtls4kk0p4auzmj5qq6v3r 15 | -------------------------------------------------------------------------------- /examples/get_domains_not_on_sale.py: -------------------------------------------------------------------------------- 1 | import argparse 2 | import sys 3 | from namebase_marketplace import marketplace 4 | from script.script_c import Script 5 | 6 | if __name__ == '__main__': 7 | parser = argparse.ArgumentParser(description='Get all my domains I dont have on sale.') 8 | 9 | parser.add_argument('--cookie', required=True, help='Input your namebase cookie (namebase-main).') 10 | 11 | args = parser.parse_args() 12 | marketplace = marketplace.Marketplace(namebase_cookie=args.cookie) 13 | script = Script(marketplace) 14 | domains = script.get_domains_not_on_sale() 15 | print(' '.join(domains)) 16 | -------------------------------------------------------------------------------- /examples/get_domains_on_sale.py: -------------------------------------------------------------------------------- 1 | import argparse 2 | import sys 3 | from namebase_marketplace import marketplace 4 | from script.script_c import Script 5 | 6 | if __name__ == '__main__': 7 | parser = argparse.ArgumentParser(description='Get all my domains I have on sell with links to namebase.') 8 | 9 | parser.add_argument('--cookie', required=True, help='Input your namebase cookie (namebase-main).') 10 | 11 | args = parser.parse_args() 12 | marketplace = marketplace.Marketplace(namebase_cookie=args.cookie) 13 | script = Script(marketplace) 14 | domains = script.get_domains_on_sale() 15 | print(' '.join(domains)) 16 | 17 | -------------------------------------------------------------------------------- /examples/accept_offers_over_threshold.py: -------------------------------------------------------------------------------- 1 | import argparse 2 | import sys 3 | from namebase_marketplace import marketplace 4 | from script.script_c import Script 5 | 6 | if __name__ == '__main__': 7 | parser = argparse.ArgumentParser(description='Accept offers over a predefined threshold.') 8 | 9 | parser.add_argument('--cookie', required=True, help='Input your namebase cookie (namebase-main).') 10 | parser.add_argument('--threshold', dest='threshold', required=True, type=float, 11 | help='Minimum amount to accept an offer.') 12 | 13 | args = parser.parse_args() 14 | marketplace = marketplace.Marketplace(namebase_cookie=args.cookie) 15 | script = Script(marketplace) 16 | offers = script.get_offers_to_accept(threshold=args.threshold) 17 | 18 | -------------------------------------------------------------------------------- /examples/remove_all_domains_from_selling.py: -------------------------------------------------------------------------------- 1 | import argparse 2 | import sys 3 | from namebase_marketplace import marketplace 4 | from script.script_c import Script 5 | 6 | if __name__ == '__main__': 7 | parser = argparse.ArgumentParser(description='REMOVE EVERY DOMAIN FROM MARKETPLACE.') 8 | 9 | parser.add_argument('--cookie', required=True, help='Input your namebase cookie (namebase-main).') 10 | parser.add_argument('--remove', dest='remove', required=True, 11 | help='By activating this flag, you agree to remove every domain you own from marketplace.') 12 | 13 | args = parser.parse_args() 14 | marketplace = marketplace.Marketplace(namebase_cookie=args.cookie) 15 | script = Script(marketplace) 16 | script.remove_all_names_from_selling_page() -------------------------------------------------------------------------------- /examples/edit_domain_description.py: -------------------------------------------------------------------------------- 1 | import argparse 2 | import sys 3 | from namebase_marketplace import marketplace 4 | from script.script_c import Script 5 | 6 | if __name__ == '__main__': 7 | parser = argparse.ArgumentParser(description='EDIT DOMAIN DESCRIPTION.') 8 | 9 | parser.add_argument('--cookie', required=True, help='Input your namebase cookie (namebase-main).') 10 | parser.add_argument('--domain', dest='domain', required=True, type=str, 11 | help='Domain to change description.') 12 | parser.add_argument('--description', dest='description',nargs='+', default=[], required=True, 13 | help='New description to put on domain') 14 | 15 | args = parser.parse_args() 16 | marketplace = marketplace.Marketplace(namebase_cookie=args.cookie) 17 | script = Script(marketplace) 18 | description = ' '.join(args.description) 19 | script.edit_domain_sale_description(domain=args.domain, description=description) -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Wing Yung Chan 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /examples/consent_offers.py: -------------------------------------------------------------------------------- 1 | import argparse 2 | import sys 3 | from namebase_marketplace import marketplace 4 | from script.script_c import Script 5 | 6 | if __name__ == '__main__': 7 | parser = argparse.ArgumentParser(description='Consent offers on a specific domain. In order to disallow or not consent a domain to receive offers you just need to run the test without the --consent flag.') 8 | 9 | parser.add_argument('--cookie', required=True, help='Input your namebase cookie (namebase-main).') 10 | parser.add_argument('--domain', dest='domain', required=True, type=str, 11 | help='Domain to consent offers or not.') 12 | parser.add_argument('--consent', dest='consent', required=False, action='store_true', default=False, 13 | help='Whether to consent offers or not. Use --consent to consent offers and dont use this flag to unconsent/disallow offers.') 14 | 15 | args = parser.parse_args() 16 | marketplace = marketplace.Marketplace(namebase_cookie=args.cookie) 17 | script = Script(marketplace) 18 | script.consent_potential_offers(domain=args.domain, consent=args.consent) 19 | 20 | -------------------------------------------------------------------------------- /examples/send_domains.py: -------------------------------------------------------------------------------- 1 | import argparse 2 | import sys 3 | from namebase_marketplace import marketplace 4 | from script.script_c import Script 5 | 6 | if __name__ == '__main__': 7 | parser = argparse.ArgumentParser(description='Send as many domains as you want through handshake chain domain.') 8 | 9 | parser.add_argument('--cookie', required=True, help='Input your namebase cookie (namebase-main).') 10 | parser.add_argument('--domains', dest='domains', required=True, nargs="+", 11 | help='Domains to send as: --domains domainexample1 domainexample2 domainexample3') 12 | parser.add_argument('--address', dest='address', required=True, type=str, 13 | help='Whether to consent offers or not. Use --consent to consent offers and dont use this flag to unconsent/disallow offers.') 14 | 15 | args = parser.parse_args() 16 | marketplace = marketplace.Marketplace(namebase_cookie=args.cookie) 17 | script = Script(marketplace) 18 | address = args.address 19 | 20 | domains = args.domains 21 | print(domains) 22 | for domain in domains: 23 | res = script.send_domain_on_chain(domain=domain, hns_address=address) 24 | print (res) 25 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | import setuptools 2 | 3 | # read the contents of your README file 4 | from os import path 5 | this_directory = path.abspath(path.dirname(__file__)) 6 | with open(path.join(this_directory, 'README.md'), encoding='utf-8') as f: 7 | long_description = f.read() 8 | 9 | setuptools.setup( 10 | name="namebase-marketplace", 11 | version="0.2.82", 12 | python_requires='>=3.6', 13 | author="Roberto Pérez Rico (pretended)", 14 | author_email="robertforperez@gmail.com", 15 | description="Python Client to interact with the Namebase Marketplace API", 16 | long_description=long_description, 17 | long_description_content_type="text/markdown", 18 | url="https://github.com/pretended/namebase-marketplace", 19 | packages=setuptools.find_packages(), 20 | install_requires=['requests'], 21 | classifiers=[ 22 | "Programming Language :: Python :: 3", 23 | "Programming Language :: Python :: 3.6", 24 | "Programming Language :: Python :: 3.7", 25 | "License :: OSI Approved :: MIT License", 26 | "Operating System :: OS Independent", 27 | 'Intended Audience :: Developers', 28 | 'Topic :: Software Development :: Libraries :: Python Modules', 29 | 'Natural Language :: English' 30 | ], 31 | 32 | ) -------------------------------------------------------------------------------- /test/test.py: -------------------------------------------------------------------------------- 1 | from namebase_marketplace import marketplace 2 | 3 | def should_accept_offer(offerAmount, threshold): 4 | return float(offerAmount) >= threshold 5 | 6 | def get_best_offer(bestBidId, domain_history): 7 | negotiations = domain_history['negotiations'] 8 | for negotiation in negotiations: 9 | history = negotiation['history'] 10 | for hist in history['bids']: 11 | amount = hist['amount'] 12 | id = hist['bidId'] 13 | isAccepted = hist['isAccepted'] 14 | if id == bestBidId and not isAccepted: 15 | return {"id" : id, "amount" : float(amount)} 16 | 17 | return {} 18 | 19 | if __name__ == '__main__': 20 | cookie= 'your cookie' 21 | m = marketplace.Marketplace(namebase_cookie=cookie) 22 | offers = m.get_offers() 23 | threshold = 8 24 | for offer in offers: 25 | ownerId = offer['ownerId'] 26 | history = m.get_offers_domain_history(domainOwnerId=ownerId) 27 | bestBidId = history['negotiations'][0]['bestBidId'] 28 | if bestBidId: 29 | best_offer = get_best_offer(bestBidId=bestBidId, 30 | domain_history=history) 31 | offerAmount = best_offer['amount'] 32 | id = best_offer['id'] 33 | should_accept = should_accept_offer(offerAmount=offerAmount, 34 | threshold=threshold) 35 | if should_accept: 36 | res = m.accept_offer(offer_id=id) 37 | -------------------------------------------------------------------------------- /namebase_marketplace/enums.py: -------------------------------------------------------------------------------- 1 | __all__ = ['Utils'] 2 | API_VERSION = 'v0' 3 | 4 | 5 | class Endpoint(): 6 | MARKETPLACE = '/api/domains/marketplace/' 7 | SALE_HISTORY = '/api/domains/sold/' 8 | USER_INFO = '/api/user' 9 | OPEN_BID = f'/api/{API_VERSION}/auction/' # + /bid 10 | MAKE_OFFER = f'/api/{API_VERSION}/marketplace/' 11 | OFFERS_RECEIVED = f'/api/{API_VERSION}/offers/received' 12 | OFFERS_HISTORY = f'/api/{API_VERSION}/offers/history' 13 | ACCEPT_OFFER_BID = f'/api/{API_VERSION}/offers/bid' 14 | DOMAIN_HISTORY = MAKE_OFFER 15 | LOGIN = '/auth/local/account-login' 16 | ENDING_SOON = '/api/domains/ending-soon/' # + OFFSET 17 | GET_DOMAIN = '/api/domains/get/' 18 | WATCH_DOMAIN = '/api/domains/watch/' 19 | DLINK = '/api/user/dlinks' 20 | MY_SALE_DOMAINS = '/api/user/domains/listed' 21 | MY_DOMAINS = '/api/user/domains/not-listed/' 22 | API_DOMAINS = '/api/domains/' 23 | 24 | class Utils(): 25 | BID = '/bid' 26 | HISTORY = '/history' 27 | BUY_NOW = '/buynow' 28 | LIST = '/list' 29 | LISTED = '/listed' 30 | CANCEL = '/cancel' 31 | CONSENT = '/consent' 32 | SORT_KEY_ARRAY = ['bid', 'price', 'name', 'date'] 33 | DEFAULT_SORT_KEY = 'bid' 34 | TRANSFER = '/transfer' 35 | SORT_DIRECTION_ARRAY = ['asc', 'desc'] 36 | DEFAULT_OPTIONS_MY_DOMAINS = {"sortKey":"acquiredAt","sortDirection":"desc","limit":100} 37 | @staticmethod 38 | def parse_bid(amount): 39 | number_str = str(amount) 40 | if isinstance(amount, int): 41 | number_str += '.' 42 | while len(number_str) < 8: 43 | number_str += '0' 44 | return number_str 45 | 46 | @staticmethod 47 | def get_real_amount(amount): 48 | part1 = amount[:-6] 49 | part2 = amount[-6:] 50 | return float(f'{part1}.{part2}') -------------------------------------------------------------------------------- /examples/sell_domains.py: -------------------------------------------------------------------------------- 1 | import argparse 2 | import sys 3 | from namebase_marketplace import marketplace 4 | from script.script_c import Script 5 | 6 | if __name__ == '__main__': 7 | parser = argparse.ArgumentParser(description='Sell domains.') 8 | 9 | parser.add_argument('--cookie', required=True, help='Input your namebase cookie (namebase-main).') 10 | parser.add_argument('--enumerate', dest='enum', nargs='+', default=[], required=False, 11 | help='Enumerate domains to be put on marketplace, you must own these domains!!! , as an example: --enumerate domain1 domain2 domain3') 12 | parser.add_argument('--all', required=False, action='store_true', 13 | help='Put on marketplace every domain you own and its not listed on namebase marketplace already with a description and a common price.') 14 | parser.add_argument('--price', required='--enumerate' in sys.argv or '--all' in sys.argv, dest='price', type=float, help='Input the price of the domains to be put on marketplace') 15 | parser.add_argument( '--description', required='--enumerate' in sys.argv or '--all' in sys.argv, type=str, dest='description', nargs='+', default=[], 16 | help='Input the description of the domains to be put on marketplace') 17 | 18 | args = parser.parse_args() 19 | if args.enum and args.all: 20 | parser.error("--ennumerate can't be spawned along --all. Use one or the other. Not together.") 21 | 22 | marketplace = marketplace.Marketplace(namebase_cookie=args.cookie) 23 | script = Script(marketplace) 24 | description = ' '.join(args.description) 25 | if args.all: 26 | script.sell_domains(price=args.price, description=description, custom_domains=False) 27 | elif args.enum: 28 | script.sell_domains(price=args.price, description=description, custom_domains=True, domains=args.enum) -------------------------------------------------------------------------------- /namebase_marketplace/utils.py: -------------------------------------------------------------------------------- 1 | """ 2 | Includes Request class for convenience which applies consistent Timeout, Headers and Base URL settings. 3 | """ 4 | __all__ = ['get_current_time_milliseconds', 'Request'] 5 | 6 | import requests 7 | import time 8 | import json 9 | 10 | 11 | def get_current_time_milliseconds(): 12 | return round(time.time() * 1000) 13 | 14 | 15 | class Request(object): 16 | def __init__(self, api_base_url, headers, cookies, timeout=30): 17 | self.url = api_base_url 18 | self.timeout = timeout 19 | self.headers = headers 20 | self.cookies = cookies 21 | 22 | def get(self, path, params=None): 23 | """GET request""" 24 | r = requests.get(url=self.url + path, params=params, timeout=self.timeout, 25 | headers=self.headers, cookies=self.cookies) 26 | r.raise_for_status() 27 | return r.json() 28 | 29 | def post(self, path, data=None, json_data=None, params=None): 30 | """POST request""" 31 | url = self.url + path 32 | print(data) 33 | r = requests.post(url=url, data=json.dumps(data), json=json_data, params=json.dumps(params), timeout=self.timeout, 34 | headers=self.headers, cookies=self.cookies) 35 | try: 36 | r.raise_for_status() 37 | except requests.exceptions.HTTPError as e: 38 | return json.loads(e.response.content) 39 | return r.json() 40 | 41 | def put(self, path, data=None, json_data=None, params=None): 42 | """PUT request""" 43 | url = self.url + path 44 | r = requests.put(url=url, data=data, json=json_data, params=params, timeout=self.timeout, 45 | headers=self.headers, cookies=self.cookies) 46 | try: 47 | r.raise_for_status() 48 | except requests.exceptions.HTTPError as e: 49 | return json.loads(e.response.content) 50 | return r.json() 51 | 52 | def post_get_response(self, path, data=None, json_data=None, params=None): 53 | url = self.url + path 54 | r = requests.post(url=url, data=data, json=json_data, params=params, timeout=self.timeout, 55 | headers=self.headers, cookies=self.cookies) 56 | try: 57 | r.raise_for_status() 58 | except requests.exceptions.HTTPError as e: 59 | return json.loads(e.response.content) 60 | return r 61 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Namebase Marketplace Api for Python 2 | == 3 | 4 |

5 | 6 | Open Issues 7 | 8 | 9 | Open Issues 10 | 11 | 12 | PyPI 13 | 14 | 15 | MIT Licence 16 | 17 | 18 | 19 | 20 | Python 3.6+ client for interacting with Namebase Marketplace API. 21 | 22 | ## Usage 23 | Instantiating the Marketplace object can be done either by using email and password or None. 24 | Only post requests can be made authenticated. 25 | 26 | Websocket API is not provided. 27 | ## Installation 28 | 29 | ### Requirements 30 | 31 | - Python 3.6 or greater 32 | 33 | ### Install 34 | 35 | > pip install namebase-marketplace 36 | 37 | 38 | ### Upgrade 39 | 40 | > pip install --upgrade namebase-marketplace 41 | 42 | ### Usage 43 | 44 | ##### Core REST API for Namebase MARKETPLACE 45 | ```python 46 | from namebase_marketplace.marketplace import * 47 | marketplace = Marketplace(email="YOUR EMAIL", pwd="YOUR PASSWORD") 48 | marketplace.get_user_info() 49 | marketplace.open_bid(domain='domain', bid_amount=0.4, blind_amount=100) 50 | ``` 51 | 52 | ##### EXAMPLE WITHOUT AUTHENTICATION: 53 | ```python 54 | from namebase_marketplace.marketplace import * 55 | marketplace = Marketplace() 56 | marketplace.get_marketplace_domains(offset=100) # Get 101-200 latest marketplace domains with default options 57 | ``` 58 | 59 | On some endpoints you can pass options, please refer them to the following documentation: https://github.com/namebasehq/api-documentation/blob/master/marketplace-api.md 60 | 61 | ### Github OAuth bypass and 2FA Auth Bypass 62 | 63 | #### Recent upgrades 64 | New auth method has been added, now you can auth yourself by using the namebase_cookie in case you cant (or dont want to) login via email-password. 65 | 66 | This is the cookie Namebase uses to auth you within the app. You can find this cookie when reloading any page and going to Network on Inspection Mode. Head to a request and find this cookie under "Cookies" tab on any explorer along with other kind of cookies. Cookie name is called "namebase-main". 67 | 68 | ###### Example 69 | ```python 70 | from namebase_marketplace.marketplace import * 71 | marketplace = Marketplace(namebase_cookie="") 72 | marketplace.get_user_info() 73 | marketplace.open_bid(domain='domain', bid_amount=0.4, blind_amount=100) 74 | ``` 75 | 76 | 77 | ## Donations 78 | 79 | I have made this library open-sourced and free to use. However, if you consider this library has helped you, or you just want to sponsor me, donations are welcomed to one of my HANDSHAKE addresses. 80 | 81 | > hs1qynh72cuj7lawdcmvjtls4kk0p4auzmj5qq6v3r 82 | -------------------------------------------------------------------------------- /examples/script/script_c.py: -------------------------------------------------------------------------------- 1 | import sys 2 | 3 | from namebase_marketplace import marketplace 4 | import time 5 | 6 | 7 | class Script: 8 | def __init__(self, m): 9 | self.m = m 10 | 11 | def sell_domains(self, price, description, custom_domains=True, domains=None): 12 | if domains is None: 13 | domains = [] 14 | if custom_domains: 15 | 16 | my_domains_not_for_sale = domains 17 | for domain in my_domains_not_for_sale: 18 | self.m.list_domain(domain=domain, amount=price, description=description) 19 | time.sleep(0.5) 20 | print(f'[===] Successfully listed domain: {domain} at a price {price} with description {description}') 21 | else: 22 | my_domains_not_for_sale = self.m.get_my_domains() 23 | for domain in my_domains_not_for_sale: 24 | self.m.list_domain(domain=domain['name'], amount=price, description=description) 25 | time.sleep(0.5) 26 | print(f'[===] Successfully listed domain: {domain["name"]} at a price {price} with description {description}') 27 | 28 | 29 | 30 | 31 | def consent_potential_offers(self, domain, consent: bool): 32 | l = self.m.consent_offers(domain=domain, consent=consent) 33 | print(l) 34 | def remove_all_names_from_selling_page(self): 35 | selling_domains = self.m.get_my_onsale_domains() 36 | for domain in selling_domains['domains']: 37 | self.m.cancel_listing(domain=domain['name']) 38 | time.sleep(0.3) 39 | print(f'[{"+" * 10}] Domain {domain["name"]} was removed from marketplace. [{"+" * 10}]') 40 | def edit_domain_sale_description(self, domain, description): 41 | domain_price = self.m.get_domain_price(domain=domain) 42 | self.m.cancel_listing(domain=domain) 43 | time.sleep(0.5) 44 | self.m.list_domain(domain=domain, amount=domain_price, description=description) 45 | 46 | 47 | def get_domains_on_sale(self): 48 | domains_on_sale = self.m.get_my_onsale_domains() 49 | BASE_URL = 'https://www.namebase.io/domains/' 50 | for domain in domains_on_sale['domains']: 51 | print(f'{BASE_URL}{domain["name"]}') 52 | return [domain['name'] for domain in domains_on_sale['domains']] 53 | def get_domains_not_on_sale(self): 54 | print('If you have a lot of domains this might take a bit. Be patient.') 55 | return self.m.get_my_domains() 56 | def send_domain_on_chain(self, domain, hns_address): 57 | res = self.m.transfer_domain_on_chain(domain=domain, hns_address=hns_address) 58 | return res 59 | 60 | def should_accept_offer(self, offerAmount, threshold): 61 | return float(offerAmount) >= threshold 62 | 63 | def get_best_offer(self, bestBidId, domain_history): 64 | negotiations = domain_history['negotiations'] 65 | for negotiation in negotiations: 66 | history = negotiation['history'] 67 | for hist in history['bids']: 68 | amount = hist['amount'] 69 | id = hist['bidId'] 70 | isAccepted = hist['isAccepted'] 71 | if id == bestBidId and not isAccepted: 72 | return {"id": id, "amount": float(amount)} 73 | 74 | return {} 75 | 76 | def filter_out_offers(self, offers, threshold): 77 | return [offer for offer in offers if float(offer['offer']) >= threshold] 78 | 79 | def get_offers_to_accept(self, threshold): 80 | offers = self.m.get_offers() 81 | filtered_offers = self.filter_out_offers(offers=offers, threshold=threshold) 82 | should_accept_offers = [] 83 | for offer in filtered_offers: 84 | try: 85 | ownerId = offer['ownerId'] 86 | name = offer['name'] 87 | history = self.m.get_offers_domain_history(domainOwnerId=ownerId) 88 | bestBidId = history['negotiations'][0]['bestBidId'] 89 | if bestBidId: 90 | best_offer = self.get_best_offer(bestBidId=bestBidId, 91 | domain_history=history) 92 | offerAmount = best_offer['amount'] 93 | id = best_offer['id'] 94 | should_accept = self.should_accept_offer(offerAmount=offerAmount, 95 | threshold=threshold) 96 | if should_accept: 97 | should_accept_offers.append({"id": id, "amount": offerAmount, "domain_name": name}) 98 | except: 99 | continue 100 | print("Should I accept all this following offers? Current minimum bid threshold is: " + str(threshold)) 101 | 102 | for offer in should_accept_offers: 103 | print(f"Domain Name: {offer['domain_name']} - Bid Amount: {offer['amount']} HNS") 104 | 105 | decision = input('Input Y (Yes) / N (No): ').lower() 106 | if decision == 'yes' or decision == 'y': 107 | for offer in should_accept_offers: 108 | self.m.accept_offer(offer_id=offer['id']) 109 | print(f"NEW SALE - Name {offer['domain_name']} was just sold for {offer['amount']} HNS.") 110 | else: 111 | print('Please, relaunch the test whenever you want to sell domains. Bye.') 112 | sys.exit(0) 113 | 114 | # if __name__ == '__main__': 115 | # marketplace = marketplace.Marketplace() 116 | # test = Script(marketplace) 117 | # """Sell domains.""" 118 | # """This will put all your domains not for sale at a price of 200HNS with description TEST""" 119 | # #test.sell_domains(price=200, description='Test', custom_domains=False) 120 | # """This will put domains you give the method not for sale at a price of 200HNS with description TEST""" 121 | # domains = ['mydomain', 'mysecondomain'] 122 | # #test.sell_domains( price=200, description='Test', custom_domains=True, domains=domains) 123 | # 124 | # """Consent Potential Offers.""" 125 | # test.consent_potential_offers( domain='domain', 126 | # consent=False) # Do not allow people send offers to domain 'domain'. 127 | # test.consent_potential_offers( domain='domain', 128 | # consent=True) # Do allow people send offers to domain 'domain'. 129 | # 130 | # """Remove all my selling domains from sale """ 131 | # test.remove_all_names_from_selling_page() 132 | # 133 | # 134 | # """Edit domain sale description""" 135 | # new_description = 'New desc' 136 | # domain = 'test_domain' 137 | # test.edit_domain_sale_description(domain, new_description) 138 | # 139 | # """Get the list of all names I am selling with urls on namebase""" 140 | # test.get_domains_on_sale() 141 | -------------------------------------------------------------------------------- /namebase_marketplace/marketplace.py: -------------------------------------------------------------------------------- 1 | """ 2 | Description: 3 | Implements Python client library for Namebase marketplace API. 4 | """ 5 | from namebase_marketplace.enums import Endpoint, Utils 6 | from namebase_marketplace.utils import Request 7 | 8 | import requests 9 | import urllib.parse 10 | import json 11 | 12 | DEFAULT_API_ROOT = "https://www.namebase.io" 13 | 14 | 15 | def _get_cookies(email, pwd): 16 | if email is None or pwd is None: 17 | return None 18 | params = { 19 | 'email': email, 20 | 'password': pwd, 21 | 'token': '' 22 | } 23 | res = requests.post(DEFAULT_API_ROOT + Endpoint.LOGIN, params=params) 24 | cookies = res.cookies.get_dict() 25 | return cookies 26 | 27 | 28 | def encode_dict(dictionary, lower=True): 29 | if dictionary: 30 | lowered_dict = dict([(k, str(v).lower() if lower else str(v)) for k, v in dictionary.items()]) 31 | return urllib.parse.urlencode(lowered_dict) 32 | else: 33 | return '' 34 | 35 | 36 | class Marketplace: 37 | def __init__(self, email=None, pwd=None, namebase_cookie=None, api_root=DEFAULT_API_ROOT): 38 | headers = { 39 | "Accept": 'application/json', 40 | "Content-Type": 'application/json', 41 | } 42 | 43 | self.cookies = _get_cookies(email=email, pwd=pwd) if not namebase_cookie else {"namebase-main" : namebase_cookie} 44 | self.request = Request(api_base_url=api_root, 45 | headers=headers, 46 | cookies=self.cookies, 47 | timeout=30) 48 | 49 | def get_user_info(self): 50 | """" GET USER INFO """ 51 | return self.request.get(Endpoint.USER_INFO) 52 | 53 | def get_marketplace_domains(self, offset=0, options=None): 54 | """ Returns 100 sorted names, paginated by an offset parameter. For example, offset=0 will get the first 100 55 | listings and offset=100 will return listings 101-200. 56 | 57 | ref: https://github.com/namebasehq/api-documentation/blob/master/marketplace-api.md#parameters 58 | """ 59 | 60 | mark = '?' 61 | if options is None: 62 | options = {} 63 | mark = '' 64 | return self.request.get(Endpoint.MARKETPLACE + f'{offset}{mark}{encode_dict(options)}') 65 | 66 | def get_sale_history(self, offset=0, options=None): 67 | mark = '?' 68 | if options is None: 69 | options = {} 70 | mark = '' 71 | return self.request.get(Endpoint.SALE_HISTORY + f'{offset}{mark}{encode_dict(options)}') 72 | 73 | def get_domain_sale_history(self, domain: str): 74 | return self.request.get(Endpoint.DOMAIN_HISTORY + f'{domain}' + Utils.HISTORY) 75 | 76 | def list_domain(self, domain: str, amount, description="", asset="HNS", options={}): 77 | """ 78 | @:param options: dict 79 | 80 | You can send options to this endpoint as an example: 81 | options = {"amount":"4344","asset":"HNS","description":"test"} 82 | """ 83 | params = {"amount": Utils.parse_bid(amount), "asset": asset, "description": description} 84 | mark = '?' 85 | if options is None: 86 | options = {} 87 | mark = '' 88 | return self.request.post(Endpoint.DOMAIN_HISTORY + f'{domain}{Utils.LIST}{mark}{encode_dict(options)}', 89 | data=params, json_data=params) 90 | 91 | def update_domain(self, domain: str, amount, description="", asset="HNS", options={}): 92 | """ 93 | @:param options: dict 94 | 95 | You can send options to this endpoint as an example: 96 | options = {"amount":"4344","asset":"HNS","description":"test"} 97 | """ 98 | return self.list_domain(domain=domain, amount=amount, description=description, asset=asset, options=options) 99 | 100 | def cancel_listing(self, domain: str): 101 | """ Removes domain from marketplace. """ 102 | return self.request.post(Endpoint.DOMAIN_HISTORY + f'{domain}{Utils.CANCEL}', data={}, json_data={}) 103 | 104 | def purchase_now(self, domain: str, listing_id: str): 105 | params = {"listingId": listing_id} 106 | return self.request.post(Endpoint.DOMAIN_HISTORY + f'{domain}{Utils.BUY_NOW}', data=params, json_data=params) 107 | 108 | def open_bid(self, domain: str, bid_amount, blind_amount): 109 | params = { 110 | "bidAmount": Utils.parse_bid(amount=bid_amount), 111 | "blindAmount": Utils.parse_bid(amount=blind_amount) 112 | } 113 | 114 | return self.request.post(Endpoint.OPEN_BID + f'{domain}{Utils.BID}', data=params) 115 | 116 | def create_bid(self, domain: str, bid_amount, blind_amount): 117 | """@Wrapper method""" 118 | return self.open_bid(domain=domain, bid_amount=bid_amount, blind_amount=blind_amount) 119 | 120 | def get_ending_soon(self, offset=0, options=None): 121 | mark = '?' 122 | if options is None: 123 | options = {} 124 | mark = '' 125 | return self.request.get(Endpoint.ENDING_SOON + f'{offset}{mark}{encode_dict(options)}') 126 | 127 | def make_offer(self, domain: str, amount): 128 | params = {"buyOfferAmount": Utils.parse_bid(amount=amount)} 129 | return self.request.post(Endpoint.MAKE_OFFER + f'{domain}{Utils.BID}', data=params, json_data=params) 130 | 131 | def get_domain_info(self, domain: str): 132 | return self.request.get(Endpoint.GET_DOMAIN + f'{domain}') 133 | 134 | def get_domain_price(self, domain: str): 135 | res = self.request.get(Endpoint.MAKE_OFFER + f'{domain}') 136 | if not res['listing']: 137 | raise Exception("Domain is not listed.") 138 | else: 139 | return Utils.get_real_amount(res['listing']['amount']) 140 | 141 | def add_to_watchlist(self, domain: str): 142 | return self.request.post(Endpoint.WATCH_DOMAIN + f'{domain}', params={}, data={}) # as in namebase 143 | 144 | def remove_from_watchlist(self, domain: str): 145 | return self.add_to_watchlist(domain=domain) 146 | 147 | def get_my_domains(self, offset=0, options={}): 148 | if not options: 149 | options = "sortKey=acquiredAt&sortDirection=desc" 150 | url = Endpoint.MY_DOMAINS + f'/{offset}?{options}' 151 | response = self.request.get(url) 152 | response_domains = response['domains'] 153 | domains = [] 154 | while len(response_domains) > 0: 155 | [domains.append(i) for i in response_domains] 156 | offset += 1 157 | url = Endpoint.MY_DOMAINS + f'/{offset}?{options}' 158 | response_domains = self.request.get(url) 159 | response_domains = response_domains['domains'] 160 | return domains 161 | 162 | def get_my_onsale_domains(self): 163 | return self.request.get(Endpoint.MY_SALE_DOMAINS) 164 | 165 | def consent_offers(self, domain: str, consent: bool): 166 | params = {"doesConsentToOffers": consent} 167 | return self.request.post(Endpoint.DOMAIN_HISTORY + f'{domain}{Utils.CONSENT}', data=params, 168 | json_data=params) # as in namebase 169 | 170 | def transfer_domain_on_chain(self, domain: str, hns_address: str): 171 | """ 172 | Test response: {"transferId":"","type":"internal","success":true} 173 | """ 174 | params = {"address" : hns_address} 175 | return self.request.post(Endpoint.API_DOMAINS + f'{domain}' + Utils.TRANSFER, data=params, json_data=params) 176 | 177 | def get_offers(self): 178 | query_string_params = { 179 | 'offset' : 0, 180 | 'sortKey': "createdAt", 181 | 'sortDirection': 'desc' 182 | } 183 | # default offset is set to 15 per request 184 | res = self.request.get(Endpoint.OFFERS_RECEIVED + f'?{encode_dict(query_string_params, lower=False)}') 185 | n_domains = res['totalCount'] 186 | domains = res['domains'] 187 | doms = [] 188 | while n_domains > 0: 189 | for domain in domains: 190 | name = domain['domain'] 191 | highestOffer = domain['highestCurrentOffer'] 192 | domainOwnerId = domain['domainOwnerId'] 193 | domainInfo = { 194 | "name": name, 195 | "offer": highestOffer, 196 | "ownerId": domainOwnerId 197 | } 198 | doms.append(domainInfo) 199 | query_string_params['offset'] = query_string_params['offset'] + 15 200 | n_domains = n_domains - 15 201 | res = self.request.get(Endpoint.OFFERS_RECEIVED + f'?{encode_dict(query_string_params, lower=False)}') 202 | domains = res['domains'] 203 | 204 | return doms 205 | def accept_offer(self, offer_id): 206 | params = { 207 | 'bidId': offer_id 208 | } 209 | return self.request.post(Endpoint.ACCEPT_OFFER_BID, data=params, json_data=params) 210 | def get_offers_domain_history(self, domainOwnerId): 211 | params = { 212 | 'domainOwnerId' : domainOwnerId 213 | } 214 | return self.request.get(Endpoint.OFFERS_HISTORY + f'?{encode_dict(params, lower=False)}') --------------------------------------------------------------------------------