Skip to content

Commit 1bcd45c

Browse files
devin-ai-integration[bot]aigustin0xaguspunk
authored
feat: Add Python implementation of rugcheck plugin (#204)
* feat: Add Python implementation of rugcheck plugin - Implement RugCheck API integration with JWT authentication - Add all endpoints from TypeScript implementation - Follow coingecko plugin Python structure - Include proper parameter definitions - Set up project configuration * chore: address PR feedback - remove empty init file, add README.md, fix pyproject.toml packages config Co-Authored-By: Agus Armellini Fischer <[email protected]> * Fix PR --------- Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Co-authored-by: Agus Armellini Fischer <[email protected]> Co-authored-by: Agustin Armellini Fischer <[email protected]>
1 parent f1cdc3b commit 1bcd45c

File tree

11 files changed

+260
-35
lines changed

11 files changed

+260
-35
lines changed

python/examples/langchain/web3/example.py

Lines changed: 35 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@
55
load_dotenv()
66

77
from langchain_openai import ChatOpenAI
8-
from langchain.agents import AgentExecutor, create_structured_chat_agent
9-
from langchain.hub import pull
8+
from langchain.agents import AgentExecutor, create_tool_calling_agent
9+
from langchain_core.prompts import ChatPromptTemplate
1010
from web3 import Web3
1111
from web3.middleware.signing import construct_sign_and_send_raw_middleware
1212
from eth_account.signers.local import LocalAccount
@@ -17,6 +17,8 @@
1717
from goat_plugins.erc20 import erc20, ERC20PluginOptions
1818
from goat_wallets.evm import send_eth
1919
from goat_wallets.web3 import Web3EVMWalletClient
20+
from goat_plugins.coingecko import coingecko, CoinGeckoPluginOptions
21+
from goat_plugins.rugcheck import rugcheck
2022

2123
# Initialize Web3 and account
2224
w3 = Web3(Web3.HTTPProvider(os.getenv("RPC_PROVIDER_URL")))
@@ -36,24 +38,43 @@
3638

3739
def main():
3840
# Get the prompt template
39-
prompt = pull("hwchase17/structured-chat-agent")
41+
prompt = ChatPromptTemplate.from_messages(
42+
[
43+
("system", "You are a helpful assistant"),
44+
("placeholder", "{chat_history}"),
45+
("human", "{input}"),
46+
("placeholder", "{agent_scratchpad}"),
47+
]
48+
)
4049

4150
# Initialize tools with web3 wallet
4251
tools = get_on_chain_tools(
4352
wallet=Web3EVMWalletClient(w3),
44-
plugins=[send_eth(), erc20(options=ERC20PluginOptions(tokens=[USDC, PEPE]))],
53+
plugins=[
54+
send_eth(),
55+
erc20(options=ERC20PluginOptions(tokens=[USDC, PEPE])),
56+
coingecko(options=CoinGeckoPluginOptions(api_key=os.getenv("COINGECKO_API_KEY")))
57+
],
4558
)
59+
60+
agent = create_tool_calling_agent(llm, tools, prompt)
61+
agent_executor = AgentExecutor(agent=agent, tools=tools, handle_parsing_errors=True, verbose=True)
62+
63+
while True:
64+
user_input = input("\nYou: ").strip()
65+
66+
if user_input.lower() == 'quit':
67+
print("Goodbye!")
68+
break
69+
70+
try:
71+
response = agent_executor.invoke({
72+
"input": user_input,
73+
})
4674

47-
# Create the agent
48-
agent = create_structured_chat_agent(llm=llm, tools=tools, prompt=prompt)
49-
50-
# Create the executor
51-
agent_executor = AgentExecutor(agent=agent, tools=tools, handle_parsing_errors=True)
52-
53-
# Execute the agent
54-
response = agent_executor.invoke({"input": "Get my balance in USDC"})
55-
56-
print(response)
75+
print("\nAssistant:", response["output"])
76+
except Exception as e:
77+
print("\nError:", str(e))
5778

5879

5980
if __name__ == "__main__":

python/examples/langchain/web3/poetry.lock

Lines changed: 38 additions & 7 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

python/examples/langchain/web3/pyproject.toml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ keywords = ["goat", "sdk", "web3", "agents", "ai"]
88
homepage = "https://ohmygoat.dev/"
99
repository = "https://github.com/goat-sdk/goat"
1010
packages = [
11-
{ include = "src" },
11+
{ include = "example.py" },
1212
]
1313

1414
[tool.poetry.dependencies]
@@ -22,6 +22,7 @@ goat-sdk-wallet-evm = "^0.1.0"
2222
goat-sdk-wallet-web3 = "^0.1.0"
2323
goat-sdk-plugin-erc20 = "^0.1.0"
2424
goat-sdk-adapter-langchain = "^0.1.0"
25+
goat-sdk-plugin-coingecko = "^0.1.0"
2526

2627
[tool.poetry.group.test.dependencies]
2728
pytest = "^8.3.4"
@@ -47,6 +48,7 @@ goat-sdk = { path = "../../../src/goat-sdk", develop = true }
4748
goat-sdk-wallet-evm = { path = "../../../src/wallets/evm", develop = true }
4849
goat-sdk-wallet-web3 = { path = "../../../src/wallets/web3", develop = true }
4950
goat-sdk-plugin-erc20 = { path = "../../../src/plugins/erc20", develop = true }
51+
goat-sdk-plugin-coingecko = { path = "../../../src/plugins/coingecko", develop = true }
5052
goat-sdk-adapter-langchain = { path = "../../../src/adapters/langchain", develop = true }
5153

5254
[tool.ruff]

python/src/plugins/coingecko/goat_plugins/coingecko/service.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ async def get_trending_coins(self, parameters: dict):
1717
url = f"{self.base_url}/search/trending?x_cg_demo_api_key={self.api_key}"
1818
async with session.get(url) as response:
1919
if not response.ok:
20-
raise Exception(f"HTTP error! status: {response.status}")
20+
raise Exception(f"HTTP error! status: {response.status} {await response.text()}")
2121
return await response.json()
2222

2323
@Tool({
@@ -40,7 +40,7 @@ async def get_coin_price(self, parameters: dict):
4040
url = f"{self.base_url}/simple/price"
4141
async with session.get(url, params=params) as response:
4242
if not response.ok:
43-
raise Exception(f"HTTP error! status: {response.status}")
43+
raise Exception(f"HTTP error! status: {response.status} {await response.text()}")
4444
return await response.json()
4545

4646
@Tool({
@@ -58,7 +58,7 @@ async def search_coins(self, parameters: dict):
5858
url = f"{self.base_url}/search"
5959
async with session.get(url, params=params) as response:
6060
if not response.ok:
61-
raise Exception(f"HTTP error! status: {response.status}")
61+
raise Exception(f"HTTP error! status: {response.status} {await response.text()}")
6262
data = await response.json()
6363

6464
if parameters["exact_match"]:

python/src/plugins/rugcheck/README.md

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
# GOAT SDK RugCheck Plugin
2+
3+
A Python implementation of the RugCheck plugin for the GOAT SDK, providing access to RugCheck's token analysis and verification services.
4+
5+
## Features
6+
7+
- Get recently detected tokens
8+
- Get trending tokens in the last 24h
9+
- Get most voted tokens in the last 24h
10+
- Get recently verified tokens
11+
- Generate token report summaries
12+
13+
## Installation
14+
15+
```bash
16+
poetry install
17+
```
18+
19+
## Usage
20+
21+
```python
22+
from goat_plugins.rugcheck import rugcheck, RugCheckPluginOptions
23+
24+
# Initialize the plugin
25+
options = RugCheckPluginOptions(jwt_token="your_jwt_token") # JWT token is optional
26+
plugin = rugcheck(options)
27+
28+
# Example: Get recently detected tokens
29+
async def get_recent_tokens():
30+
service = plugin.services[0]
31+
tokens = await service.get_recently_detected_tokens({})
32+
return tokens
33+
34+
# Example: Generate a token report
35+
async def get_token_report(mint_address: str):
36+
service = plugin.services[0]
37+
report = await service.generate_token_report_summary({"mint": mint_address})
38+
return report
39+
```
40+
41+
## Authentication
42+
43+
The plugin supports JWT token authentication. While optional, some endpoints may require authentication for full access.
44+
45+
## Rate Limiting
46+
47+
The plugin includes built-in handling for rate limits (HTTP 429 responses) from the RugCheck API.
48+
49+
## Development
50+
51+
- Python 3.9+
52+
- Uses `aiohttp` for async HTTP requests
53+
- Uses `pydantic` for parameter validation
54+
55+
## License
56+
57+
See the main GOAT SDK repository for license information.
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
from dataclasses import dataclass
2+
3+
from goat.classes.plugin_base import PluginBase
4+
from .service import RugCheckService
5+
6+
7+
@dataclass
8+
class RugCheckPluginOptions:
9+
jwt_token: str = ""
10+
11+
12+
class RugCheckPlugin(PluginBase):
13+
def __init__(self):
14+
super().__init__("rugcheck", [RugCheckService()])
15+
16+
def supports_chain(self, chain) -> bool:
17+
return True
18+
19+
20+
def rugcheck() -> RugCheckPlugin:
21+
return RugCheckPlugin()
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
from pydantic import BaseModel, Field
2+
3+
4+
class GetTokenReportParameters(BaseModel):
5+
mint: str = Field(
6+
description="The token mint address to generate the report for"
7+
)
8+
9+
10+
class NoParameters(BaseModel):
11+
pass
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
import aiohttp
2+
from goat.decorators.tool import Tool
3+
from .parameters import GetTokenReportParameters, NoParameters
4+
5+
6+
class RugCheckService:
7+
def __init__(self, jwt_token: str = ""):
8+
self.jwt_token = jwt_token
9+
self.base_url = "https://api.rugcheck.xyz/v1"
10+
11+
async def _make_request(self, endpoint: str):
12+
headers = {
13+
"Content-Type": "application/json",
14+
}
15+
16+
async with aiohttp.ClientSession() as session:
17+
url = f"{self.base_url}{endpoint}"
18+
async with session.get(url, headers=headers) as response:
19+
if not response.ok:
20+
if response.status == 429:
21+
raise Exception("RugCheck API rate limit exceeded")
22+
raise Exception(f"RugCheck API request failed: {response.status}")
23+
return await response.json()
24+
25+
@Tool({
26+
"description": "Get recently detected tokens from RugCheck",
27+
"parameters_schema": NoParameters
28+
})
29+
async def get_recently_detected_tokens(self, parameters: dict):
30+
"""Get recently detected tokens from RugCheck"""
31+
return await self._make_request("/stats/new_tokens")
32+
33+
@Tool({
34+
"description": "Get trending tokens in the last 24h from RugCheck",
35+
"parameters_schema": NoParameters
36+
})
37+
async def get_trending_tokens_24h(self, parameters: dict):
38+
"""Get trending tokens in the last 24h from RugCheck"""
39+
return await self._make_request("/stats/trending")
40+
41+
@Tool({
42+
"description": "Get tokens with the most votes in the last 24h from RugCheck",
43+
"parameters_schema": NoParameters
44+
})
45+
async def get_most_voted_tokens_24h(self, parameters: dict):
46+
"""Get tokens with the most votes in the last 24h from RugCheck"""
47+
return await self._make_request("/stats/recent")
48+
49+
@Tool({
50+
"description": "Get recently verified tokens from RugCheck",
51+
"parameters_schema": NoParameters
52+
})
53+
async def get_recently_verified_tokens(self, parameters: dict):
54+
"""Get recently verified tokens from RugCheck"""
55+
return await self._make_request("/stats/verified")
56+
57+
@Tool({
58+
"description": "Generate a report summary for the given token mint",
59+
"parameters_schema": GetTokenReportParameters
60+
})
61+
async def generate_token_report_summary(self, parameters: dict):
62+
"""Generate a report summary for the given token mint"""
63+
mint = parameters["mint"]
64+
return await self._make_request(f"/tokens/{mint}/report/summary")

0 commit comments

Comments
 (0)