Skip to content

Commit 03d83fb

Browse files
committed
feat: Adds functions to the solana agent kit plugin
1 parent 52f8cd2 commit 03d83fb

File tree

15 files changed

+947
-172
lines changed

15 files changed

+947
-172
lines changed

packages/plugin-solana-agentkit/src/actions/createToken.ts

+2-11
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,7 @@ import {
1111
State,
1212
type Action,
1313
} from "@elizaos/core";
14-
15-
import { SolanaAgentKit } from "solana-agent-kit";
16-
14+
import { getSAK } from "../client";
1715
export interface CreateTokenContent extends Content {
1816
name: string;
1917
uri: string;
@@ -103,14 +101,7 @@ export default {
103101
}
104102

105103
elizaLogger.log("Init solana agent kit...");
106-
const solanaPrivatekey = runtime.getSetting("SOLANA_PRIVATE_KEY");
107-
const rpc = runtime.getSetting("SOLANA_RPC_URL");
108-
const openAIKey = runtime.getSetting("OPENAI_API_KEY");
109-
const solanaAgentKit = new SolanaAgentKit(
110-
solanaPrivatekey,
111-
rpc,
112-
openAIKey
113-
);
104+
const solanaAgentKit = await getSAK(runtime);
114105
try {
115106
const deployedAddress = await solanaAgentKit.deployToken(
116107
content.name,

packages/plugin-solana/src/actions/getTokenInfo.ts packages/plugin-solana-agentkit/src/actions/getTokenInfo.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import {
1313
import { composeContext } from "@elizaos/core";
1414
import { generateObjectDeprecated } from "@elizaos/core";
1515
import { ACTIONS } from "solana-agent-kit";
16-
import { getSAK } from "../utils";
16+
import { getSAK } from "../client";
1717

1818
const GET_TOKEN_INFO_ACTION = ACTIONS.GET_TOKEN_DATA_ACTION;
1919

packages/plugin-solana/src/actions/gibwork.ts packages/plugin-solana-agentkit/src/actions/gibwork.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import {
1212
import { composeContext } from "@elizaos/core";
1313
import { generateObjectDeprecated } from "@elizaos/core";
1414
import { ACTIONS } from "solana-agent-kit";
15-
import { getSAK } from "../utils";
15+
import { getSAK } from "../client";
1616

1717
const GIBWORK_ACTION = ACTIONS.CREATE_GIBWORK_TASK_ACTION;
1818

packages/plugin-solana/src/actions/lend.ts packages/plugin-solana-agentkit/src/actions/lend.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import {
1212
import { composeContext } from "@elizaos/core";
1313
import { generateObjectDeprecated } from "@elizaos/core";
1414
import { ACTIONS } from "solana-agent-kit";
15-
import { getSAK } from "../utils";
15+
import { getSAK } from "../client";
1616

1717
const LEND_ASSET_ACTION = ACTIONS.LEND_ASSET_ACTION;
1818

packages/plugin-solana/src/actions/stake.ts packages/plugin-solana-agentkit/src/actions/stake.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import {
1212
import { composeContext } from "@elizaos/core";
1313
import { generateObjectDeprecated } from "@elizaos/core";
1414
import { ACTIONS } from "solana-agent-kit";
15-
import { getSAK } from "../utils";
15+
import { getSAK } from "../client";
1616

1717
const STAKE_ACTION = ACTIONS.STAKE_WITH_JUP_ACTION;
1818

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,205 @@
1+
import {
2+
ActionExample,
3+
composeContext,
4+
generateObjectDeprecated,
5+
HandlerCallback,
6+
IAgentRuntime,
7+
Memory,
8+
ModelClass,
9+
settings,
10+
State,
11+
type Action,
12+
elizaLogger,
13+
} from "@elizaos/core";
14+
import { Connection, PublicKey } from "@solana/web3.js";
15+
import { ACTIONS } from "solana-agent-kit";
16+
import { getSAK } from "../client";
17+
18+
const TRADE_ACTION = ACTIONS.TRADE_ACTION;
19+
20+
const swapTemplate = `Respond with a JSON markdown block containing only the extracted values. Use null for any values that cannot be determined.
21+
22+
Example response:
23+
\`\`\`json
24+
{
25+
"inputTokenSymbol": "SOL",
26+
"outputTokenSymbol": "USDC",
27+
"inputTokenCA": "So11111111111111111111111111111111111111112",
28+
"outputTokenCA": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
29+
"amount": 1.5
30+
}
31+
\`\`\`
32+
33+
{{recentMessages}}
34+
35+
Given the recent messages and wallet information below:
36+
37+
{{walletInfo}}
38+
39+
Extract the following information about the requested token swap:
40+
- Input token symbol (the token being sold)
41+
- Output token symbol (the token being bought)
42+
- Input token contract address if provided
43+
- Output token contract address if provided
44+
- Amount to swap
45+
46+
Respond with a JSON markdown block containing only the extracted values. Use null for any values that cannot be determined. The result should be a valid JSON object with the following schema:
47+
\`\`\`json
48+
{
49+
"inputTokenSymbol": string | null,
50+
"outputTokenSymbol": string | null,
51+
"inputTokenCA": string | null,
52+
"outputTokenCA": string | null,
53+
"amount": number | string | null
54+
}
55+
\`\`\``;
56+
57+
// if we get the token symbol but not the CA, check walet for matching token, and if we have, get the CA for it
58+
59+
export default {
60+
name: TRADE_ACTION.name,
61+
similes: TRADE_ACTION.similes,
62+
validate: async (runtime: IAgentRuntime, message: Memory) => {
63+
// Check if the necessary parameters are provided in the message
64+
elizaLogger.log("Message:", message);
65+
return true;
66+
},
67+
description: TRADE_ACTION.description,
68+
handler: async (
69+
runtime: IAgentRuntime,
70+
message: Memory,
71+
state: State,
72+
_options: { [key: string]: unknown },
73+
callback?: HandlerCallback
74+
): Promise<boolean> => {
75+
const sak = await getSAK(runtime);
76+
// composeState
77+
if (!state) {
78+
state = (await runtime.composeState(message)) as State;
79+
} else {
80+
state = await runtime.updateRecentMessageState(state);
81+
}
82+
83+
const swapContext = composeContext({
84+
state,
85+
template: swapTemplate,
86+
});
87+
88+
const response = await generateObjectDeprecated({
89+
runtime,
90+
context: swapContext,
91+
modelClass: ModelClass.LARGE,
92+
});
93+
94+
elizaLogger.log("Response:", response);
95+
// const type = response.inputTokenSymbol?.toUpperCase() === "SOL" ? "buy" : "sell";
96+
97+
// Add SOL handling logic
98+
if (response.inputTokenSymbol?.toUpperCase() === "SOL") {
99+
response.inputTokenCA = settings.SOL_ADDRESS;
100+
}
101+
if (response.outputTokenSymbol?.toUpperCase() === "SOL") {
102+
response.outputTokenCA = settings.SOL_ADDRESS;
103+
}
104+
105+
if (!response.amount) {
106+
elizaLogger.log("No amount provided, skipping swap");
107+
const responseMsg = {
108+
text: "I need the amount to perform the swap",
109+
};
110+
callback?.(responseMsg);
111+
return true;
112+
}
113+
114+
// TODO: if response amount is half, all, etc, semantically retrieve amount and return as number
115+
if (!response.amount) {
116+
elizaLogger.log("Amount is not a number, skipping swap");
117+
const responseMsg = {
118+
text: "The amount must be a number",
119+
};
120+
callback?.(responseMsg);
121+
return true;
122+
}
123+
try {
124+
const connection = new Connection(
125+
"https://api.mainnet-beta.solana.com"
126+
);
127+
128+
// const provider = new WalletProvider(connection, walletPublicKey);
129+
130+
console.log("Wallet Public Key:", sak.wallet_address.toString());
131+
console.log("inputTokenSymbol:", response.inputTokenCA);
132+
console.log("outputTokenSymbol:", response.outputTokenCA);
133+
console.log("amount:", response.amount);
134+
135+
const txid = await sak.trade(
136+
new PublicKey(response.outputTokenCA),
137+
response.amount,
138+
new PublicKey(response.inputTokenCA),
139+
);
140+
141+
const latestBlockhash = await connection.getLatestBlockhash();
142+
143+
const confirmation = await connection.confirmTransaction(
144+
{
145+
signature: txid,
146+
blockhash: latestBlockhash.blockhash,
147+
lastValidBlockHeight: latestBlockhash.lastValidBlockHeight,
148+
},
149+
"confirmed"
150+
);
151+
152+
if (confirmation.value.err) {
153+
throw new Error(
154+
`Transaction failed: ${confirmation.value.err}`
155+
);
156+
}
157+
158+
if (confirmation.value.err) {
159+
throw new Error(
160+
`Transaction failed: ${confirmation.value.err}`
161+
);
162+
}
163+
164+
elizaLogger.log("Swap completed successfully!");
165+
elizaLogger.log(`Transaction ID: ${txid}`);
166+
167+
const responseMsg = {
168+
text: `Swap completed successfully! Transaction ID: ${txid}`,
169+
};
170+
171+
callback?.(responseMsg);
172+
173+
return true;
174+
} catch (error) {
175+
elizaLogger.error("Error during token swap:", error);
176+
return false;
177+
}
178+
},
179+
examples: [
180+
[
181+
{
182+
user: "{{user1}}",
183+
content: {
184+
inputTokenSymbol: "SOL",
185+
outputTokenSymbol: "USDC",
186+
amount: 0.1,
187+
},
188+
},
189+
{
190+
user: "{{user2}}",
191+
content: {
192+
text: "Swapping 0.1 SOL for USDC...",
193+
action: "TOKEN_SWAP",
194+
},
195+
},
196+
{
197+
user: "{{user2}}",
198+
content: {
199+
text: "Swap completed successfully! Transaction ID: ...",
200+
},
201+
},
202+
],
203+
// Add more examples as needed
204+
] as ActionExample[][],
205+
} as Action;

0 commit comments

Comments
 (0)