-
Notifications
You must be signed in to change notification settings - Fork 696
Add solana token rank #445
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
848d373
dbda5e1
d6735f4
f7bbbd8
060549b
61c5608
6e62983
ef16b3e
a3dde27
914dcda
4b775bc
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,32 @@ | ||
| from typing import TypedDict | ||
| from abstracts.skill import SkillStoreABC | ||
| from skills.base import SkillConfig, SkillState | ||
| from skills.solana_token_rank.base import SolanaTokenRankBaseTool | ||
| from skills.solana_token_rank.solana_token_rank import SolanaTokenRank | ||
|
|
||
| _cache: dict[str, SolanaTokenRankBaseTool] = {} | ||
|
|
||
| class SkillStates(TypedDict): | ||
| solana_token_rank: SkillState | ||
|
|
||
| class Config(SkillConfig): | ||
| states: SkillStates | ||
|
|
||
| async def get_skills(config: "Config", is_private: bool, store: SkillStoreABC, **_) -> list[SolanaTokenRankBaseTool]: | ||
| available_skills = [] | ||
| for skill_name, state in config["states"].items(): | ||
| if state == "disabled": | ||
| continue | ||
| elif state == "public" or (state == "private" and is_private): | ||
| available_skills.append(skill_name) | ||
|
|
||
| return [get_solana_skill(name, store) for name in available_skills] | ||
|
|
||
| def get_solana_skill(name: str, store: SkillStoreABC) -> SolanaTokenRankBaseTool: | ||
| if name == "solana_token_rank": | ||
| if name not in _cache: | ||
| _cache[name] = SolanaTokenRank(skill_store=store) | ||
| return _cache[name] | ||
| else: | ||
| raise ValueError(f"Unknown solana_token_rank skill: {name}") | ||
|
|
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,17 @@ | ||
| from typing import Type | ||
| from pydantic import BaseModel, Field | ||
| from abstracts.skill import SkillStoreABC | ||
| from skills.base import IntentKitSkill | ||
|
|
||
| class SolanaTokenRankBaseTool(IntentKitSkill): | ||
| """Base class for Solana Token Rank tools.""" | ||
|
|
||
| name: str = Field(description="The name of the tool") | ||
| description: str = Field(description="A description of what the tool does") | ||
| args_schema: Type[BaseModel] | ||
| skill_store: SkillStoreABC = Field(description="The skill store for persisting data") | ||
|
|
||
| @property | ||
| def category(self) -> str: | ||
| return "solana_token_rank" | ||
|
|
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,26 @@ | ||
| { | ||
| "$schema": "http://json-schema.org/draft-07/schema#", | ||
| "type": "object", | ||
| "title": "Solana Token Rank Skill", | ||
| "description": "Configuration schema for Solana Token Rank skill", | ||
| "properties": { | ||
| "states": { | ||
| "type": "object", | ||
| "properties": { | ||
| "solana_token_rank": { | ||
| "type": "string", | ||
| "title": "Solana Token Rank", | ||
| "enum": [ | ||
| "disabled", | ||
| "public", | ||
| "private" | ||
| ], | ||
| "description": "State of the solana_token_rank skill" | ||
| } | ||
| }, | ||
| "description": "States for each Solana token rank skill (disabled, public, or private)" | ||
| } | ||
| }, | ||
| "required": ["states"], | ||
| "additionalProperties": true | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,46 @@ | ||
| import httpx | ||
| from pydantic import BaseModel, Field | ||
| from typing import Type | ||
| from skills.solana_token_rank.base import SolanaTokenRankBaseTool | ||
|
|
||
| class SolanaTokenRankInput(BaseModel): | ||
| wallet_address: str = Field(description="Solana wallet address to look up") | ||
| token_mint: str = Field(description="Solana token mint address to rank against") | ||
|
|
||
| class SolanaTokenRank(SolanaTokenRankBaseTool): | ||
| name: str = "solana_token_rank" | ||
| description: str = "Get the rank, amount held, and top holder of a given Solana token." | ||
| args_schema: Type[BaseModel] = SolanaTokenRankInput | ||
|
|
||
| async def _arun(self, wallet_address: str, token_mint: str, **kwargs) -> str: | ||
| try: | ||
| base_url = "https://api.helius.xyz/v0/tokens/holding" | ||
| api_key = "YOUR_HELIUS_API_KEY" # Replace with env or system config in production | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this is not the right way to add the api key, please check how other skills get the api key from config, you're need to add it in the .env file, thanks! |
||
| url = f"{base_url}?api-key={api_key}&wallets[]={wallet_address}&mints[]={token_mint}" | ||
|
|
||
| async with httpx.AsyncClient() as client: | ||
| response = await client.get(url) | ||
| response.raise_for_status() | ||
| data = response.json() | ||
|
|
||
| if not data or not data[0].get("tokens"): | ||
| return "No token data found for this wallet and mint." | ||
|
|
||
| token_data = data[0]["tokens"][0] | ||
| amount = token_data.get("amount") | ||
|
|
||
| # Simulate a rank and top holder — in real code you'd use on-chain index or API | ||
| fake_rank = 1234 | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this simulation needs to be removed, as it should work using the api only! |
||
| fake_total = 100000 | ||
| fake_top_holder = "TopHolderAddress" | ||
|
|
||
| return ( | ||
| f"Wallet: {wallet_address}\n" | ||
| f"Holds: {amount} tokens of {token_mint}\n" | ||
| f"Rank: #{fake_rank} of {fake_total} holders\n" | ||
| f"Top Holder: {fake_top_holder}" | ||
| ) | ||
|
|
||
| except Exception as e: | ||
| return f"Error getting token rank: {str(e)}" | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
please add an image in the solana_token_rank folder, and add the image path here as it is being done in the other skills, thanks!