Merge branch 'main' into feature/getBalanceOther

This commit is contained in:
aryan
2024-12-30 06:33:33 +05:30
25 changed files with 287 additions and 221 deletions

View File

@@ -31,7 +31,7 @@
},
"overrides": [
{
"files": ["test/**/*", "src/utils/keypair.ts"],
"files": ["test/**/*", "src/utils/keypair.ts", "examples/**/*"],
"rules": {
"no-console": "off"
}

View File

@@ -2,8 +2,6 @@
# Solana Agent Kit
![Solana Agent Kit Cover 1 (3)](https://github.com/user-attachments/assets/cfa380f6-79d9-474d-9852-3e1976c6de70)
@@ -25,6 +23,10 @@ An open-source toolkit for connecting AI agents to Solana protocols. Now, any ag
Anyone - whether an SF-based AI researcher or a crypto-native builder - can bring their AI agents trained with any model and seamlessly integrate with Solana.
[![Run on Repl.it](https://replit.com/badge/github/sendaifun/solana-agent-kit)](https://replit.com/@sendaifun/Solana-Agent-Kit)
> Replit template created by [Arpit Singh](https://github.com/The-x-35)
## 🔧 Core Blockchain Features
- **Token Operations**
@@ -237,6 +239,17 @@ The toolkit relies on several key Solana and Metaplex libraries:
Contributions are welcome! Please feel free to submit a Pull Request.
Refer to [CONTRIBUTING.md](CONTRIBUTING.md) for detailed guidelines on how to contribute to this project.
## Contributors
<a href="https://github.com/sendaifun/solana-agent-kit/graphs/contributors">
<img src="https://contrib.rocks/image?repo=sendaifun/solana-agent-kit" />
</a>
## Star History
[![Star History Chart](https://api.star-history.com/svg?repos=sendaifun/solana-agent-kit&type=Date)](https://star-history.com/#sendaifun/solana-agent-kit&Date)
## License
Apache-2 License

63
SECURITY.md Normal file
View File

@@ -0,0 +1,63 @@
# Security Policy
## Reporting a Vulnerability
We take the security of our software seriously. If you believe you have found a security vulnerability, please report it to us following these guidelines:
### Reporting Process
1. **DO NOT** create a public GitHub issue for the vulnerability
2. Email your findings to:
- Primary: aryan@sendai.fun
- Secondary: dev@sendai.fun
### What to Include
Please include the following information in your report:
- A clear description of the vulnerability
- Steps to reproduce the issue
- Affected versions
- Any potential impacts
- Optional: Suggested fixes or mitigations
### Response Timeline
- We will acknowledge receipt of your vulnerability report within 48 hours
- We aim to send a more detailed response within 5 business days
- We will keep you informed of our progress throughout the process
### Security Updates
Security updates will be released as soon as possible after we have confirmed and fixed the vulnerability. Updates will be published through:
- GitHub releases
- Security advisories
- Email notifications to affected parties (if applicable)
## Supported Versions
As an open-source project under the Apache 2.0 license, we focus our security updates on the latest stable release. While you're free to use any version as per the Apache 2.0 license terms, we strongly recommend using the most recent version for the best security posture.
| Version | Security Updates |
| ------- | --------------- |
| Latest Release | ✅ Active |
| Previous Releases | ⚠️ Use at your own risk |
Note: The Apache 2.0 license comes with NO WARRANTIES or CONDITIONS of any kind, either express or implied. Users are responsible for their own security assessment when using any version of this software.
## Security Best Practices
When using this software, please follow these security best practices:
- Keep your private keys secure and never share them
- Regularly update to the latest version
- Review transaction details before signing
- Use appropriate access controls in production environments
## Bug Bounty Program
Currently, we do not offer a bug bounty program. However, we greatly appreciate responsible disclosure of security vulnerabilities.
## License
This security policy is part of our project licensed under [Apache 2.0](LICENSE).

View File

@@ -1 +1 @@
window.navigationData = "data:application/octet-stream;base64,H4sIAAAAAAAAE42TwU7DMAyG3yXniooJJtTbRFUkGDCN3hCHEFwaNXWixBFMaO+O6BCsLPW45OIv3x/ZzuOHIHgnUYgHayTKxSsg3WgSmXCSWlEIZWQIEPJx/aSl3ohMdBpfRHE6u9hmP6ZLawwo0hZLcMZuesA9n0YC30gFIU+BY/HsfJ4U37uvMxyxflOs0oMk69OiXY27XgGpduW1gjUEZzFA0nSIcdIr/fxmfTfEQy1Dt4Zp9RTMBVxHpwl8bTvAUpJMiv9CnHAZjV0oZSNSCSS1CWw7pnEu5FYj/c72rqrZjEmai1jF3jURlzKiall9kjymriIO7eS2N8Gx2g21/1zCNMrJ1bBUu49fW2v2XtxEHBob8gNobJyfbZ8+AWWuiIJlBAAA"
window.navigationData = "data:application/octet-stream;base64,H4sIAAAAAAAAE42TwU4DIRCG34VzY2OjjemtcbMmWrWpezMeEKcuWZYhMEQb03cXt8a6lp164QAf3w/D8PghCN5JzMQDGmnl/BUs3WgSI+Ek1WleGRkChHF//aSm1iSo0fZFzE4nF9vRj+kSjQFFGm0BzuCmTVv2Pm0J/FqqpMyBffHkfJoV37uvMRyxflOs0oMk9HnRbo3bXgKpeum1ghUEl7IgazrEOOmVfn5D33TxUMnQrGBYPQRzAdfR6SSosAFbSJJZ8V+IEy6iwblSGC0VQFKbwJZjGOdCbpNh/7Z3ZcVmDNJcxDK2bh3tQkaralafJY+py2i7cnLdm+FY7YbqfzZhHuXkqmuq3cevEM2vE6e7d4UN4wOob5yebZ8+AWWuiIJlBAAA"

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -15,6 +15,10 @@
<li>And more...</li>
</ul>
<p>Anyone - whether an SF-based AI researcher or a crypto-native builder - can bring their AI agents trained with any model and seamlessly integrate with Solana.</p>
<p><a href="https://replit.com/@sendaifun/Solana-Agent-Kit" target="_blank" class="external"><img src="https://replit.com/badge/github/sendaifun/solana-agent-kit" alt="Run on Repl.it"></a></p>
<blockquote>
<p>Replit template created by <a href="https://github.com/The-x-35" target="_blank" class="external">Arpit Singh</a></p>
</blockquote>
<a id="md:🔧-core-blockchain-features" class="tsd-anchor"></a><h2 class="tsd-anchor-link">🔧 Core Blockchain Features<a href="#md:🔧-core-blockchain-features" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24"><use href="assets/icons.svg#icon-anchor"></use></svg></a></h2><ul>
<li>
<p><strong>Token Operations</strong></p>
@@ -149,6 +153,10 @@
</ul>
<a id="md:contributing" class="tsd-anchor"></a><h2 class="tsd-anchor-link">Contributing<a href="#md:contributing" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24"><use href="assets/icons.svg#icon-anchor"></use></svg></a></h2><p>Contributions are welcome! Please feel free to submit a Pull Request.
Refer to <a href="media/CONTRIBUTING.md">CONTRIBUTING.md</a> for detailed guidelines on how to contribute to this project.</p>
<a id="md:contributors" class="tsd-anchor"></a><h2 class="tsd-anchor-link">Contributors<a href="#md:contributors" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24"><use href="assets/icons.svg#icon-anchor"></use></svg></a></h2><a href="https://github.com/sendaifun/solana-agent-kit/graphs/contributors">
<img src="https://contrib.rocks/image?repo=sendaifun/solana-agent-kit" />
</a>
<a id="md:star-history" class="tsd-anchor"></a><h2 class="tsd-anchor-link">Star History<a href="#md:star-history" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24"><use href="assets/icons.svg#icon-anchor"></use></svg></a></h2><p><a href="https://star-history.com/#sendaifun/solana-agent-kit&amp;Date" target="_blank" class="external"><img src="https://api.star-history.com/svg?repos=sendaifun/solana-agent-kit&amp;type=Date" alt="Star History Chart"></a></p>
<a id="md:license" class="tsd-anchor"></a><h2 class="tsd-anchor-link">License<a href="#md:license" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24"><use href="assets/icons.svg#icon-anchor"></use></svg></a></h2><p>Apache-2 License</p>
<a id="md:security" class="tsd-anchor"></a><h2 class="tsd-anchor-link">Security<a href="#md:security" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24"><use href="assets/icons.svg#icon-anchor"></use></svg></a></h2><p>This toolkit handles private keys and transactions. Always ensure you're using it in a secure environment and never share your private keys.</p>
</div></div><div class="col-sidebar"><div class="page-menu"><div class="tsd-navigation settings"><details class="tsd-accordion"><summary class="tsd-accordion-summary"><h3><svg width="20" height="20" viewBox="0 0 24 24" fill="none"><use href="assets/icons.svg#icon-chevronDown"></use></svg>Settings</h3></summary><div class="tsd-accordion-details"><div class="tsd-filter-visibility"><span class="settings-label">Member Visibility</span><ul id="tsd-filter-options"><li class="tsd-filter-item"><label class="tsd-filter-input"><input type="checkbox" id="tsd-filter-protected" name="protected"/><svg width="32" height="32" viewBox="0 0 32 32" aria-hidden="true"><rect class="tsd-checkbox-background" width="30" height="30" x="1" y="1" rx="6" fill="none"></rect><path class="tsd-checkbox-checkmark" d="M8.35422 16.8214L13.2143 21.75L24.6458 10.25" stroke="none" stroke-width="3.5" stroke-linejoin="round" fill="none"></path></svg><span>Protected</span></label></li><li class="tsd-filter-item"><label class="tsd-filter-input"><input type="checkbox" id="tsd-filter-inherited" name="inherited" checked/><svg width="32" height="32" viewBox="0 0 32 32" aria-hidden="true"><rect class="tsd-checkbox-background" width="30" height="30" x="1" y="1" rx="6" fill="none"></rect><path class="tsd-checkbox-checkmark" d="M8.35422 16.8214L13.2143 21.75L24.6458 10.25" stroke="none" stroke-width="3.5" stroke-linejoin="round" fill="none"></path></svg><span>Inherited</span></label></li><li class="tsd-filter-item"><label class="tsd-filter-input"><input type="checkbox" id="tsd-filter-external" name="external"/><svg width="32" height="32" viewBox="0 0 32 32" aria-hidden="true"><rect class="tsd-checkbox-background" width="30" height="30" x="1" y="1" rx="6" fill="none"></rect><path class="tsd-checkbox-checkmark" d="M8.35422 16.8214L13.2143 21.75L24.6458 10.25" stroke="none" stroke-width="3.5" stroke-linejoin="round" fill="none"></path></svg><span>External</span></label></li></ul></div><div class="tsd-theme-toggle"><label class="settings-label" for="tsd-theme">Theme</label><select id="tsd-theme"><option value="os">OS</option><option value="light">Light</option><option value="dark">Dark</option></select></div></div></details></div><details open class="tsd-accordion tsd-page-navigation"><summary class="tsd-accordion-summary"><h3><svg width="20" height="20" viewBox="0 0 24 24" fill="none"><use href="assets/icons.svg#icon-chevronDown"></use></svg>On This Page</h3></summary><div class="tsd-accordion-details"><a href="#md:solana-agent-kit"><span>Solana <wbr/>Agent <wbr/>Kit</span></a><ul><li><a href="#md:🔧-core-blockchain-features"><span>🔧 <wbr/>Core <wbr/>Blockchain <wbr/>Features</span></a></li><li><a href="#md:🤖-ai-integration-features"><span>🤖 AI <wbr/>Integration <wbr/>Features</span></a></li><li><a href="#md:📦-installation"><span>📦 <wbr/>Installation</span></a></li><li><a href="#md:quick-start"><span>Quick <wbr/>Start</span></a></li><li><a href="#md:usage-examples"><span>Usage <wbr/>Examples</span></a></li><li><ul><li><a href="#md:deploy-a-new-token"><span>Deploy a <wbr/>New <wbr/>Token</span></a></li><li><a href="#md:create-nft-collection"><span>Create NFT <wbr/>Collection</span></a></li><li><a href="#md:swap-tokens"><span>Swap <wbr/>Tokens</span></a></li><li><a href="#md:lend-tokens"><span>Lend <wbr/>Tokens</span></a></li><li><a href="#md:stake-sol"><span>Stake SOL</span></a></li><li><a href="#md:send-an-spl-token-airdrop-via-zk-compression"><span>Send an SPL <wbr/>Token <wbr/>Airdrop via ZK <wbr/>Compression</span></a></li><li><a href="#md:fetch-price-data-from-pyth"><span>Fetch <wbr/>Price <wbr/>Data from <wbr/>Pyth</span></a></li></ul></li><li><a href="#md:examples"><span>Examples</span></a></li><li><ul><li><a href="#md:langgraph-multi-agent-system"><span>Lang<wbr/>Graph <wbr/>Multi-<wbr/>Agent <wbr/>System</span></a></li></ul></li><li><a href="#md:dependencies"><span>Dependencies</span></a></li><li><a href="#md:contributing"><span>Contributing</span></a></li><li><a href="#md:license"><span>License</span></a></li><li><a href="#md:security"><span>Security</span></a></li></ul></div></details></div><div class="site-menu"><nav class="tsd-navigation"><a href="modules.html" class="current"><svg class="tsd-kind-icon" viewBox="0 0 24 24"><use href="assets/icons.svg#icon-1"></use></svg><span>solana-agent-kit</span></a><ul class="tsd-small-nested-navigation" id="tsd-nav-container" data-base="."><li>Loading...</li></ul></nav></div></div></div><footer><p class="tsd-generator">Generated using <a href="https://typedoc.org/" target="_blank">TypeDoc</a></p></footer><div class="overlay"></div></body></html>
</div></div><div class="col-sidebar"><div class="page-menu"><div class="tsd-navigation settings"><details class="tsd-accordion"><summary class="tsd-accordion-summary"><h3><svg width="20" height="20" viewBox="0 0 24 24" fill="none"><use href="assets/icons.svg#icon-chevronDown"></use></svg>Settings</h3></summary><div class="tsd-accordion-details"><div class="tsd-filter-visibility"><span class="settings-label">Member Visibility</span><ul id="tsd-filter-options"><li class="tsd-filter-item"><label class="tsd-filter-input"><input type="checkbox" id="tsd-filter-protected" name="protected"/><svg width="32" height="32" viewBox="0 0 32 32" aria-hidden="true"><rect class="tsd-checkbox-background" width="30" height="30" x="1" y="1" rx="6" fill="none"></rect><path class="tsd-checkbox-checkmark" d="M8.35422 16.8214L13.2143 21.75L24.6458 10.25" stroke="none" stroke-width="3.5" stroke-linejoin="round" fill="none"></path></svg><span>Protected</span></label></li><li class="tsd-filter-item"><label class="tsd-filter-input"><input type="checkbox" id="tsd-filter-inherited" name="inherited" checked/><svg width="32" height="32" viewBox="0 0 32 32" aria-hidden="true"><rect class="tsd-checkbox-background" width="30" height="30" x="1" y="1" rx="6" fill="none"></rect><path class="tsd-checkbox-checkmark" d="M8.35422 16.8214L13.2143 21.75L24.6458 10.25" stroke="none" stroke-width="3.5" stroke-linejoin="round" fill="none"></path></svg><span>Inherited</span></label></li><li class="tsd-filter-item"><label class="tsd-filter-input"><input type="checkbox" id="tsd-filter-external" name="external"/><svg width="32" height="32" viewBox="0 0 32 32" aria-hidden="true"><rect class="tsd-checkbox-background" width="30" height="30" x="1" y="1" rx="6" fill="none"></rect><path class="tsd-checkbox-checkmark" d="M8.35422 16.8214L13.2143 21.75L24.6458 10.25" stroke="none" stroke-width="3.5" stroke-linejoin="round" fill="none"></path></svg><span>External</span></label></li></ul></div><div class="tsd-theme-toggle"><label class="settings-label" for="tsd-theme">Theme</label><select id="tsd-theme"><option value="os">OS</option><option value="light">Light</option><option value="dark">Dark</option></select></div></div></details></div><details open class="tsd-accordion tsd-page-navigation"><summary class="tsd-accordion-summary"><h3><svg width="20" height="20" viewBox="0 0 24 24" fill="none"><use href="assets/icons.svg#icon-chevronDown"></use></svg>On This Page</h3></summary><div class="tsd-accordion-details"><a href="#md:solana-agent-kit"><span>Solana <wbr/>Agent <wbr/>Kit</span></a><ul><li><a href="#md:🔧-core-blockchain-features"><span>🔧 <wbr/>Core <wbr/>Blockchain <wbr/>Features</span></a></li><li><a href="#md:🤖-ai-integration-features"><span>🤖 AI <wbr/>Integration <wbr/>Features</span></a></li><li><a href="#md:📦-installation"><span>📦 <wbr/>Installation</span></a></li><li><a href="#md:quick-start"><span>Quick <wbr/>Start</span></a></li><li><a href="#md:usage-examples"><span>Usage <wbr/>Examples</span></a></li><li><ul><li><a href="#md:deploy-a-new-token"><span>Deploy a <wbr/>New <wbr/>Token</span></a></li><li><a href="#md:create-nft-collection"><span>Create NFT <wbr/>Collection</span></a></li><li><a href="#md:swap-tokens"><span>Swap <wbr/>Tokens</span></a></li><li><a href="#md:lend-tokens"><span>Lend <wbr/>Tokens</span></a></li><li><a href="#md:stake-sol"><span>Stake SOL</span></a></li><li><a href="#md:send-an-spl-token-airdrop-via-zk-compression"><span>Send an SPL <wbr/>Token <wbr/>Airdrop via ZK <wbr/>Compression</span></a></li><li><a href="#md:fetch-price-data-from-pyth"><span>Fetch <wbr/>Price <wbr/>Data from <wbr/>Pyth</span></a></li></ul></li><li><a href="#md:examples"><span>Examples</span></a></li><li><ul><li><a href="#md:langgraph-multi-agent-system"><span>Lang<wbr/>Graph <wbr/>Multi-<wbr/>Agent <wbr/>System</span></a></li></ul></li><li><a href="#md:dependencies"><span>Dependencies</span></a></li><li><a href="#md:contributing"><span>Contributing</span></a></li><li><a href="#md:contributors"><span>Contributors</span></a></li><li><a href="#md:star-history"><span>Star <wbr/>History</span></a></li><li><a href="#md:license"><span>License</span></a></li><li><a href="#md:security"><span>Security</span></a></li></ul></div></details></div><div class="site-menu"><nav class="tsd-navigation"><a href="modules.html" class="current"><svg class="tsd-kind-icon" viewBox="0 0 24 24"><use href="assets/icons.svg#icon-1"></use></svg><span>solana-agent-kit</span></a><ul class="tsd-small-nested-navigation" id="tsd-nav-container" data-base="."><li>Loading...</li></ul></nav></div></div></div><footer><p class="tsd-generator">Generated using <a href="https://typedoc.org/" target="_blank">TypeDoc</a></p></footer><div class="overlay"></div></body></html>

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -1,7 +1,6 @@
import { createReactAgent } from "@langchain/langgraph/prebuilt";
import { gpt4o } from "../utils/model";
import { solanaAgentState } from "../utils/state";
import { HumanMessage } from "@langchain/core/messages";
import { agentKit } from "../utils/solanaAgent";
import {
SolanaBalanceTool,

View File

@@ -8,27 +8,30 @@ import * as readline from "readline";
import { PostgresSaver } from "@langchain/langgraph-checkpoint-postgres";
dotenv.config();
const checkpointer = PostgresSaver.fromConnString(
process.env.POSTGRES_DB_URL!
);
const checkpointer = PostgresSaver.fromConnString(process.env.POSTGRES_DB_URL!);
function validateEnvironment(): void {
const missingVars: string[] = [];
const requiredVars = ["OPENAI_API_KEY", "RPC_URL", "SOLANA_PRIVATE_KEY", "POSTGRES_DB_URL"];
const missingVars: string[] = [];
const requiredVars = [
"OPENAI_API_KEY",
"RPC_URL",
"SOLANA_PRIVATE_KEY",
"POSTGRES_DB_URL",
];
requiredVars.forEach((varName) => {
if (!process.env[varName]) {
missingVars.push(varName);
}
});
if (missingVars.length > 0) {
console.error("Error: Required environment variables are not set");
missingVars.forEach((varName) => {
console.error(`${varName}=your_${varName.toLowerCase()}_here`);
});
process.exit(1);
requiredVars.forEach((varName) => {
if (!process.env[varName]) {
missingVars.push(varName);
}
});
if (missingVars.length > 0) {
console.error("Error: Required environment variables are not set");
missingVars.forEach((varName) => {
console.error(`${varName}=your_${varName.toLowerCase()}_here`);
});
process.exit(1);
}
}
validateEnvironment();
@@ -36,37 +39,37 @@ validateEnvironment();
const WALLET_DATA_FILE = "wallet_data.txt";
async function initializeAgent() {
try {
const llm = new ChatOpenAI({
modelName: "gpt-4o-mini",
temperature: 0.7,
});
try {
const llm = new ChatOpenAI({
modelName: "gpt-4o-mini",
temperature: 0.7,
});
let walletDataStr: string | null = null;
let walletDataStr: string | null = null;
if (fs.existsSync(WALLET_DATA_FILE)) {
try {
walletDataStr = fs.readFileSync(WALLET_DATA_FILE, "utf8");
} catch (error) {
console.error("Error reading wallet data:", error);
}
}
if (fs.existsSync(WALLET_DATA_FILE)) {
try {
walletDataStr = fs.readFileSync(WALLET_DATA_FILE, "utf8");
} catch (error) {
console.error("Error reading wallet data:", error);
}
}
const solanaAgent = new SolanaAgentKit(
process.env.SOLANA_PRIVATE_KEY!,
process.env.RPC_URL,
process.env.OPENAI_API_KEY!,
);
const solanaAgent = new SolanaAgentKit(
process.env.SOLANA_PRIVATE_KEY!,
process.env.RPC_URL,
process.env.OPENAI_API_KEY!,
);
const tools = createSolanaTools(solanaAgent);
await checkpointer.setup();
const config = { configurable: { thread_id: "Solana Agent Kit!" } };
const tools = createSolanaTools(solanaAgent);
await checkpointer.setup();
const config = { configurable: { thread_id: "Solana Agent Kit!" } };
const agent = createReactAgent({
llm,
tools,
checkpointSaver: checkpointer,
messageModifier: `
const agent = createReactAgent({
llm,
tools,
checkpointSaver: checkpointer,
messageModifier: `
You are a helpful agent that can interact onchain using the Solana Agent Kit. You are
empowered to interact onchain using your tools. If you ever need funds, you can request them from the
faucet. If not, you can provide your wallet details and request funds from the user. If there is a 5XX
@@ -75,146 +78,146 @@ async function initializeAgent() {
themselves using the Solana Agent Kit, recommend they go to https://www.solanaagentkit.xyz for more information. Be
concise and helpful with your responses. Refrain from restating your tools' descriptions unless it is explicitly requested.
`,
});
});
if (walletDataStr) {
fs.writeFileSync(WALLET_DATA_FILE, walletDataStr);
}
return { agent, config };
} catch (error) {
console.error("Failed to initialize agent:", error);
throw error;
if (walletDataStr) {
fs.writeFileSync(WALLET_DATA_FILE, walletDataStr);
}
return { agent, config };
} catch (error) {
console.error("Failed to initialize agent:", error);
throw error;
}
}
async function runAutonomousMode(agent: any, config: any, interval = 10) {
console.log("Starting autonomous mode...");
console.log("Starting autonomous mode...");
while (true) {
try {
const thought =
"Be creative and do something interesting on the blockchain. " +
"Choose an action or set of actions and execute it that highlights your abilities.";
while (true) {
try {
const thought =
"Be creative and do something interesting on the blockchain. " +
"Choose an action or set of actions and execute it that highlights your abilities.";
const stream = await agent.stream(
{ messages: [new HumanMessage(thought)] },
config,
);
const stream = await agent.stream(
{ messages: [new HumanMessage(thought)] },
config,
);
for await (const chunk of stream) {
if ("agent" in chunk) {
console.log(chunk.agent.messages[0].content);
} else if ("tools" in chunk) {
console.log(chunk.tools.messages[0].content);
}
console.log("-------------------");
}
await new Promise((resolve) => setTimeout(resolve, interval * 1000));
} catch (error) {
if (error instanceof Error) {
console.error("Error:", error.message);
}
process.exit(1);
for await (const chunk of stream) {
if ("agent" in chunk) {
console.log(chunk.agent.messages[0].content);
} else if ("tools" in chunk) {
console.log(chunk.tools.messages[0].content);
}
console.log("-------------------");
}
await new Promise((resolve) => setTimeout(resolve, interval * 1000));
} catch (error) {
if (error instanceof Error) {
console.error("Error:", error.message);
}
process.exit(1);
}
}
}
async function runChatMode(agent: any, config: any) {
console.log("Starting chat mode... Type 'exit' to end.");
console.log("Starting chat mode... Type 'exit' to end.");
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout,
});
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout,
});
const question = (prompt: string): Promise<string> =>
new Promise((resolve) => rl.question(prompt, resolve));
const question = (prompt: string): Promise<string> =>
new Promise((resolve) => rl.question(prompt, resolve));
try {
while (true) {
const userInput = await question("\nPrompt: ");
try {
while (true) {
const userInput = await question("\nPrompt: ");
if (userInput.toLowerCase() === "exit") {
break;
}
if (userInput.toLowerCase() === "exit") {
break;
}
const stream = await agent.stream(
{ messages: [new HumanMessage(userInput)] },
config,
);
const stream = await agent.stream(
{ messages: [new HumanMessage(userInput)] },
config,
);
for await (const chunk of stream) {
if ("agent" in chunk) {
console.log(chunk.agent.messages[0].content);
} else if ("tools" in chunk) {
console.log(chunk.tools.messages[0].content);
}
console.log("-------------------");
}
for await (const chunk of stream) {
if ("agent" in chunk) {
console.log(chunk.agent.messages[0].content);
} else if ("tools" in chunk) {
console.log(chunk.tools.messages[0].content);
}
} catch (error) {
if (error instanceof Error) {
console.error("Error:", error.message);
}
process.exit(1);
} finally {
rl.close();
console.log("-------------------");
}
}
} catch (error) {
if (error instanceof Error) {
console.error("Error:", error.message);
}
process.exit(1);
} finally {
rl.close();
}
}
async function chooseMode(): Promise<"chat" | "auto"> {
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout,
});
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout,
});
const question = (prompt: string): Promise<string> =>
new Promise((resolve) => rl.question(prompt, resolve));
const question = (prompt: string): Promise<string> =>
new Promise((resolve) => rl.question(prompt, resolve));
while (true) {
console.log("\nAvailable modes:");
console.log("1. chat - Interactive chat mode");
console.log("2. auto - Autonomous action mode");
while (true) {
console.log("\nAvailable modes:");
console.log("1. chat - Interactive chat mode");
console.log("2. auto - Autonomous action mode");
const choice = (await question("\nChoose a mode (enter number or name): "))
.toLowerCase()
.trim();
const choice = (await question("\nChoose a mode (enter number or name): "))
.toLowerCase()
.trim();
rl.close();
rl.close();
if (choice === "1" || choice === "chat") {
return "chat";
} else if (choice === "2" || choice === "auto") {
return "auto";
}
console.log("Invalid choice. Please try again.");
if (choice === "1" || choice === "chat") {
return "chat";
} else if (choice === "2" || choice === "auto") {
return "auto";
}
console.log("Invalid choice. Please try again.");
}
}
async function main() {
try {
console.log("Starting Agent...");
const { agent, config } = await initializeAgent();
const mode = await chooseMode();
try {
console.log("Starting Agent...");
const { agent, config } = await initializeAgent();
const mode = await chooseMode();
if (mode === "chat") {
await runChatMode(agent, config);
} else {
await runAutonomousMode(agent, config);
}
} catch (error) {
if (error instanceof Error) {
console.error("Error:", error.message);
}
process.exit(1);
if (mode === "chat") {
await runChatMode(agent, config);
} else {
await runAutonomousMode(agent, config);
}
} catch (error) {
if (error instanceof Error) {
console.error("Error:", error.message);
}
process.exit(1);
}
}
if (require.main === module) {
main().catch((error) => {
console.error("Fatal error:", error);
process.exit(1);
});
main().catch((error) => {
console.error("Fatal error:", error);
process.exit(1);
});
}

View File

@@ -1,6 +1,6 @@
{
"name": "solana-agent-kit",
"version": "1.3.0",
"version": "1.3.1",
"description": "connect any ai agents to solana protocols",
"main": "dist/index.js",
"types": "dist/index.d.ts",
@@ -14,7 +14,7 @@
"format": "prettier --write \"src/**/*.ts\" \"test/**/*.ts\""
},
"engines": {
"node": ">=23.1.0",
"node": ">=22.0.0",
"pnpm": ">=8.0.0"
},
"keywords": [],

View File

@@ -9,7 +9,6 @@ import {
import { create_image } from "../tools/create_image";
import { BN } from "@coral-xyz/anchor";
import { FEE_TIERS } from "../tools";
import { toJSON } from "../utils/toJSON";
export class SolanaBalanceTool extends Tool {
name = "solana_balance";
@@ -361,7 +360,7 @@ export class SolanaRegisterDomainTool extends Tool {
protected async _call(input: string): Promise<string> {
try {
const parsedInput = toJSON(input);
const parsedInput = JSON.parse(input);
this.validateInput(parsedInput);
const tx = await this.solanaKit.registerDomain(
@@ -1298,7 +1297,7 @@ export class SolanaRockPaperScissorsTool extends Tool {
protected async _call(input: string): Promise<string> {
try {
const parsedInput = toJSON(input);
const parsedInput = JSON.parse(input);
this.validateInput(parsedInput);
const result = await this.solanaKit.rockPaperScissors(
Number(parsedInput['"amount"']),

View File

@@ -1,11 +1,7 @@
import {
VersionedTransaction,
PublicKey,
LAMPORTS_PER_SOL,
} from "@solana/web3.js";
import { VersionedTransaction, PublicKey } from "@solana/web3.js";
import { SolanaAgentKit } from "../index";
import { TOKENS, DEFAULT_OPTIONS, JUP_API } from "../constants";
import { getMint } from "@solana/spl-token";
/**
* Swap tokens using Jupiter Exchange
* @param agent SolanaAgentKit instance
@@ -23,12 +19,23 @@ export async function trade(
slippageBps: number = DEFAULT_OPTIONS.SLIPPAGE_BPS,
): Promise<string> {
try {
// Check if input token is native SOL
const isNativeSol = inputMint.equals(TOKENS.SOL);
// For native SOL, we use LAMPORTS_PER_SOL, otherwise fetch mint info
const inputDecimals = isNativeSol
? 9 // SOL always has 9 decimals
: (await getMint(agent.connection, inputMint)).decimals;
// Calculate the correct amount based on actual decimals
const scaledAmount = inputAmount * Math.pow(10, inputDecimals);
const quoteResponse = await (
await fetch(
`${JUP_API}/quote?` +
`inputMint=${inputMint.toString()}` +
`inputMint=${isNativeSol ? TOKENS.SOL.toString() : inputMint.toString()}` +
`&outputMint=${outputMint.toString()}` +
`&amount=${inputAmount * LAMPORTS_PER_SOL}` +
`&amount=${scaledAmount}` +
`&slippageBps=${slippageBps}` +
`&onlyDirectRoutes=true` +
`&maxAccounts=20`,

View File

@@ -1,26 +0,0 @@
export const toJSON = (str: string): any => {
try {
// Remove curly braces and split by comma
const pairs = str.trim().slice(1, -1).split(",");
// Convert to object with explicit type
const obj: Record<string, any> = {};
pairs.forEach((pair) => {
const [key, value] = pair
.trim()
.split(":")
.map((s) => s.trim());
if (!key || value === undefined) {
throw new Error("Invalid key-value pair format");
}
obj[key] = isNaN(Number(value)) ? value : Number(value);
});
return JSON.parse(JSON.stringify(obj));
} catch (error) {
throw new Error(`Failed to parse string to JSON: ${error}`);
}
};