Skip to content

Commit 14c71d3

Browse files
committed
feat: swap
1 parent 136f530 commit 14c71d3

File tree

2 files changed

+32
-127
lines changed

2 files changed

+32
-127
lines changed

packages/plugin-solana/src/actions/swap.ts

+9-127
Original file line numberDiff line numberDiff line change
@@ -10,94 +10,14 @@ import {
1010
State,
1111
type Action,
1212
} from "@elizaos/core";
13-
import { Connection, PublicKey, VersionedTransaction } from "@solana/web3.js";
14-
import BigNumber from "bignumber.js";
13+
import { Connection, PublicKey } from "@solana/web3.js";
1514
import { getWalletKey } from "../keypairUtils.ts";
1615
import { walletProvider, WalletProvider } from "../providers/wallet.ts";
17-
import { getTokenDecimals } from "./swapUtils.ts";
18-
import { SolanaAgentKit, ACTIONS } from "solana-agent-kit";
16+
import { ACTIONS } from "solana-agent-kit";
17+
import { getSAK } from "../utils";
1918

2019
const TRADE_ACTION = ACTIONS.TRADE_ACTION;
2120

22-
async function swapToken(
23-
connection: Connection,
24-
walletPublicKey: PublicKey,
25-
inputTokenCA: string,
26-
outputTokenCA: string,
27-
amount: number
28-
): Promise<any> {
29-
try {
30-
// Get the decimals for the input token
31-
const decimals =
32-
inputTokenCA === settings.SOL_ADDRESS
33-
? new BigNumber(9)
34-
: new BigNumber(
35-
await getTokenDecimals(connection, inputTokenCA)
36-
);
37-
38-
console.log("Decimals:", decimals.toString());
39-
40-
// Use BigNumber for adjustedAmount: amount * (10 ** decimals)
41-
const amountBN = new BigNumber(amount);
42-
const adjustedAmount = amountBN.multipliedBy(
43-
new BigNumber(10).pow(decimals)
44-
);
45-
46-
console.log("Fetching quote with params:", {
47-
inputMint: inputTokenCA,
48-
outputMint: outputTokenCA,
49-
amount: adjustedAmount,
50-
});
51-
52-
const quoteResponse = await fetch(
53-
`https://quote-api.jup.ag/v6/quote?inputMint=${inputTokenCA}&outputMint=${outputTokenCA}&amount=${adjustedAmount}&slippageBps=50`
54-
);
55-
const quoteData = await quoteResponse.json();
56-
57-
if (!quoteData || quoteData.error) {
58-
console.error("Quote error:", quoteData);
59-
throw new Error(
60-
`Failed to get quote: ${quoteData?.error || "Unknown error"}`
61-
);
62-
}
63-
64-
console.log("Quote received:", quoteData);
65-
66-
const swapRequestBody = {
67-
quoteResponse: quoteData,
68-
userPublicKey: walletPublicKey.toString(),
69-
wrapAndUnwrapSol: true,
70-
computeUnitPriceMicroLamports: 2000000,
71-
dynamicComputeUnitLimit: true,
72-
};
73-
74-
console.log("Requesting swap with body:", swapRequestBody);
75-
76-
const swapResponse = await fetch("https://quote-api.jup.ag/v6/swap", {
77-
method: "POST",
78-
headers: {
79-
"Content-Type": "application/json",
80-
},
81-
body: JSON.stringify(swapRequestBody),
82-
});
83-
84-
const swapData = await swapResponse.json();
85-
86-
if (!swapData || !swapData.swapTransaction) {
87-
console.error("Swap error:", swapData);
88-
throw new Error(
89-
`Failed to get swap transaction: ${swapData?.error || "No swap transaction returned"}`
90-
);
91-
}
92-
93-
console.log("Swap transaction received");
94-
return swapData;
95-
} catch (error) {
96-
console.error("Error in swapToken:", error);
97-
throw error;
98-
}
99-
}
100-
10121
const swapTemplate = `Respond with a JSON markdown block containing only the extracted values. Use null for any values that cannot be determined.
10222
10323
Example response:
@@ -185,6 +105,7 @@ export const executeSwap: Action = {
185105
_options: { [key: string]: unknown },
186106
callback?: HandlerCallback
187107
): Promise<boolean> => {
108+
const sak = await getSAK(runtime);
188109
// composeState
189110
if (!state) {
190111
state = (await runtime.composeState(message)) as State;
@@ -284,61 +205,22 @@ export const executeSwap: Action = {
284205
const connection = new Connection(
285206
"https://api.mainnet-beta.solana.com"
286207
);
287-
const { publicKey: walletPublicKey } = await getWalletKey(
288-
runtime,
289-
false
290-
);
291208

292209
// const provider = new WalletProvider(connection, walletPublicKey);
293210

294-
console.log("Wallet Public Key:", walletPublicKey);
211+
console.log("Wallet Public Key:", sak.wallet_address.toString());
295212
console.log("inputTokenSymbol:", response.inputTokenCA);
296213
console.log("outputTokenSymbol:", response.outputTokenCA);
297214
console.log("amount:", response.amount);
298215

299-
const swapResult = await swapToken(
300-
connection,
301-
walletPublicKey,
302-
response.inputTokenCA as string,
303-
response.outputTokenCA as string,
304-
response.amount as number
305-
);
306-
307-
console.log("Deserializing transaction...");
308-
const transactionBuf = Buffer.from(
309-
swapResult.swapTransaction,
310-
"base64"
216+
const txid = await sak.trade(
217+
new PublicKey(response.outputTokenCA),
218+
response.amount,
219+
new PublicKey(response.inputTokenCA),
311220
);
312-
const transaction =
313-
VersionedTransaction.deserialize(transactionBuf);
314-
315-
console.log("Preparing to sign transaction...");
316-
317-
console.log("Creating keypair...");
318-
const { keypair } = await getWalletKey(runtime, true);
319-
// Verify the public key matches what we expect
320-
if (keypair.publicKey.toBase58() !== walletPublicKey.toBase58()) {
321-
throw new Error(
322-
"Generated public key doesn't match expected public key"
323-
);
324-
}
325-
326-
console.log("Signing transaction...");
327-
transaction.sign([keypair]);
328-
329-
console.log("Sending transaction...");
330221

331222
const latestBlockhash = await connection.getLatestBlockhash();
332223

333-
const txid = await connection.sendTransaction(transaction, {
334-
skipPreflight: false,
335-
maxRetries: 3,
336-
preflightCommitment: "confirmed",
337-
});
338-
339-
console.log("Transaction sent:", txid);
340-
341-
// Confirm transaction using the blockhash
342224
const confirmation = await connection.confirmTransaction(
343225
{
344226
signature: txid,

packages/plugin-solana/src/utils.ts

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import { SolanaAgentKit } from "solana-agent-kit";
2+
import { IAgentRuntime } from "@elizaos/core";
3+
import { getWalletKey } from "./keypairUtils";
4+
import bs58 from "bs58";
5+
6+
export async function getSAK(runtime: IAgentRuntime) {
7+
const {publicKey} = await getWalletKey(runtime, false);
8+
const {keypair} = await getWalletKey(runtime, true);
9+
10+
if (keypair.publicKey.toBase58() !== publicKey.toBase58()) {
11+
throw new Error(
12+
"Generated public key doesn't match expected public key"
13+
);
14+
}
15+
16+
return new SolanaAgentKit(
17+
bs58.encode(keypair.secretKey),
18+
runtime.getSetting("SOLANA_RPC_URL"),
19+
{
20+
OPENAI_API_KEY: runtime.getSetting("OPENAI_API_KEY"),
21+
}
22+
);
23+
}

0 commit comments

Comments
 (0)