Skip to content
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

Add snapshot module to create an airdrop #5

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions agent_server.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
from datetime import datetime
import argparse
from injective_functions.factory import InjectiveClientFactory
from injective_functions.snapshot import Snapshot
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Remove unused import.

The Snapshot import is not used in this file. Either remove it or ensure it's properly utilized if needed for the snapshot functionality.

-from injective_functions.snapshot import Snapshot
🧰 Tools
🪛 Ruff (0.8.0)

8-8: injective_functions.snapshot.Snapshot imported but unused

Remove unused import: injective_functions.snapshot.Snapshot

(F401)

from injective_functions.utils.function_helper import (
FunctionSchemaLoader,
FunctionExecutor,
Expand Down Expand Up @@ -46,6 +47,7 @@ def __init__(self):
"./injective_functions/exchange/exchange_schema.json",
"./injective_functions/staking/staking_schema.json",
"./injective_functions/token_factory/token_factory_schema.json",
"./injective_functions/snapshot/snapshot_schema.json",
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codebase verification

Snapshot implementation needs improvements

The snapshot implementation exists but has several issues that need to be addressed:

  • injective_functions/snapshot/__init__.py: The implementation makes direct HTTP requests without error handling, timeout settings, or proper response validation against the schema
  • The schema in snapshot_schema.json defines an empty parameters object, but the implementation doesn't reflect any configurable parameters
  • The class inherits from something (super().__init__()) but doesn't explicitly declare a parent class
  • Missing type hints for the return data structure that matches the actual API response
🔗 Analysis chain

Verify snapshot implementation.

The snapshot schema path is added, but we need to ensure that the corresponding implementation exists and is properly integrated.


Let me gather more information about the snapshot implementation.


Let me check the implementation details in the identified files.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify the existence and structure of the snapshot implementation

# Check if snapshot module exists
echo "Checking for snapshot module..."
fd -t f "snapshot" injective_functions/snapshot

# Check for snapshot implementation
echo "Checking for get_snapshot implementation..."
ast-grep --pattern 'class Snapshot:
  $$$
  async def get_snapshot($$$):
    $$$'

Length of output: 351


Script:

#!/bin/bash
# Let's check for any Python files in the snapshot directory and their content
echo "Checking for Python files in snapshot directory..."
fd -e py . injective_functions/snapshot

# Let's also check the content of snapshot_schema.json
echo -e "\nChecking snapshot schema content..."
cat injective_functions/snapshot/snapshot_schema.json

# Let's search for any snapshot-related imports or usage
echo -e "\nChecking for snapshot imports or usage..."
rg -l "snapshot" --type py

Length of output: 826


Script:

#!/bin/bash
# Check the content of snapshot/__init__.py
echo "Content of snapshot/__init__.py:"
cat injective_functions/snapshot/__init__.py

# Check how snapshot is used in factory.py
echo -e "\nSnapshot usage in factory.py:"
rg "snapshot" -A 5 -B 5 injective_functions/factory.py

# Check how snapshot is used in function_helper.py
echo -e "\nSnapshot usage in function_helper.py:"
rg "snapshot" -A 5 -B 5 injective_functions/utils/function_helper.py

Length of output: 2116

"./injective_functions/utils/utils_schema.json",
]
self.function_schemas = FunctionSchemaLoader.load_schemas(schema_paths)
Expand Down
2 changes: 2 additions & 0 deletions injective_functions/factory.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
from injective_functions.exchange.trader import InjectiveTrading
from injective_functions.staking import InjectiveStaking
from injective_functions.token_factory import InjectiveTokenFactory
from injective_functions.snapshot import Snapshot


