Skip to content

Commit

Permalink
feat: add Python Solana wallet implementation (#233)
Browse files Browse the repository at this point in the history
* feat: add Python Solana wallet implementation

Co-Authored-By: [email protected] <[email protected]>

* feat: add README, pyproject.toml, poetry.toml, and __init__.py for Solana wallet

Co-Authored-By: [email protected] <[email protected]>

* Rename wallet-building function

* Fix transaction construction in wallet

* Add Solana example to validate Solana wallet

* Better .env.template and PubKey derivation fix

* Rename solana wallet build function

* Langchain Solana example

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-authored-by: [email protected] <[email protected]>
Co-authored-by: Andrea V <[email protected]>
  • Loading branch information
3 people authored Jan 16, 2025
1 parent a6970f8 commit 4040ead
Show file tree
Hide file tree
Showing 17 changed files with 4,240 additions and 0 deletions.
3 changes: 3 additions & 0 deletions python/examples/langchain/solana/.env.template
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
OPENAI_API_KEY=
SOLANA_RPC_ENDPOINT=https://api.devnet.solana.com
SOLANA_WALLET_SEED=2JpXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
21 changes: 21 additions & 0 deletions python/examples/langchain/solana/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Langchain web3 Example

## Setup

Copy the `.env.template` and populate with your values.

```
cp .env.template .env
```

Install dependencies

```
poetry install --no-root
```

## Usage

```
poetry run example.py
```
67 changes: 67 additions & 0 deletions python/examples/langchain/solana/example.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import os
from dotenv import load_dotenv

# Load environment variables
load_dotenv()

from langchain_openai import ChatOpenAI
from langchain.agents import AgentExecutor, create_tool_calling_agent
from langchain_core.prompts import ChatPromptTemplate
from solana.rpc.api import Client as SolanaClient
from solders.keypair import Keypair

from goat_adapters.langchain import get_on_chain_tools
from goat_wallets.solana import solana

# Initialize Solana client and wallet
client = SolanaClient(os.getenv("SOLANA_RPC_ENDPOINT"))
keypair = Keypair.from_base58_string(os.getenv("SOLANA_WALLET_SEED") or "")
wallet = solana(client, keypair)

# Initialize LLM
llm = ChatOpenAI(model="gpt-4o-mini")


def main():
# Get the prompt template
prompt = ChatPromptTemplate.from_messages(
[
("system", "You are a helpful assistant"),
("placeholder", "{chat_history}"),
("human", "{input}"),
("placeholder", "{agent_scratchpad}"),
]
)

# Initialize tools with Solana wallet
tools = get_on_chain_tools(
wallet=wallet,
plugins=[], # Add Solana specific plugins here when needed
)

agent = create_tool_calling_agent(llm, tools, prompt)
agent_executor = AgentExecutor(
agent=agent, tools=tools, handle_parsing_errors=True, verbose=True
)

while True:
user_input = input("\nYou: ").strip()

if user_input.lower() == "quit":
print("Goodbye!")
break

try:
response = agent_executor.invoke(
{
"input": user_input,
}
)

print("\nAssistant:", response["output"])
except Exception as e:
print("\nError:", str(e))


if __name__ == "__main__":
main()
2,286 changes: 2,286 additions & 0 deletions python/examples/langchain/solana/poetry.lock

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions python/examples/langchain/solana/poetry.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
[virtualenvs]
in-project = true
51 changes: 51 additions & 0 deletions python/examples/langchain/solana/pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
[tool.poetry]
name = "goat-sdk-example-langchain-solana"
version = "0.1.0"
description = "Goat example for Langchain with Solana"
authors = ["Andrea Villa <[email protected]>"]
readme = "README.md"
keywords = ["goat", "sdk", "solana", "agents", "ai"]
homepage = "https://ohmygoat.dev/"
repository = "https://github.com/goat-sdk/goat"
packages = [
{ include = "example.py" },
]

[tool.poetry.dependencies]
python = "^3.12"
langchain = "^0.3.2"
langchain-openai = "^0.2.14"
python-dotenv = "^1.0.1"
solana = "^0.30.2"
solders = "^0.18.0"
goat-sdk = "^0.1.0"
goat-sdk-wallet-solana = "^0.1.0"
goat-sdk-adapter-langchain = "^0.1.0"

[tool.poetry.group.test.dependencies]
pytest = "^8.3.4"
pytest-asyncio = "^0.25.0"

[tool.poetry.urls]
"Bug Tracker" = "https://github.com/goat-sdk/goat/issues"

[tool.pytest.ini_options]
addopts = [
"--import-mode=importlib",
]
pythonpath = "src"
asyncio_default_fixture_loop_scope = "function"

[build-system]
requires = ["poetry-core"]
build-backend = "poetry.core.masonry.api"

[tool.poetry.group.dev.dependencies]
ruff = "^0.8.6"
goat-sdk = { path = "../../../src/goat-sdk", develop = true }
goat-sdk-wallet-solana = { path = "../../../src/wallets/solana", develop = true }
goat-sdk-adapter-langchain = { path = "../../../src/adapters/langchain", develop = true }

[tool.ruff]
line-length = 120
target-version = "py312"
2 changes: 2 additions & 0 deletions python/examples/solana/wallet/.env.template
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
SOLANA_RPC_ENDPOINT=https://api.devnet.solana.com
SOLANA_WALLET_SEED=2JpXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
34 changes: 34 additions & 0 deletions python/examples/solana/wallet/example.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import os
from dotenv import load_dotenv
from solana.rpc.api import Client as SolanaClient
from solders.keypair import Keypair
from solders.instruction import Instruction
from typing import List, Optional
from goat_wallets.solana import solana, SolanaTransaction

# Load environment variables
load_dotenv()

# Initialize Solana client and keypair
client = SolanaClient(os.getenv("SOLANA_RPC_ENDPOINT"))
keypair = Keypair.from_base58_string(os.getenv("SOLANA_WALLET_SEED") or "")

# Create wallet instance
wallet = solana(client, keypair)

# Get wallet address
address = wallet.get_address()

# Check balance
balance = wallet.balance_of(address)

# Sign message
signature = wallet.sign_message("Hello, Solana!")

# Send transaction
transaction: SolanaTransaction = {
"instructions": [], # Add your Instruction objects here
"address_lookup_table_addresses": None, # Optional List[str]
"accounts_to_sign": None, # Optional List[Keypair]
}
result = wallet.send_transaction(transaction)
Loading

0 comments on commit 4040ead

Please sign in to comment.