├── 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 |
--------------------------------------------------------------------------------