class InjectiveClientFactory:
Expand Down Expand Up @@ -41,6 +42,7 @@ async def create_all(private_key: str, network_type: str = "mainnet") -> Dict:
"trader": InjectiveTrading(chain_client),
"staking": InjectiveStaking(chain_client),
"token_factory": InjectiveTokenFactory(chain_client),
"snapshot": Snapshot(),
}
print(clients)
return clients
9 changes: 9 additions & 0 deletions injective_functions/function_schemas.json
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,15 @@
},
"required": ["to_address", "amount"]
}
},
{
"name": "get_snapshot",
"description": "Get a snapshot to create an airdrop",
"parameters": {
"type": "object",
"properties": {},
"required": []
}
Comment on lines +129 to +135
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Enhance the snapshot function schema with more detailed parameters and documentation.

The current schema lacks important details that would help users understand and properly use this function:

  1. The parameters object is empty, which means there's no input validation
  2. The description doesn't specify what kind of snapshot data will be returned

Consider adding these parameters to better define the contract:

 {
   "name": "get_snapshot",
-  "description": "Get a snapshot to create an airdrop",
+  "description": "Get a snapshot of token holders or other on-chain data for creating an airdrop. Returns a list of addresses and their corresponding data.",
   "parameters": {
     "type": "object",
     "properties": {
+      "snapshot_type": {
+        "type": "string",
+        "enum": ["token_holders", "stakers", "liquidity_providers"],
+        "description": "Type of snapshot to retrieve"
+      },
+      "token_address": {
+        "type": "string",
+        "description": "Address of the token contract (required for token_holders snapshot type)"
+      },
+      "block_height": {
+        "type": "integer",
+        "description": "Optional block height for historical snapshot. If not provided, uses latest block"
+      }
     },
-    "required": []
+    "required": ["snapshot_type"]
   }
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
"name": "get_snapshot",
"description": "Get a snapshot to create an airdrop",
"parameters": {
"type": "object",
"properties": {},
"required": []
}
"name": "get_snapshot",
"description": "Get a snapshot of token holders or other on-chain data for creating an airdrop. Returns a list of addresses and their corresponding data.",
"parameters": {
"type": "object",
"properties": {
"snapshot_type": {
"type": "string",
"enum": ["token_holders", "stakers", "liquidity_providers"],
"description": "Type of snapshot to retrieve"
},
"token_address": {
"type": "string",
"description": "Address of the token contract (required for token_holders snapshot type)"
},
"block_height": {
"type": "integer",
"description": "Optional block height for historical snapshot. If not provided, uses latest block"
}
},
"required": ["snapshot_type"]
}

}
]
}
9 changes: 9 additions & 0 deletions injective_functions/functions_schemas.json
Original file line number Diff line number Diff line change
Expand Up @@ -906,6 +906,15 @@
"uri_hash"
]
}
},
{
"name": "get_snapshot",
"description": "Get a snapshot to create an airdrop",
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Enhance function description with more details

The current description is too brief and doesn't explain what data the snapshot captures or how it will be used for the airdrop.

Suggested enhancement:

-  "description": "Get a snapshot to create an airdrop",
+  "description": "Creates a point-in-time snapshot of token holder balances for airdrop distribution. Returns a mapping of addresses to their token balances at the specified block height, filtered by the given criteria.",
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
"description": "Get a snapshot to create an airdrop",
"description": "Creates a point-in-time snapshot of token holder balances for airdrop distribution. Returns a mapping of addresses to their token balances at the specified block height, filtered by the given criteria.",

"parameters": {
"type": "object",
"properties": {},
"required": []
}
Comment on lines +911 to +917
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Add essential parameters for snapshot functionality

The current schema lacks crucial parameters typically needed for creating an airdrop snapshot. Consider adding:

  • block_height or timestamp: Point in time for the snapshot
  • criteria: Rules for inclusion (e.g., minimum balance, specific tokens)
  • token_address: Address of the token contract to snapshot

Here's a suggested schema enhancement:

   "name": "get_snapshot",
   "description": "Get a snapshot to create an airdrop",
   "parameters": {
     "type": "object",
-    "properties": {},
-    "required": []
+    "properties": {
+      "block_height": {
+        "type": "integer",
+        "description": "Block height at which to take the snapshot. Use 0 for latest block"
+      },
+      "token_address": {
+        "type": "string",
+        "description": "Address of the token contract to snapshot"
+      },
+      "min_balance": {
+        "type": "string",
+        "description": "Minimum token balance required for inclusion in snapshot"
+      }
+    },
+    "required": ["token_address"]
   }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
"name": "get_snapshot",
"description": "Get a snapshot to create an airdrop",
"parameters": {
"type": "object",
"properties": {},
"required": []
}
"name": "get_snapshot",
"description": "Get a snapshot to create an airdrop",
"parameters": {
"type": "object",
"properties": {
"block_height": {
"type": "integer",
"description": "Block height at which to take the snapshot. Use 0 for latest block"
},
"token_address": {
"type": "string",
"description": "Address of the token contract to snapshot"
},
"min_balance": {
"type": "string",
"description": "Minimum token balance required for inclusion in snapshot"
}
},
"required": ["token_address"]
}

}
]
}
17 changes: 17 additions & 0 deletions injective_functions/snapshot/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import json
from typing import Dict, List
import requests

Comment on lines +1 to +4
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Remove unused import and use aiohttp instead of requests.

The json import is unused, and since this is an async method, we should use an async HTTP client.

-import json
 from typing import Dict, List
-import requests
+import aiohttp
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
import json
from typing import Dict, List
import requests
from typing import Dict, List
import aiohttp
🧰 Tools
🪛 Ruff (0.8.0)

