├── .gitignore ├── README.md ├── config.py ├── data ├── abi │ └── daily_claim_abi.json ├── private_keys.example.txt └── proxies.example.txt ├── main.py ├── modules ├── account.py ├── executor.py ├── generate_wallets.py ├── utils.py └── withdraw_from_binance.py ├── poetry.lock ├── pyproject.toml ├── requirements.txt └── settings.py /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | wheels/ 23 | share/python-wheels/ 24 | *.egg-info/ 25 | .installed.cfg 26 | *.egg 27 | MANIFEST 28 | 29 | # PyInstaller 30 | # Usually these files are written by a python script from a template 31 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 32 | *.manifest 33 | *.spec 34 | 35 | # Installer logs 36 | pip-log.txt 37 | pip-delete-this-directory.txt 38 | 39 | # Unit test / coverage reports 40 | htmlcov/ 41 | .tox/ 42 | .nox/ 43 | .coverage 44 | .coverage.* 45 | .cache 46 | nosetests.xml 47 | coverage.xml 48 | *.cover 49 | *.py,cover 50 | .hypothesis/ 51 | .pytest_cache/ 52 | cover/ 53 | 54 | # Translations 55 | *.mo 56 | *.pot 57 | 58 | # Django stuff: 59 | *.log 60 | local_settings.py 61 | db.sqlite3 62 | db.sqlite3-journal 63 | 64 | # Flask stuff: 65 | instance/ 66 | .webassets-cache 67 | 68 | # Scrapy stuff: 69 | .scrapy 70 | 71 | # Sphinx documentation 72 | docs/_build/ 73 | 74 | # PyBuilder 75 | .pybuilder/ 76 | target/ 77 | 78 | # Jupyter Notebook 79 | .ipynb_checkpoints 80 | 81 | # IPython 82 | profile_default/ 83 | ipython_config.py 84 | 85 | # pyenv 86 | # For a library or package, you might want to ignore these files since the code is 87 | # intended to run in multiple environments; otherwise, check them in: 88 | # .python-version 89 | 90 | # pipenv 91 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 92 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 93 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 94 | # install all needed dependencies. 95 | #Pipfile.lock 96 | 97 | # poetry 98 | # Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control. 99 | # This is especially recommended for binary packages to ensure reproducibility, and is more 100 | # commonly ignored for libraries. 101 | # https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control 102 | #poetry.lock 103 | 104 | # pdm 105 | # Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control. 106 | #pdm.lock 107 | # pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it 108 | # in version control. 109 | # https://pdm.fming.dev/#use-with-ide 110 | .pdm.toml 111 | 112 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm 113 | __pypackages__/ 114 | 115 | # Celery stuff 116 | celerybeat-schedule 117 | celerybeat.pid 118 | 119 | # SageMath parsed files 120 | *.sage.py 121 | 122 | # Environments 123 | .env 124 | .venv 125 | env/ 126 | venv/ 127 | ENV/ 128 | env.bak/ 129 | venv.bak/ 130 | 131 | # Spyder project settings 132 | .spyderproject 133 | .spyproject 134 | 135 | # Rope project settings 136 | .ropeproject 137 | 138 | # mkdocs documentation 139 | /site 140 | 141 | # mypy 142 | .mypy_cache/ 143 | .dmypy.json 144 | dmypy.json 145 | 146 | # Pyre type checker 147 | .pyre/ 148 | 149 | # pytype static type analyzer 150 | .pytype/ 151 | 152 | # Cython debug symbols 153 | cython_debug/ 154 | 155 | # PyCharm 156 | # JetBrains specific template is maintained in a separate JetBrains.gitignore that can 157 | # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore 158 | # and can be added to the global gitignore or merged into this file. For a more nuclear 159 | # option (not recommended) you can uncomment the following to ignore the entire idea folder. 160 | #.idea/ 161 | 162 | cached_user_agents.json 163 | generated_addresses.txt 164 | generated_keys.txt 165 | generated_seeds.txt 166 | private_keys.txt 167 | proxies.txt 168 | stats.json -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Script for StarryNift 2 | 3 | TG channel - https://t.me/easypeoff 4 | 5 | ## Capabilities 6 | 7 | 1) Generate new wallets 8 | 9 | 2) Withdraw BNB from Binance to BNB chain or opBNB chain 10 | 11 | 3) Register an account on StarryNift using your referral code 12 | 13 | 4) Daily check ins 14 | 15 | 5) Complete quests (Follow and being 10 minutes online are now supported) 16 | 17 | 6) Use free daily ruffles (free 0 - 50xp on daily basis) 18 | 19 | 7) Get account stats (UserId, Level, XP, ReferralCode) 20 | 21 | Other: 22 | 23 | - proxies 24 | 25 | - user agents are being randomly generated and cached for each wallet after the first use of the wallet in data/cached_user_agents.json. Every next execution it will use the same user agent it was using previously for this particular wallet 26 | 27 | - configurable RPCs 28 | 29 | ## Installation 30 | 31 | Install python3.9 or higher 32 | 33 | In project directory run: 34 | ``` 35 | pip install -r requirements.txt 36 | ``` 37 | 38 | ## Settings 39 | 40 | Input private keys in data/private_keys.txt 41 | 42 | Input proxies in data/proxies.txt 43 | 44 | Read and configure script in settings.py 45 | 46 | ## Run 47 | ``` 48 | python main.py 49 | ``` 50 | -------------------------------------------------------------------------------- /config.py: -------------------------------------------------------------------------------- 1 | import json 2 | 3 | 4 | with open("data/private_keys.txt", "r") as f: 5 | PRIVATE_KEYS = f.read().splitlines() 6 | 7 | 8 | with open("data/proxies.txt", "r") as f: 9 | PROXIES = f.read().splitlines() 10 | 11 | 12 | with open("data/abi/daily_claim_abi.json", "r") as f: 13 | DAILY_CLAIM_ABI = json.load(f) 14 | 15 | try: 16 | with open("data/cached_user_agents.json", "r") as f: 17 | CACHED_USER_AGENTS = json.load(f) 18 | except FileNotFoundError: 19 | CACHED_USER_AGENTS = {} 20 | -------------------------------------------------------------------------------- /data/abi/daily_claim_abi.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "inputs": [], 4 | "stateMutability": "nonpayable", 5 | "type": "constructor" 6 | }, 7 | { 8 | "anonymous": false, 9 | "inputs": [ 10 | { 11 | "indexed": true, 12 | "internalType": "address", 13 | "name": "user", 14 | "type": "address" 15 | }, 16 | { 17 | "indexed": false, 18 | "internalType": "uint256", 19 | "name": "date", 20 | "type": "uint256" 21 | }, 22 | { 23 | "indexed": false, 24 | "internalType": "uint256", 25 | "name": "consecutiveDays", 26 | "type": "uint256" 27 | }, 28 | { 29 | "indexed": false, 30 | "internalType": "uint256", 31 | "name": "rewardXP", 32 | "type": "uint256" 33 | } 34 | ], 35 | "name": "UserSignedIn", 36 | "type": "event" 37 | }, 38 | { 39 | "inputs": [], 40 | "name": "admin", 41 | "outputs": [ 42 | { 43 | "internalType": "address", 44 | "name": "", 45 | "type": "address" 46 | } 47 | ], 48 | "stateMutability": "view", 49 | "type": "function" 50 | }, 51 | { 52 | "inputs": [ 53 | { 54 | "internalType": "address", 55 | "name": "user", 56 | "type": "address" 57 | } 58 | ], 59 | "name": "getConsecutiveSignInDays", 60 | "outputs": [ 61 | { 62 | "internalType": "uint256", 63 | "name": "", 64 | "type": "uint256" 65 | } 66 | ], 67 | "stateMutability": "view", 68 | "type": "function" 69 | }, 70 | { 71 | "inputs": [ 72 | { 73 | "internalType": "address", 74 | "name": "user", 75 | "type": "address" 76 | } 77 | ], 78 | "name": "getLastSignInDate", 79 | "outputs": [ 80 | { 81 | "internalType": "uint256", 82 | "name": "", 83 | "type": "uint256" 84 | } 85 | ], 86 | "stateMutability": "view", 87 | "type": "function" 88 | }, 89 | { 90 | "inputs": [ 91 | { 92 | "internalType": "uint256", 93 | "name": "day", 94 | "type": "uint256" 95 | } 96 | ], 97 | "name": "getRewardXP", 98 | "outputs": [ 99 | { 100 | "internalType": "uint256", 101 | "name": "", 102 | "type": "uint256" 103 | } 104 | ], 105 | "stateMutability": "view", 106 | "type": "function" 107 | }, 108 | { 109 | "inputs": [], 110 | "name": "getSignInInterval", 111 | "outputs": [ 112 | { 113 | "internalType": "uint256", 114 | "name": "", 115 | "type": "uint256" 116 | } 117 | ], 118 | "stateMutability": "view", 119 | "type": "function" 120 | }, 121 | { 122 | "inputs": [ 123 | { 124 | "internalType": "address", 125 | "name": "user", 126 | "type": "address" 127 | } 128 | ], 129 | "name": "getTimeUntilNextSignIn", 130 | "outputs": [ 131 | { 132 | "internalType": "uint256", 133 | "name": "", 134 | "type": "uint256" 135 | } 136 | ], 137 | "stateMutability": "view", 138 | "type": "function" 139 | }, 140 | { 141 | "inputs": [ 142 | { 143 | "internalType": "address", 144 | "name": "user", 145 | "type": "address" 146 | } 147 | ], 148 | "name": "hasBrokenStreak", 149 | "outputs": [ 150 | { 151 | "internalType": "bool", 152 | "name": "", 153 | "type": "bool" 154 | } 155 | ], 156 | "stateMutability": "view", 157 | "type": "function" 158 | }, 159 | { 160 | "inputs": [], 161 | "name": "setDefaultRewards", 162 | "outputs": [], 163 | "stateMutability": "nonpayable", 164 | "type": "function" 165 | }, 166 | { 167 | "inputs": [ 168 | { 169 | "internalType": "uint256", 170 | "name": "_maxDays", 171 | "type": "uint256" 172 | } 173 | ], 174 | "name": "setMaxConsecutiveDays", 175 | "outputs": [], 176 | "stateMutability": "nonpayable", 177 | "type": "function" 178 | }, 179 | { 180 | "inputs": [ 181 | { 182 | "internalType": "uint256", 183 | "name": "_interval", 184 | "type": "uint256" 185 | } 186 | ], 187 | "name": "setSignInInterval", 188 | "outputs": [], 189 | "stateMutability": "nonpayable", 190 | "type": "function" 191 | }, 192 | { 193 | "inputs": [ 194 | { 195 | "internalType": "uint256", 196 | "name": "day", 197 | "type": "uint256" 198 | }, 199 | { 200 | "internalType": "uint256", 201 | "name": "rewardXP", 202 | "type": "uint256" 203 | } 204 | ], 205 | "name": "setSignInReward", 206 | "outputs": [], 207 | "stateMutability": "nonpayable", 208 | "type": "function" 209 | }, 210 | { 211 | "inputs": [], 212 | "name": "signIn", 213 | "outputs": [], 214 | "stateMutability": "nonpayable", 215 | "type": "function" 216 | }, 217 | { 218 | "inputs": [ 219 | { 220 | "internalType": "uint256", 221 | "name": "day", 222 | "type": "uint256" 223 | }, 224 | { 225 | "internalType": "uint256", 226 | "name": "reward", 227 | "type": "uint256" 228 | } 229 | ], 230 | "name": "updateSignReward", 231 | "outputs": [], 232 | "stateMutability": "nonpayable", 233 | "type": "function" 234 | } 235 | ] -------------------------------------------------------------------------------- /data/private_keys.example.txt: -------------------------------------------------------------------------------- 1 | key1 2 | key2 -------------------------------------------------------------------------------- /data/proxies.example.txt: -------------------------------------------------------------------------------- 1 | login:pass@host:port 2 | login:pass@host:port -------------------------------------------------------------------------------- /main.py: -------------------------------------------------------------------------------- 1 | import asyncio 2 | import sys 3 | from questionary import Choice 4 | import questionary 5 | from config import PRIVATE_KEYS, PROXIES 6 | from modules.executor import Executor 7 | 8 | 9 | def get_module(executor: Executor): 10 | choices = [ 11 | Choice(f"{i}) {key}", value) 12 | for i, (key, value) in enumerate( 13 | { 14 | "Generate wallets": executor.generate_wallets, 15 | "Withdraw BNB from Binance": executor.withdraw_from_binance, 16 | "StarryNift module": executor.run_starrynift, 17 | "Get accounts stats": executor.get_accounts_stats, 18 | "Exit": "exit", 19 | }.items(), 20 | start=1, 21 | ) 22 | ] 23 | result = questionary.select( 24 | "Select a method to get started", 25 | choices=choices, 26 | qmark="🛠 ", 27 | pointer="✅ ", 28 | ).ask() 29 | if result == "exit": 30 | sys.exit() 31 | return result 32 | 33 | 34 | async def main(module): 35 | await module() 36 | 37 | 38 | if __name__ == "__main__": 39 | executor = Executor(PRIVATE_KEYS, PROXIES) 40 | module = get_module(executor) 41 | asyncio.run(main(module)) 42 | -------------------------------------------------------------------------------- /modules/account.py: -------------------------------------------------------------------------------- 1 | import asyncio 2 | import random 3 | import time 4 | from eth_account import Account as EthAccount 5 | from eth_account.messages import encode_defunct 6 | from loguru import logger 7 | from modules.utils import retry 8 | from settings import BNB_RPC, DISABLE_SSL, OPBNB_RPC, REF_LINK, USER_IDS_TO_FOLLOW 9 | from config import DAILY_CLAIM_ABI 10 | import aiohttp 11 | 12 | import datetime 13 | 14 | from web3 import AsyncWeb3 15 | from web3.middleware import async_geth_poa_middleware 16 | from web3.exceptions import TransactionNotFound 17 | 18 | 19 | class Account: 20 | def __init__(self, id: int, key: str, proxy: str, user_agent: str): 21 | self.headers = { 22 | "Accept-Encoding": "gzip, deflate, br", 23 | "Accept-Language": "ru;q=0.9,en-US;q=0.8,en;q=0.7", 24 | "Connection": "keep-alive", 25 | "Content-Type": "application/json;charset=UTF-8", 26 | "Host": "api.starrynift.art", 27 | "Origin": "https://starrynift.art", 28 | "Referer": "https://starrynift.art/", 29 | "Sec-Ch-Ua-Mobile": "?0", 30 | "Sec-Ch-Ua-Platform": '"Windows"', 31 | "Sec-Fetch-Dest": "empty", 32 | "Sec-Fetch-Mode": "cors", 33 | "Sec-Fetch-Site": "same-site", 34 | "User-Agent": user_agent, 35 | } 36 | 37 | self.id = id 38 | self.key = key 39 | self.proxy = proxy 40 | self.account = EthAccount.from_key(self.key) 41 | self.address = self.account.address 42 | self.user_agent = user_agent 43 | 44 | self.referral_code = REF_LINK.split("=")[1] 45 | 46 | self.w3 = AsyncWeb3( 47 | AsyncWeb3.AsyncHTTPProvider(BNB_RPC), 48 | middlewares=[async_geth_poa_middleware], 49 | ) 50 | 51 | self.quests_mapping = { 52 | "Follow": self.follow_user, 53 | "Online": self.complete_online_quest, 54 | } 55 | 56 | self.user_id = None 57 | 58 | async def make_request(self, method, url, **kwargs): 59 | if DISABLE_SSL: 60 | kwargs["ssl"] = False 61 | 62 | async with aiohttp.ClientSession( 63 | headers=self.headers, trust_env=True 64 | ) as session: 65 | return await session.request( 66 | method, url, proxy=f"http://{self.proxy}", **kwargs 67 | ) 68 | 69 | def get_current_date(self, utc=False): 70 | if utc: 71 | return datetime.datetime.utcnow().strftime("%Y%m%d") 72 | return datetime.datetime.now().strftime("%Y-%m-%d") 73 | 74 | def get_utc_timestamp(self): 75 | return ( 76 | datetime.datetime.now(datetime.timezone.utc).strftime( 77 | "%Y-%m-%dT%H:%M:%S.%f" 78 | )[:-3] 79 | + "Z" 80 | ) 81 | 82 | async def wait_until_tx_finished( 83 | self, hash: str, max_wait_time=480, web3=None 84 | ) -> None: 85 | if web3 is None: 86 | web3 = self.w3 87 | 88 | start_time = time.time() 89 | while True: 90 | try: 91 | receipts = await web3.eth.get_transaction_receipt(hash) 92 | status = receipts.get("status") 93 | if status == 1: 94 | logger.success(f"[{self.address}] {hash.hex()} successfully!") 95 | return receipts["transactionHash"].hex() 96 | elif status is None: 97 | await asyncio.sleep(0.3) 98 | else: 99 | logger.error( 100 | f"[{self.id}][{self.address}] {hash.hex()} transaction failed! {receipts}" 101 | ) 102 | return None 103 | except TransactionNotFound: 104 | if time.time() - start_time > max_wait_time: 105 | logger.error( 106 | f"[{self.id}][{self.address}]{hash.hex()} transaction failed!" 107 | ) 108 | return None 109 | await asyncio.sleep(1) 110 | 111 | async def send_data_tx( 112 | self, to, from_, data, gas_price=None, gas_limit=None, nonce=None, chain_id=None 113 | ): 114 | if chain_id == 56: 115 | web3 = self.w3 116 | elif chain_id == 204: 117 | web3 = AsyncWeb3( 118 | AsyncWeb3.AsyncHTTPProvider(OPBNB_RPC), 119 | middlewares=[async_geth_poa_middleware], 120 | ) 121 | else: 122 | raise ValueError("Invalid chain id") 123 | 124 | transaction = { 125 | "to": to, 126 | "from": from_, 127 | "data": data, 128 | "gasPrice": gas_price or web3.to_wei(await web3.eth.gas_price, "gwei"), 129 | "gas": gas_limit or await web3.eth.estimate_gas({"to": to, "data": data}), 130 | "nonce": nonce or await web3.eth.get_transaction_count(self.address), 131 | "chainId": chain_id or await web3.eth.chain_id, 132 | } 133 | 134 | signed_transaction = web3.eth.account.sign_transaction(transaction, self.key) 135 | try: 136 | transaction_hash = await web3.eth.send_raw_transaction( 137 | signed_transaction.rawTransaction 138 | ) 139 | tx_hash = await self.wait_until_tx_finished( 140 | transaction_hash, max_wait_time=480, web3=web3 141 | ) 142 | if tx_hash is None: 143 | return False, None 144 | return True, tx_hash 145 | except Exception as e: 146 | logger.error(f"[{self.id}][{self.address}] Error while sending tx | {e}") 147 | return e, None 148 | 149 | def sign_msg(self, msg): 150 | return self.w3.eth.account.sign_message( 151 | (encode_defunct(text=msg)), self.key 152 | ).signature.hex() 153 | 154 | async def get_login_signature_message(self): 155 | req = await self.make_request( 156 | "get", 157 | f"https://api.starrynift.art/api-v2/starryverse/auth/wallet/challenge?address={self.address}", 158 | ) 159 | message = (await req.json()).get("message") 160 | if message is None: 161 | raise RuntimeError("Error while getting signature message") 162 | return message 163 | 164 | @retry 165 | async def get_mint_signature(self): 166 | response = await self.make_request( 167 | "post", 168 | "https://api.starrynift.art/api-v2/citizenship/citizenship-card/sign", 169 | json={"category": 1}, 170 | ) 171 | 172 | if response.status not in (200, 201): 173 | raise RuntimeError( 174 | f"Error while getting mint signature message | {await response.text()}" 175 | ) 176 | 177 | return (await response.json()).get("signature") 178 | 179 | @retry 180 | async def login(self): 181 | logger.info(f"[{self.id}][{self.address}] Logging in...") 182 | 183 | signature = self.sign_msg(await self.get_login_signature_message()) 184 | 185 | response = await self.make_request( 186 | "post", 187 | "https://api.starrynift.art/api-v2/starryverse/auth/wallet/evm/login", 188 | json={ 189 | "address": self.address, 190 | "signature": signature, 191 | "referralCode": self.referral_code, 192 | "referralSource": 0, 193 | }, 194 | ) 195 | res_json = await response.json() 196 | auth_token = res_json.get("token") 197 | 198 | if auth_token: 199 | self.headers["Authorization"] = f"Bearer {auth_token}" 200 | else: 201 | raise RuntimeError(f"Error while logging in") 202 | 203 | info = await self.get_current_user_info() 204 | self.user_id = info["userId"] 205 | 206 | return bool(auth_token) 207 | 208 | async def mint_nft_pass(self): 209 | logger.info(f"[{self.id}][{self.address}] Minting pass...") 210 | 211 | signature = await self.get_mint_signature() 212 | 213 | status, tx_hash = await self.send_mint_tx(signature) 214 | 215 | if status is True and await self.send_mint_tx_hash(tx_hash): 216 | logger.success(f"[{self.id}][{self.address}] | Pass minted: {tx_hash}") 217 | return True 218 | 219 | logger.error( 220 | f"[{self.id}][{self.address}] | Error while minting pass: {status}" 221 | ) 222 | return False 223 | 224 | @retry 225 | async def send_mint_tx(self, signature): 226 | return await self.send_data_tx( 227 | to="0xC92Df682A8DC28717C92D7B5832376e6aC15a90D", 228 | from_=self.address, 229 | data=f"0xf75e03840000000000000000000000000000000000000000000000000000000000000020000000000000000000000000{self.address[2:]}000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000041{signature[2:]}00000000000000000000000000000000000000000000000000000000000000", 230 | gas_price=self.w3.to_wei(2, "gwei"), 231 | gas_limit=210000, 232 | chain_id=56, 233 | ) 234 | 235 | @retry 236 | async def check_if_pass_is_minted(self): 237 | logger.info( 238 | f"[{self.id}][{self.address}] Checking if pass has already been minted..." 239 | ) 240 | 241 | response = await self.make_request( 242 | "get", 243 | f"https://api.starrynift.art/api-v2/citizenship/citizenship-card/check-card-minted?address={self.address}", 244 | ) 245 | 246 | if response.status not in (200, 201): 247 | raise RuntimeError( 248 | f"Error while checking if pass is minted | {await response.text()}" 249 | ) 250 | 251 | return (await response.json()).get("isMinted") 252 | 253 | @retry 254 | async def send_mint_tx_hash(self, tx_hash): 255 | resp = await self.make_request( 256 | "post", 257 | "https://api.starrynift.art/api-v2/webhook/confirm/citizenship/mint", 258 | json={"txHash": tx_hash}, 259 | ) 260 | if resp.status not in (200, 201) or (await resp.json()).get("ok") != 1: 261 | raise RuntimeError( 262 | f"Error while sending mint tx hash | {await resp.text()}" 263 | ) 264 | 265 | return True 266 | 267 | async def daily_claim(self): 268 | logger.info(f"[{self.id}][{self.address}] Checking in...") 269 | 270 | time_to_claim = await self.get_daily_claim_time() 271 | if time_to_claim > 0: 272 | logger.info( 273 | f"[{self.id}][{self.address}] Next claim in {datetime.timedelta(seconds=time_to_claim)}" 274 | ) 275 | return 276 | 277 | result = await self.send_daily_tx() 278 | if result is None: 279 | logger.error(f"[{self.id}][{self.address}] Failed daily check in") 280 | return 281 | 282 | status, tx_hash = result 283 | 284 | if status is True and await self.send_daily_tx_hash(tx_hash): 285 | logger.success(f"[{self.id}][{self.address}] Successfully daily checked in") 286 | else: 287 | logger.error(f"[{self.id}][{self.address}] Failed daily check in") 288 | 289 | @retry 290 | async def send_daily_tx(self): 291 | status, hash = await self.send_data_tx( 292 | to="0xE3bA0072d1da98269133852fba1795419D72BaF4", 293 | from_=self.address, 294 | data=f"0x9e4cda43", 295 | gas_price=self.w3.to_wei(2, "gwei"), 296 | gas_limit=100000, 297 | chain_id=56, 298 | ) 299 | 300 | if not status: 301 | raise RuntimeError(f"Error while sending daily tx | {hash}") 302 | 303 | return status, hash 304 | 305 | @retry 306 | async def send_daily_tx_hash(self, tx_hash): 307 | resp = await self.make_request( 308 | "post", 309 | "https://api.starrynift.art/api-v2/webhook/confirm/daily-checkin/checkin", 310 | json={"txHash": tx_hash}, 311 | ) 312 | 313 | if resp.status not in (200, 201) or (await resp.json()).get("ok") != 1: 314 | raise RuntimeError( 315 | f"Error while sending daily tx hash | {await resp.text()}" 316 | ) 317 | 318 | return True 319 | 320 | @retry 321 | async def get_daily_claim_time(self): 322 | contract = self.w3.eth.contract( 323 | address=self.w3.to_checksum_address( 324 | "0xe3ba0072d1da98269133852fba1795419d72baf4" 325 | ), 326 | abi=DAILY_CLAIM_ABI, 327 | ) 328 | return await contract.functions.getTimeUntilNextSignIn(self.address).call() 329 | 330 | async def complete_quests(self): 331 | quests = await self.get_quests() 332 | 333 | for item in quests: 334 | quest = item["name"] 335 | if not item["completed"]: 336 | logger.info(f"[{self.id}][{self.address}] Completing quest: {quest}") 337 | try: 338 | func = self.quests_mapping.get(quest) 339 | if func is None: 340 | logger.warning(f"Quest {quest} is not supported") 341 | continue 342 | result = await func() 343 | if result is False: 344 | logger.error( 345 | f"[{self.id}][{self.address}] {quest} Quest Failed" 346 | ) 347 | else: 348 | logger.success( 349 | f"[{self.id}][{self.address}] {quest} Quest Completed" 350 | ) 351 | except RuntimeError as e: 352 | logger.error( 353 | f"[{self.id}][{self.address}] {quest} Quest Failed | {e}" 354 | ) 355 | else: 356 | logger.info( 357 | f"[{self.id}][{self.address}] {quest} Quest Already Compeleted" 358 | ) 359 | 360 | @retry 361 | async def get_quests(self): 362 | response = await self.make_request( 363 | "get", 364 | f"https://api.starrynift.art/api-v2/citizenship/citizenship-card/daily-tasks?page=1&page_size=10", 365 | ) 366 | 367 | if response.status not in (200, 201) or "items" not in await response.json(): 368 | raise RuntimeError(f"Error while getting quests | {await response.text()}") 369 | 370 | return (await response.json()).get("items") 371 | 372 | @retry 373 | async def follow_user(self): 374 | user_to_follow = None 375 | for user_id in USER_IDS_TO_FOLLOW: 376 | info = await self.get_user_info(user_id) 377 | if info["userId"] != self.user_id and not info["isFollow"]: 378 | user_to_follow = user_id 379 | break 380 | 381 | if user_to_follow is None: 382 | logger.error( 383 | f"[{self.id}][{self.address}] Already followed all users. Can't complete quest" 384 | ) 385 | return False 386 | 387 | response = await self.make_request( 388 | "post", 389 | "https://api.starrynift.art/api-v2/starryverse/user/follow", 390 | json={"userId": user_to_follow}, 391 | ) 392 | 393 | if response.status not in (200, 201) or (await response.json()).get("ok") != 1: 394 | raise RuntimeError(f"Error while following user | {await response.text()}") 395 | 396 | return True 397 | 398 | @retry 399 | async def get_user_info(self, user_id): 400 | response = await self.make_request( 401 | "get", 402 | f"https://api.starrynift.art/api-v2/starryverse/character/user/{user_id}", 403 | ) 404 | 405 | if response.status not in (200, 201): 406 | raise RuntimeError( 407 | f"Error while getting user info | {await response.text()}" 408 | ) 409 | 410 | return await response.json() 411 | 412 | @retry 413 | async def get_current_user_info(self): 414 | response = await self.make_request( 415 | "get", 416 | f"https://api.starrynift.art/api-v2/starryverse/character", 417 | ) 418 | 419 | if response.status not in (200, 201): 420 | raise RuntimeError( 421 | f"Error while getting user info | {await response.text()}" 422 | ) 423 | 424 | return await response.json() 425 | 426 | async def complete_online_quest(self): 427 | logger.info(f"[{self.id}][{self.address}] It would take about 10 minutes...") 428 | for i in range(21): 429 | await self.send_ping() 430 | await asyncio.sleep(30) 431 | 432 | return True 433 | 434 | @retry 435 | async def send_ping(self): 436 | response = await self.make_request( 437 | "get", 438 | f"https://api.starrynift.art/api-v2/space/online/ping", 439 | ) 440 | 441 | if response.status not in (200, 201): 442 | raise RuntimeError(f"Error while sending ping | {await response.text()}") 443 | 444 | return True 445 | 446 | async def get_if_already_ruffled_today(self): 447 | response = await self.make_request( 448 | "post", 449 | f"https://api.starrynift.art/api-v2/citizenship/raffle/status", 450 | json={}, 451 | ) 452 | 453 | if response.status not in (200, 201): 454 | raise RuntimeError( 455 | f"Error while checking if ruffled today | {await response.text()}" 456 | ) 457 | 458 | return (await response.json()).get("used") 459 | 460 | async def ruffle(self): 461 | logger.info(f"[{self.id}][{self.address}] Ruffling...") 462 | 463 | await asyncio.sleep(random.randint(3, 10)) 464 | info = await self.get_ruffle_info() 465 | if info["used"]: 466 | logger.info(f"[{self.id}][{self.address}] Already used free ruffle today") 467 | return 468 | 469 | if not info["signature"]: 470 | logger.error(f"[{self.id}][{self.address}] Daily wasn't completed") 471 | return 472 | logger.info(f"[{self.id}][{self.address}] Ruffle xp: {info['xp']}") 473 | 474 | result = await self.send_ruffle_tx( 475 | xp=info["xp"], 476 | signature=info["signature"], 477 | nonce=info["nonce"], 478 | ) 479 | if result is None: 480 | logger.error(f"[{self.id}][{self.address}] Ruffle failed") 481 | return 482 | 483 | status, tx_hash = result 484 | 485 | await self.send_ruffle_hash(tx_hash) 486 | 487 | logger.success(f"[{self.id}][{self.address}] Ruffle success") 488 | return True 489 | 490 | @retry 491 | async def send_ruffle_tx(self, xp, nonce, signature): 492 | data = ( 493 | "0x9fc96c7e" 494 | "0000000000000000000000000000000000000000000000000000000000000020" 495 | f"000000000000000000000000{self.address[2:]}" 496 | f"{format(xp, '064x')}" 497 | f"{format(int(nonce), '064x')}" 498 | "0000000000000000000000000000000000000000000000000000000000000080" 499 | f"0000000000000000000000000000000000000000000000000000000000000041{signature[2:]}" 500 | "00000000000000000000000000000000000000000000000000000000000000" 501 | ) 502 | 503 | status, tx_hash = await self.send_data_tx( 504 | to=self.w3.to_checksum_address( 505 | "0x557764618fc2f4eca692d422ba79c70f237113e6" 506 | ), 507 | from_=self.address, 508 | data=data, 509 | gas_price=self.w3.to_wei("0.00002", "gwei"), 510 | gas_limit=100000, 511 | chain_id=204, 512 | ) 513 | if not status: 514 | raise RuntimeError(f"Error while sending ruffle tx | {tx_hash}") 515 | 516 | return status, tx_hash 517 | 518 | @retry 519 | async def send_ruffle_hash(self, tx_hash): 520 | response = await self.make_request( 521 | "post", 522 | "https://api.starrynift.art/api-v2/webhook/confirm/raffle/mint", 523 | json={"txHash": tx_hash}, 524 | ) 525 | 526 | if response.status not in (200, 201) or (await response.json()).get("ok") != 1: 527 | raise RuntimeError( 528 | f"Error while sending ruffle tx hash | {await response.text()}" 529 | ) 530 | 531 | return True 532 | 533 | @retry 534 | async def get_ruffle_info(self): 535 | response = await self.make_request( 536 | "post", 537 | f"https://api.starrynift.art/api-v2/citizenship/raffle/status", 538 | json={}, 539 | ) 540 | 541 | if response.status not in (200, 201): 542 | raise RuntimeError( 543 | f"Error while getting ruffle info | {await response.text()}" 544 | ) 545 | 546 | return await response.json() 547 | -------------------------------------------------------------------------------- /modules/executor.py: -------------------------------------------------------------------------------- 1 | import asyncio 2 | import json 3 | import random 4 | from loguru import logger 5 | from fake_useragent import UserAgent 6 | from modules.account import Account 7 | from modules.generate_wallets import generate_wallets 8 | from modules.withdraw_from_binance import withdraw_from_binance 9 | from settings import SHUFFLE_ACCOUNTS, THREADS 10 | from config import CACHED_USER_AGENTS 11 | from modules.utils import sleep 12 | 13 | 14 | class Executor: 15 | def __init__(self, wallets: list[str], proxies: list[str]): 16 | self.accounts = self._load_accounts(wallets, proxies) 17 | 18 | async def generate_wallets(self): 19 | await generate_wallets() 20 | 21 | async def withdraw_from_binance(self): 22 | for i, account in enumerate(self.accounts, start=1): 23 | await withdraw_from_binance(address=account.address, proxy=account.proxy) 24 | 25 | if i != len(self.accounts): 26 | await sleep(account) 27 | 28 | async def run_starrynift(self): 29 | groups = self._generate_groups() 30 | 31 | tasks = [] 32 | for id, group in enumerate(groups): 33 | tasks.append( 34 | asyncio.create_task( 35 | self._run_starrynift(group, id), 36 | name=f"group - {id}", 37 | ) 38 | ) 39 | 40 | await asyncio.gather(*tasks) 41 | 42 | async def _run_starrynift(self, group: list[Account], group_id: int): 43 | for i, account in enumerate(group): 44 | if i != 0 or group_id != 0: 45 | await sleep(account) 46 | 47 | logger.info(f"Running #{account.id} account: {account.address}") 48 | if await account.login(): 49 | if not await account.check_if_pass_is_minted(): 50 | if not await account.mint_nft_pass(): 51 | continue 52 | 53 | await account.daily_claim() 54 | await account.ruffle() 55 | await account.complete_quests() 56 | 57 | async def get_accounts_stats(self): 58 | stats = {} 59 | for i, account in enumerate(self.accounts, start=1): 60 | logger.info(f"[{account.id}][{account.address}] Getting stats...") 61 | if await account.login(): 62 | info = await account.get_current_user_info() 63 | stats[account.address] = { 64 | "userId": info["userId"], 65 | "level": info["level"], 66 | "xp": info["xp"], 67 | "referralCode": info["referralCode"], 68 | } 69 | 70 | with open("data/stats.json", "w") as f: 71 | f.write(json.dumps(stats, indent=4)) 72 | 73 | logger.info("Stats saved to data/stats.json") 74 | 75 | def _generate_groups(self): 76 | global THREADS 77 | 78 | if THREADS <= 0: 79 | THREADS = 1 80 | elif THREADS > len(self.accounts): 81 | THREADS = len(self.accounts) 82 | 83 | group_size = len(self.accounts) // THREADS 84 | remainder = len(self.accounts) % THREADS 85 | 86 | groups = [] 87 | start = 0 88 | for i in range(THREADS): 89 | # Add an extra account to some groups to distribute the remainder 90 | end = start + group_size + (1 if i < remainder else 0) 91 | groups.append(self.accounts[start:end]) 92 | start = end 93 | 94 | return groups 95 | 96 | def _load_accounts(self, wallets: list[str], proxies: list[str]) -> list[Account]: 97 | accounts = [] 98 | for i, (wallet, proxy) in enumerate(zip(wallets, proxies), start=1): 99 | user_agent = CACHED_USER_AGENTS.get(wallet) 100 | 101 | if user_agent is not None: 102 | accounts.append( 103 | Account(id=i, key=wallet, proxy=proxy, user_agent=user_agent) 104 | ) 105 | else: 106 | user_agent = UserAgent(os="windows").random 107 | CACHED_USER_AGENTS[wallet] = user_agent 108 | accounts.append( 109 | Account(id=i, key=wallet, proxy=proxy, user_agent=user_agent) 110 | ) 111 | 112 | with open("data/cached_user_agents.json", "w") as f: 113 | f.write(json.dumps(CACHED_USER_AGENTS, indent=4)) 114 | 115 | if SHUFFLE_ACCOUNTS: 116 | random.shuffle(accounts) 117 | 118 | return accounts 119 | -------------------------------------------------------------------------------- /modules/generate_wallets.py: -------------------------------------------------------------------------------- 1 | from typing import Optional 2 | from loguru import logger 3 | 4 | from hdwallet import BIP44HDWallet 5 | from hdwallet.cryptocurrencies import EthereumMainnet 6 | from hdwallet.derivations import BIP44Derivation 7 | from hdwallet.utils import generate_mnemonic 8 | 9 | 10 | async def generate_wallets(): 11 | num = input("How many wallets do you want to generate? ") 12 | logger.info(f"Generating {num} wallets") 13 | 14 | wallets = { 15 | "mnemonics": [], 16 | "addresses": [], 17 | "keys": [], 18 | } 19 | 20 | for i in range(int(num)): 21 | # Generate english mnemonic words 22 | MNEMONIC: str = generate_mnemonic(language="english", strength=128) 23 | # Secret passphrase/password for mnemonic 24 | PASSPHRASE: Optional[str] = None # "meherett" 25 | 26 | # Initialize Ethereum mainnet BIP44HDWallet 27 | bip44_hdwallet: BIP44HDWallet = BIP44HDWallet(cryptocurrency=EthereumMainnet) 28 | # Get Ethereum BIP44HDWallet from mnemonic 29 | bip44_hdwallet.from_mnemonic( 30 | mnemonic=MNEMONIC, language="english", passphrase=PASSPHRASE 31 | ) 32 | # Clean default BIP44 derivation indexes/paths 33 | bip44_hdwallet.clean_derivation() 34 | mnemonics = bip44_hdwallet.mnemonic() 35 | 36 | # Derivation from Ethereum BIP44 derivation path 37 | bip44_derivation: BIP44Derivation = BIP44Derivation( 38 | cryptocurrency=EthereumMainnet, account=0, change=False, address=0 39 | ) 40 | # Drive Ethereum BIP44HDWallet 41 | bip44_hdwallet.from_path(path=bip44_derivation) 42 | # Print address_index, path, address and private_key 43 | address = bip44_hdwallet.address() 44 | key = bip44_hdwallet.private_key() 45 | # Clean derivation indexes/paths 46 | bip44_hdwallet.clean_derivation() 47 | 48 | wallets["mnemonics"].append(mnemonics) 49 | wallets["addresses"].append(address) 50 | wallets["keys"].append(f"{key}") 51 | 52 | with open(f"data/generated_keys.txt", "w+") as f: 53 | for x in wallets["keys"]: 54 | f.write(f"0x{str(x)}\n") 55 | 56 | with open(f"data/generated_addresses.txt", "w+") as f: 57 | for x in wallets["addresses"]: 58 | f.write(f"{str(x)}\n") 59 | 60 | with open(f"data/generated_seeds.txt", "w+") as f: 61 | for x in wallets["mnemonics"]: 62 | f.write(f"{str(x)}\n") 63 | 64 | logger.success("Done generating wallets") 65 | -------------------------------------------------------------------------------- /modules/utils.py: -------------------------------------------------------------------------------- 1 | import asyncio 2 | import random 3 | import traceback 4 | from loguru import logger 5 | 6 | from settings import MAX_SLEEP, MIN_SLEEP, RETRIES 7 | 8 | 9 | async def sleep(account=None): 10 | sleep_time = random.randint(MIN_SLEEP, MAX_SLEEP) 11 | if account: 12 | logger.info( 13 | f"[{account.id}][{account.address}] Sleeping for {sleep_time} seconds" 14 | ) 15 | else: 16 | logger.info(f"Sleeping for {sleep_time} seconds") 17 | await asyncio.sleep(sleep_time) 18 | 19 | 20 | def retry(func): 21 | async def wrapper(*args, **kwargs): 22 | retries = 0 23 | while retries <= RETRIES: 24 | try: 25 | result = await func(*args, **kwargs) 26 | return result 27 | except Exception as e: 28 | traceback.print_exc() 29 | retries += 1 30 | logger.error(f"Error | {e}") 31 | if retries <= RETRIES: 32 | logger.info(f"Retrying... {retries}/{RETRIES}") 33 | await sleep() 34 | 35 | return wrapper 36 | -------------------------------------------------------------------------------- /modules/withdraw_from_binance.py: -------------------------------------------------------------------------------- 1 | import random 2 | import ccxt 3 | from loguru import logger 4 | 5 | from settings import ( 6 | BINANCE_API_KEY, 7 | BINANCE_SECRET_KEY, 8 | MAX_WITHDRAW, 9 | MIN_WITHDRAW, 10 | USE_PROXY_FOR_BINANCE, 11 | ) 12 | 13 | 14 | async def withdraw_from_binance(address, proxy): 15 | client_params = { 16 | "apiKey": BINANCE_API_KEY, 17 | "secret": BINANCE_SECRET_KEY, 18 | "enableRateLimit": True, 19 | "options": {"defaultType": "spot"}, 20 | } 21 | 22 | amount = round(random.uniform(MIN_WITHDRAW, MAX_WITHDRAW), 6) 23 | 24 | if USE_PROXY_FOR_BINANCE: 25 | client_params["proxies"] = { 26 | "http": f"http://{proxy}", 27 | } 28 | 29 | ccxt_client = ccxt.binance(client_params) 30 | 31 | try: 32 | withdraw = ccxt_client.withdraw( 33 | code="BNB", 34 | amount=amount, 35 | address=address, 36 | tag=None, 37 | params={"network": "BEP20"}, 38 | ) 39 | logger.success( 40 | f"{ccxt_client.name} - {address} | withdraw {amount} BNB to BNB network)" 41 | ) 42 | 43 | except Exception as error: 44 | logger.error(f"{ccxt_client.name} - {address} | withdraw error : {error}") 45 | -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [tool.poetry] 2 | name = "starrynift-automation" 3 | version = "0.1.0" 4 | description = "" 5 | authors = ["Alex "] 6 | readme = "README.md" 7 | 8 | [tool.poetry.dependencies] 9 | python = "^3.9" 10 | loguru = "^0.7.2" 11 | web3 = "^6.14.0" 12 | aiohttp = "^3.9.1" 13 | fake-useragent = "^1.4.0" 14 | questionary = "^2.0.1" 15 | hdwallet = "^2.2.1" 16 | ccxt = "^4.2.20" 17 | 18 | 19 | [build-system] 20 | requires = ["poetry-core"] 21 | build-backend = "poetry.core.masonry.api" 22 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | aiodns==3.1.1 ; python_version >= "3.9" and python_version < "4.0" 2 | aiohttp==3.9.1 ; python_version >= "3.9" and python_version < "4.0" 3 | aiosignal==1.3.1 ; python_version >= "3.9" and python_version < "4.0" 4 | async-timeout==4.0.3 ; python_version >= "3.9" and python_version < "3.11" 5 | attrs==23.2.0 ; python_version >= "3.9" and python_version < "4.0" 6 | base58==2.1.1 ; python_version >= "3.9" and python_version < "4" 7 | bitarray==2.9.2 ; python_version >= "3.9" and python_version < "4" 8 | ccxt==4.2.21 ; python_version >= "3.9" and python_version < "4.0" 9 | certifi==2023.11.17 ; python_version >= "3.9" and python_version < "4.0" 10 | cffi==1.16.0 ; python_version >= "3.9" and python_version < "4.0" 11 | charset-normalizer==3.3.2 ; python_version >= "3.9" and python_version < "4.0" 12 | colorama==0.4.6 ; python_version >= "3.9" and python_version < "4.0" and sys_platform == "win32" 13 | cryptography==42.0.0 ; python_version >= "3.9" and python_version < "4.0" 14 | cytoolz==0.12.2 ; python_version >= "3.9" and python_version < "4" and implementation_name == "cpython" 15 | ecdsa==0.18.0 ; python_version >= "3.9" and python_version < "4" 16 | eth-abi==5.0.0 ; python_version >= "3.9" and python_version < "4" 17 | eth-account==0.10.0 ; python_version >= "3.9" and python_version < "4" 18 | eth-hash==0.6.0 ; python_version >= "3.9" and python_version < "4" 19 | eth-hash[pycryptodome]==0.6.0 ; python_version >= "3.9" and python_version < "4" 20 | eth-keyfile==0.7.0 ; python_version >= "3.9" and python_version < "4" 21 | eth-keys==0.5.0 ; python_version >= "3.9" and python_version < "4" 22 | eth-rlp==1.0.0 ; python_version >= "3.9" and python_version < "4" 23 | eth-typing==4.0.0 ; python_version >= "3.9" and python_version < "4" 24 | eth-utils==3.0.0 ; python_version >= "3.9" and python_version < "4" 25 | fake-useragent==1.4.0 ; python_version >= "3.9" and python_version < "4.0" 26 | frozenlist==1.4.1 ; python_version >= "3.9" and python_version < "4.0" 27 | hdwallet==2.2.1 ; python_version >= "3.9" and python_version < "4" 28 | hexbytes==0.3.1 ; python_version >= "3.9" and python_version < "4" 29 | idna==3.6 ; python_version >= "3.9" and python_version < "4.0" 30 | importlib-resources==6.1.1 ; python_version >= "3.9" and python_version < "3.10" 31 | jsonschema-specifications==2023.12.1 ; python_version >= "3.9" and python_version < "4.0" 32 | jsonschema==4.21.1 ; python_version >= "3.9" and python_version < "4.0" 33 | loguru==0.7.2 ; python_version >= "3.9" and python_version < "4.0" 34 | lru-dict==1.2.0 ; python_version >= "3.9" and python_version < "4.0" 35 | mnemonic==0.21 ; python_version >= "3.9" and python_version < "4" 36 | multidict==6.0.4 ; python_version >= "3.9" and python_version < "4.0" 37 | parsimonious==0.9.0 ; python_version >= "3.9" and python_version < "4" 38 | prompt-toolkit==3.0.36 ; python_version >= "3.9" and python_version < "4.0" 39 | protobuf==4.25.2 ; python_version >= "3.9" and python_version < "4.0" 40 | pycares==4.4.0 ; python_version >= "3.9" and python_version < "4.0" 41 | pycparser==2.21 ; python_version >= "3.9" and python_version < "4.0" 42 | pycryptodome==3.20.0 ; python_version >= "3.9" and python_version < "4" 43 | pyunormalize==15.1.0 ; python_version >= "3.9" and python_version < "4.0" 44 | pywin32==306 ; python_version >= "3.9" and python_version < "4.0" and platform_system == "Windows" 45 | questionary==2.0.1 ; python_version >= "3.9" and python_version < "4.0" 46 | referencing==0.32.1 ; python_version >= "3.9" and python_version < "4.0" 47 | regex==2023.12.25 ; python_version >= "3.9" and python_version < "4" 48 | requests==2.31.0 ; python_version >= "3.9" and python_version < "4.0" 49 | rlp==4.0.0 ; python_version >= "3.9" and python_version < "4" 50 | rpds-py==0.17.1 ; python_version >= "3.9" and python_version < "4.0" 51 | setuptools==69.0.3 ; python_version >= "3.9" and python_version < "4.0" 52 | six==1.16.0 ; python_version >= "3.9" and python_version < "4" 53 | toolz==0.12.1 ; python_version >= "3.9" and python_version < "4" and (implementation_name == "pypy" or implementation_name == "cpython") 54 | typing-extensions==4.9.0 ; python_version >= "3.9" and python_version < "4.0" 55 | urllib3==2.1.0 ; python_version >= "3.9" and python_version < "4.0" 56 | wcwidth==0.2.13 ; python_version >= "3.9" and python_version < "4.0" 57 | web3==6.14.0 ; python_version >= "3.9" and python_version < "4.0" 58 | websockets==12.0 ; python_version >= "3.9" and python_version < "4.0" 59 | win32-setctime==1.1.0 ; python_version >= "3.9" and python_version < "4.0" and sys_platform == "win32" 60 | yarl==1.9.4 ; python_version >= "3.9" and python_version < "4.0" 61 | zipp==3.17.0 ; python_version >= "3.9" and python_version < "3.10" 62 | -------------------------------------------------------------------------------- /settings.py: -------------------------------------------------------------------------------- 1 | # Referal link to StarryNift 2 | REF_LINK = "https://starrynift.art?referralCode=8RrY9jzgE8" 3 | 4 | # User ids to follow for quest completion 5 | # Make sure to input user id, not link 6 | # Will Follow 1 not followed user per account daily. 7 | # You can get your userIds by using Get accounts stats option 8 | USER_IDS_TO_FOLLOW = [ 9 | "i51Hwgqq8e", 10 | "wLCvTVtzC7", 11 | "gTSV3gtflS", 12 | "sZbhJ3m-S5", 13 | "qZiaScTXcp", 14 | "BvDh6oWLvv", 15 | "9ZkHSyATB0", 16 | "TciUEa7WV9", 17 | "GMC8KbdEXP", 18 | "k6r-Eeh1Ha", 19 | "sA9e90ApWU", 20 | "dgs7fK5YXN", 21 | "89B1uZG_a2", 22 | "zmnnh1mxzl", 23 | "oLxFYpMvTz", 24 | "lC2f0PduqS", 25 | "QgHXExKJKK", 26 | "KnK6dxUQRn", 27 | "7mT6s4-iVS", 28 | "_EiFdqJV1l", 29 | "3KElmquZzz", 30 | "eU2P0WiyLu", 31 | "E4MdLCmlHs", 32 | "hwTe4ekmCo", 33 | "LmeEU_m8Sq", 34 | "_YpzxoraSq", 35 | "bjyp7uE5sY", 36 | "Ut2-SP9vkK", 37 | "-KJVzigOzP", 38 | "NhZDgdRyRN", 39 | "AnzFNDe6_T", 40 | "tBXXXWMLUs", 41 | "z8tPhANWbZ", 42 | "G64Y2HZBix", 43 | "ENRSYgxcbg", 44 | "06LU5nZx_n", 45 | "ZY39pnH0sO", 46 | "BCO7TAo3YJ", 47 | "Lk47x2VK_C", 48 | "EKs0VON7v_", 49 | "gZoM7GBaIT", 50 | "CeJWB9d878", 51 | "dBt_77bSbq", 52 | "Na80WID3Ou", 53 | "rYpJRluc_l", 54 | "tGg7b_OL4x", 55 | "C-CbELi8RU", 56 | "aO7SJbh3Fi", 57 | "d71c3nmbg0", 58 | "OwZtyv3SxZ", 59 | ] 60 | 61 | DISABLE_SSL = False 62 | 63 | SHUFFLE_ACCOUNTS = False 64 | RETRIES = 2 65 | 66 | THREADS = 5 67 | 68 | MIN_SLEEP = 30 69 | MAX_SLEEP = 50 70 | 71 | BNB_RPC = "https://bsc.publicnode.com" 72 | OPBNB_RPC = "https://opbnb-rpc.publicnode.com" 73 | 74 | 75 | # ___________________________________________ 76 | # | BINANCE WITHDRAW | 77 | 78 | BINANCE_API_KEY = "" 79 | BINANCE_SECRET_KEY = "" 80 | 81 | MIN_WITHDRAW = 0.01001 82 | MAX_WITHDRAW = 0.0105 83 | 84 | USE_PROXY_FOR_BINANCE = ( 85 | False # If True, you need to whitelist your proxies IPs in Binance API settings 86 | ) 87 | --------------------------------------------------------------------------------