├── README.md ├── getNewPairs.py ├── getTokenInfo.py ├── getTrendingWallets.py ├── gmgn ├── __init__.py ├── __pycache__ │ ├── __init__.cpython-312.pyc │ └── client.cpython-312.pyc └── client.py └── requirements.txt /README.md: -------------------------------------------------------------------------------- 1 |

2 |
3 | GMGN.ai Wrapper 4 |

5 |

6 | An API wrapper for undocumented endpoints at GMGN.ai
NOTE: This is for MY personal use, I do not condone the use of this API for any prohibited reason. :)
7 |


8 |

Note, the GMGN.ai domain is cloudflare protected,
meaning some requests will fail to get access to an unprotected endpoint
Join the Discord Server and request access
https://discord.gg/xxWqZppjht

9 | Example, for more examples go here

10 | 11 | ```python 12 | from gmgn import gmgn 13 | 14 | gmgn = gmgn() 15 | 16 | getTokenInfo = gmgn.getTokenInfo(contractAddress="9eLRcHw2G4Ugrnp1p5165PuZsQ2YSc9GnBpGZS7Cpump") 17 | 18 | print(getTokenInfo) 19 | ``` 20 | -------------------------------------------------------------------------------- /getNewPairs.py: -------------------------------------------------------------------------------- 1 | from gmgn import gmgn 2 | 3 | gmgn = gmgn() 4 | 5 | getNewPairs = gmgn.getNewPairs(limit=1) 6 | 7 | print(getNewPairs) -------------------------------------------------------------------------------- /getTokenInfo.py: -------------------------------------------------------------------------------- 1 | from gmgn import gmgn 2 | 3 | gmgn = gmgn() 4 | 5 | getTokenInfo = gmgn.getTokenInfo("QFp94pu1bbUq3o2Qz1PhH8SmZVtRQ9Y2LSxeadYpump") 6 | 7 | print(getTokenInfo) -------------------------------------------------------------------------------- /getTrendingWallets.py: -------------------------------------------------------------------------------- 1 | from gmgn import gmgn 2 | 3 | gmgn = gmgn() 4 | 5 | getTrendingWallets = gmgn.getTrendingWallets(timeframe="7d", walletTag="smart_degen") 6 | 7 | print(getTrendingWallets) 8 | -------------------------------------------------------------------------------- /gmgn/__init__.py: -------------------------------------------------------------------------------- 1 | from gmgn.client import gmgn -------------------------------------------------------------------------------- /gmgn/__pycache__/__init__.cpython-312.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1f1n/gmgnai-wrapper/2ad21aa656571ab6670ed1ba5c3079bae9ae6313/gmgn/__pycache__/__init__.cpython-312.pyc -------------------------------------------------------------------------------- /gmgn/__pycache__/client.cpython-312.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1f1n/gmgnai-wrapper/2ad21aa656571ab6670ed1ba5c3079bae9ae6313/gmgn/__pycache__/client.cpython-312.pyc -------------------------------------------------------------------------------- /gmgn/client.py: -------------------------------------------------------------------------------- 1 | import random 2 | import tls_client 3 | from fake_useragent import UserAgent 4 | 5 | # author - 1f1n 6 | # date - 05/06/2024 7 | 8 | class gmgn: 9 | BASE_URL = "https://gmgn.ai/defi/quotation" 10 | 11 | def __init__(self): 12 | pass 13 | 14 | def randomiseRequest(self): 15 | self.identifier = random.choice( 16 | [browser for browser in tls_client.settings.ClientIdentifiers.__args__ 17 | if browser.startswith(('chrome', 'safari', 'firefox', 'opera'))] 18 | ) 19 | parts = self.identifier.split('_') 20 | identifier, version, *rest = parts 21 | identifier = identifier.capitalize() 22 | 23 | self.sendRequest = tls_client.Session(random_tls_extension_order=True, client_identifier=self.identifier) 24 | self.sendRequest.timeout_seconds = 60 25 | 26 | if identifier == 'Opera': 27 | identifier = 'Chrome' 28 | osType = 'Windows' 29 | elif version.lower() == 'ios': 30 | osType = 'iOS' 31 | else: 32 | osType = 'Windows' 33 | 34 | try: 35 | self.user_agent = UserAgent(os=[osType]).random 36 | except Exception: 37 | self.user_agent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:82.0) Gecko/20100101 Firefox/82.0" 38 | 39 | self.headers = { 40 | 'Host': 'gmgn.ai', 41 | 'accept': 'application/json, text/plain, */*', 42 | 'accept-language': 'fr-FR,fr;q=0.9,en-US;q=0.8,en;q=0.7', 43 | 'dnt': '1', 44 | 'priority': 'u=1, i', 45 | 'referer': 'https://gmgn.ai/?chain=sol', 46 | 'user-agent': self.user_agent 47 | } 48 | 49 | 50 | def getTokenInfo(self, contractAddress: str) -> dict: 51 | """ 52 | Gets info on a token. 53 | """ 54 | self.randomiseRequest() 55 | if not contractAddress: 56 | return "You must input a contract address." 57 | url = f"{self.BASE_URL}/v1/tokens/sol/{contractAddress}" 58 | 59 | request = self.sendRequest.get(url, headers=self.headers) 60 | 61 | jsonResponse = request.json() 62 | 63 | return jsonResponse 64 | 65 | def getNewPairs(self, limit: int = None) -> dict: 66 | """ 67 | Limit - Limits how many tokens are in the response. 68 | """ 69 | self.randomiseRequest() 70 | if not limit: 71 | limit = 50 72 | elif limit > 50: 73 | return "You cannot have more than check more than 50 pairs." 74 | 75 | url = f"{self.BASE_URL}/v1/pairs/sol/new_pairs?limit={limit}&orderby=open_timestamp&direction=desc&filters[]=not_honeypot" 76 | 77 | request = self.sendRequest.get(url, headers=self.headers) 78 | 79 | jsonResponse = request.json()['data'] 80 | 81 | return jsonResponse 82 | 83 | def getTrendingWallets(self, timeframe: str = None, walletTag: str = None) -> dict: 84 | """ 85 | Gets a list of trending wallets based on a timeframe and a wallet tag. 86 | 87 | Timeframes\n 88 | 1d = 1 Day\n 89 | 7d = 7 Days\n 90 | 30d = 30 days\n 91 | 92 | ---------------- 93 | 94 | Wallet Tags\n 95 | pump_smart = Pump.Fun Smart Money\n 96 | smart_degen = Smart Money\n 97 | reowned = KOL/VC/Influencer\n 98 | snipe_bot = Snipe Bot\n 99 | 100 | """ 101 | self.randomiseRequest() 102 | if not timeframe: 103 | timeframe = "7d" 104 | if not walletTag: 105 | walletTag = "smart_degen" 106 | 107 | url = f"{self.BASE_URL}/v1/rank/sol/wallets/{timeframe}?tag={walletTag}&orderby=pnl_{timeframe}&direction=desc" 108 | 109 | request = self.sendRequest.get(url, headers=self.headers) 110 | 111 | jsonResponse = request.json()['data'] 112 | 113 | return jsonResponse 114 | 115 | def getTrendingTokens(self, timeframe: str = None) -> dict: 116 | """ 117 | Gets a list of trending tokens based on a timeframe. 118 | 119 | Timeframes\n 120 | 1m = 1 Minute\n 121 | 5m = 5 Minutes\n 122 | 1h = 1 Hour\n 123 | 6h = 6 Hours\n 124 | 24h = 24 Hours\n 125 | """ 126 | timeframes = ["1m", "5m", "1h", "6h", "24h"] 127 | self.randomiseRequest() 128 | 129 | if not timeframe: 130 | timeframe = "1h" 131 | 132 | if timeframe not in timeframes: 133 | return "Not a valid timeframe." 134 | 135 | if timeframe == "1m": 136 | url = f"{self.BASE_URL}/v1/rank/sol/swaps/{timeframe}?orderby=swaps&direction=desc&limit=20" 137 | else: 138 | url = f"{self.BASE_URL}/v1/rank/sol/swaps/{timeframe}?orderby=swaps&direction=desc" 139 | 140 | request = self.sendRequest.get(url, headers=self.headers) 141 | 142 | jsonResponse = request.json()['data'] 143 | 144 | return jsonResponse 145 | 146 | def getTokensByCompletion(self, limit: int = None) -> dict: 147 | """ 148 | Gets tokens by their bonding curve completion progress.\n 149 | 150 | Limit - Limits how many tokens in the response. 151 | """ 152 | self.randomiseRequest() 153 | if not limit: 154 | limit = 50 155 | elif limit > 50: 156 | return "Limit cannot be above 50." 157 | 158 | url = f"{self.BASE_URL}/v1/rank/sol/pump?limit={limit}&orderby=progress&direction=desc&pump=true" 159 | 160 | request = self.sendRequest.get(url, headers=self.headers) 161 | 162 | jsonResponse = request.json()['data'] 163 | 164 | return jsonResponse 165 | 166 | def findSnipedTokens(self, size: int = None) -> dict: 167 | """ 168 | Gets a list of tokens that have been sniped.\n 169 | 170 | Size - The amount of tokens in the response 171 | """ 172 | self.randomiseRequest() 173 | if not size: 174 | size = 10 175 | elif size > 39: 176 | return "Size cannot be more than 39" 177 | 178 | url = f"{self.BASE_URL}/v1/signals/sol/snipe_new?size={size}&is_show_alert=false&featured=false" 179 | 180 | request = self.sendRequest.get(url, headers=self.headers) 181 | 182 | jsonResponse = request.json()['data'] 183 | 184 | return jsonResponse 185 | 186 | def getGasFee(self): 187 | """ 188 | Get the current gas fee price. 189 | """ 190 | self.randomiseRequest() 191 | url = f"{self.BASE_URL}/v1/chains/sol/gas_price" 192 | 193 | request = self.sendRequest.get(url, headers=self.headers) 194 | 195 | jsonResponse = request.json()['data'] 196 | 197 | return jsonResponse 198 | 199 | def getTokenUsdPrice(self, contractAddress: str = None) -> dict: 200 | """ 201 | Get the realtime USD price of the token. 202 | """ 203 | self.randomiseRequest() 204 | if not contractAddress: 205 | return "You must input a contract address." 206 | 207 | url = f"{self.BASE_URL}/v1/sol/tokens/realtime_token_price?address={contractAddress}" 208 | 209 | request = self.sendRequest.get(url, headers=self.headers) 210 | 211 | jsonResponse = request.json()['data'] 212 | 213 | return jsonResponse 214 | 215 | def getTopBuyers(self, contractAddress: str = None) -> dict: 216 | """ 217 | Get the top buyers of a token. 218 | """ 219 | self.randomiseRequest() 220 | if not contractAddress: 221 | return "You must input a contract address." 222 | 223 | url = f"{self.BASE_URL}/v1/tokens/top_buyers/sol/{contractAddress}" 224 | 225 | request = self.sendRequest.get(url, headers=self.headers) 226 | 227 | jsonResponse = request.json()['data'] 228 | 229 | return jsonResponse 230 | 231 | def getSecurityInfo(self, contractAddress: str = None) -> dict: 232 | """ 233 | Gets security info about the token. 234 | """ 235 | self.randomiseRequest() 236 | if not contractAddress: 237 | return "You must input a contract address." 238 | 239 | url = f"{self.BASE_URL}/v1/tokens/security/sol/{contractAddress}" 240 | 241 | request = self.sendRequest.get(url, headers=self.headers) 242 | 243 | jsonResponse = request.json()['data'] 244 | 245 | return jsonResponse 246 | 247 | def getWalletInfo(self, walletAddress: str = None, period: str = None) -> dict: 248 | """ 249 | Gets various information about a wallet address. 250 | 251 | Period - 7d, 30d - The timeframe of the wallet you're checking. 252 | """ 253 | self.randomiseRequest() 254 | periods = ["1d", "7d", "30d"] 255 | 256 | if not walletAddress: 257 | return "You must input a wallet address." 258 | if not period or period not in periods: 259 | period = "7d" 260 | 261 | url = f"{self.BASE_URL}/v1/smartmoney/sol/walletNew/{walletAddress}?period={period}" 262 | 263 | request = self.sendRequest.get(url, headers=self.headers) 264 | 265 | jsonResponse = request.json()['data'] 266 | 267 | return jsonResponse 268 | 269 | def getWalletTokenDistribution(self, walletAddress: str = None, period: str = None) -> dict: 270 | """ 271 | Get the distribution of ROI on tokens traded by the wallet address 272 | """ 273 | self.randomiseRequest() 274 | periods = ["1d", "7d", "30d"] 275 | 276 | if not walletAddress: 277 | return "You must input a wallet address." 278 | if not period or period not in periods: 279 | period = "7d" 280 | 281 | url = f"{self.BASE_URL}/v1/rank/sol/wallets/{walletAddress}/unique_token_7d?interval={period}" 282 | request = self.sendRequest.get(url, headers=self.headers) 283 | 284 | jsonResponse = request.json()['data'] 285 | 286 | return jsonResponse 287 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | tls_client 2 | fake_useragent 3 | typing_extensions 4 | --------------------------------------------------------------------------------