1-1: json imported but unused

(F401)

"""This class handles all the functions related to the snapshot module"""


class Snapshot():
def __init__(self) -> None:
# Initializes the network and the composer
super().__init__()

Comment on lines +8 to +12
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Remove unnecessary super() call.

The Snapshot class doesn't inherit from any base class, making the super().__init__() call unnecessary and potentially harmful.

 class Snapshot():
     def __init__(self) -> None:
-        # Initializes the network and the composer
-        super().__init__()
+        pass
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
class Snapshot():
def __init__(self) -> None:
# Initializes the network and the composer
super().__init__()
class Snapshot():
def __init__(self) -> None:
pass

async def get_snapshot(self) -> List[Dict]:
data = requests.get(
"https://tokenstation.app/api/snapshots/last").json()

return data
Comment on lines +13 to +17
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Add error handling and timeout for external API call.

The current implementation lacks proper error handling for the HTTP request and response parsing. This could lead to unhandled exceptions and potential security vulnerabilities.

 async def get_snapshot(self) -> List[Dict]:
+    try:
+        response = requests.get(
+            "https://tokenstation.app/api/snapshots/last",
+            timeout=10,  # Add reasonable timeout
+            headers={'User-Agent': 'iAgent/1.0'}  # Identify your client
+        )
+        response.raise_for_status()  # Check for HTTP errors
+        return response.json()
+    except requests.RequestException as e:
+        raise ValueError(f"Failed to fetch snapshot: {str(e)}")
+    except json.JSONDecodeError as e:
+        raise ValueError(f"Invalid response format: {str(e)}")
-    data = requests.get(
-        "https://tokenstation.app/api/snapshots/last").json()
-
-    return data
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
async def get_snapshot(self) -> List[Dict]:
data = requests.get(
"https://tokenstation.app/api/snapshots/last").json()
return data
async def get_snapshot(self) -> List[Dict]:
try:
response = requests.get(
"https://tokenstation.app/api/snapshots/last",
timeout=10, # Add reasonable timeout
headers={'User-Agent': 'iAgent/1.0'} # Identify your client
)
response.raise_for_status() # Check for HTTP errors
return response.json()
except requests.RequestException as e:
raise ValueError(f"Failed to fetch snapshot: {str(e)}")
except json.JSONDecodeError as e:
raise ValueError(f"Invalid response format: {str(e)}")

13 changes: 13 additions & 0 deletions injective_functions/snapshot/snapshot_schema.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"functions": [
{
"name": "get_snapshot",
"description": "Get a snapshot to create an airdrop",
"parameters": {
"type": "object",
"properties": {},
"required": []
}
Comment on lines +6 to +10
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Parameters schema needs enhancement for airdrop snapshot use case.

The current empty parameters schema may be insufficient for airdrop snapshots. Consider adding:

  • timestamp or block_height for point-in-time snapshots
  • token_address to specify which token holders to snapshot
  • min_balance to set minimum holding requirements

Example enhancement:

 "parameters": {
   "type": "object",
   "properties": {
+    "token_address": {
+      "type": "string",
+      "description": "Address of the token to snapshot"
+    },
+    "block_height": {
+      "type": "integer",
+      "description": "Optional block height for historical snapshot"
+    },
+    "min_balance": {
+      "type": "string",
+      "description": "Minimum token balance to include in snapshot"
+    }
   },
-  "required": []
+  "required": ["token_address"]
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
"parameters": {
"type": "object",
"properties": {},
"required": []
}
"parameters": {
"type": "object",
"properties": {
"token_address": {
"type": "string",
"description": "Address of the token to snapshot"
},
"block_height": {
"type": "integer",
"description": "Optional block height for historical snapshot"
},
"min_balance": {
"type": "string",
"description": "Minimum token balance to include in snapshot"
}
},
"required": ["token_address"]
}

}
]
}
Comment on lines +1 to +13
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Add response schema definition.

The schema should define the expected response format for better API documentation and runtime validation.

Add this after the parameters object:

"returns": {
  "type": "array",
  "items": {
    "type": "object",
    "properties": {
      "address": {
        "type": "string",
        "description": "Wallet address"
      },
      "balance": {
        "type": "string",
        "description": "Token balance at snapshot time"
      }
    },
    "required": ["address", "balance"]
  }
}

2 changes: 2 additions & 0 deletions injective_functions/utils/function_helper.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,8 @@ class InjectiveFunctionMapper:
"mint": ("token_factory", "mint"),
"burn": ("token_factory", "burn"),
"set_denom_metadata": ("token_factory", "set_denom_metadata"),

"get_snapshot": ("snapshot", "get_snapshot"),
}

@classmethod
Expand Down