Skip to content

Commit 9b6479a

Browse files
committed
swapDao
Signed-off-by: MarcoMandar <malicemandar@gmail.com>
1 parent af5508e commit 9b6479a

File tree

3 files changed

+174
-2
lines changed

3 files changed

+174
-2
lines changed

core/src/actions/swapDao.ts

+168
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,168 @@
1+
import { Connection, Keypair, PublicKey, Transaction } from "@solana/web3.js";
2+
import fetch from "cross-fetch";
3+
import {
4+
ActionExample,
5+
IAgentRuntime,
6+
Memory,
7+
type Action,
8+
} from "../core/types.ts";
9+
10+
async function getQuote(
11+
baseToken: string,
12+
outputToken: string,
13+
amount: number
14+
): Promise<any> {
15+
const quoteResponse = await fetch(
16+
`https://quote-api.jup.ag/v6/quote?inputMint=${baseToken}&outputMint=${outputToken}&amount=${amount * 10 ** 6}&slippageBps=50`
17+
);
18+
const swapTransaction = await quoteResponse.json();
19+
const swapTransactionBuf = Buffer.from(swapTransaction, "base64");
20+
return new Uint8Array(swapTransactionBuf);
21+
}
22+
23+
async function invokeSwapDao(
24+
connection: Connection,
25+
authority: Keypair,
26+
statePDA: PublicKey,
27+
walletPDA: PublicKey,
28+
instructionData: Buffer
29+
): Promise<string> {
30+
const discriminator = new Uint8Array([
31+
25, 143, 207, 190, 174, 228, 130, 107,
32+
]);
33+
34+
// Combine discriminator and instructionData into a single Uint8Array
35+
const combinedData = new Uint8Array(
36+
discriminator.length + instructionData.length
37+
);
38+
combinedData.set(discriminator, 0);
39+
combinedData.set(instructionData, discriminator.length);
40+
41+
const transaction = new Transaction().add({
42+
programId: new PublicKey("PROGRAM_ID"),
43+
keys: [
44+
{ pubkey: authority.publicKey, isSigner: true, isWritable: true },
45+
{ pubkey: statePDA, isSigner: false, isWritable: true },
46+
{ pubkey: walletPDA, isSigner: false, isWritable: true },
47+
],
48+
data: Buffer.from(combinedData),
49+
});
50+
51+
const signature = await connection.sendTransaction(transaction, [
52+
authority,
53+
]);
54+
await connection.confirmTransaction(signature);
55+
return signature;
56+
}
57+
58+
async function promptConfirmation(): Promise<boolean> {
59+
// confirmation logic here
60+
const confirmSwap = window.confirm("Confirm the token swap?");
61+
return confirmSwap;
62+
}
63+
64+
export const executeSwap: Action = {
65+
name: "EXECUTE_SWAP_DAO",
66+
similes: ["SWAP_TOKENS_DAO", "TOKEN_SWAP_DAO"],
67+
validate: async (runtime: IAgentRuntime, message: Memory) => {
68+
console.log("Message:", message);
69+
return true;
70+
},
71+
description: "Perform a DAO token swap using execute_invoke.",
72+
handler: async (
73+
runtime: IAgentRuntime,
74+
message: Memory
75+
): Promise<boolean> => {
76+
const { inputToken, outputToken, amount } = message.content;
77+
78+
try {
79+
const connection = new Connection(
80+
"https://api.mainnet-beta.solana.com" // better if we use a better rpc
81+
);
82+
const authority = Keypair.fromSecretKey(
83+
Uint8Array.from(
84+
Buffer.from(
85+
runtime.getSetting("WALLET_PRIVATE_KEY"), // should be the authority private key
86+
"base64"
87+
)
88+
)
89+
);
90+
const daoMint = new PublicKey(runtime.getSetting("DAO_MINT")); // DAO mint address
91+
92+
// Derive PDAs
93+
const [statePDA] = await PublicKey.findProgramAddress(
94+
[Buffer.from("state"), daoMint.toBuffer()],
95+
authority.publicKey
96+
);
97+
const [walletPDA] = await PublicKey.findProgramAddress(
98+
[Buffer.from("wallet"), daoMint.toBuffer()],
99+
authority.publicKey
100+
);
101+
102+
const quoteData = await getQuote(
103+
inputToken as string,
104+
outputToken as string,
105+
amount as number
106+
);
107+
console.log("Swap Quote:", quoteData);
108+
109+
const confirmSwap = await promptConfirmation();
110+
if (!confirmSwap) {
111+
console.log("Swap canceled by user");
112+
return false;
113+
}
114+
115+
// Prepare instruction data for swap
116+
const instructionData = Buffer.from(
117+
JSON.stringify({
118+
quote: quoteData.data,
119+
userPublicKey: authority.publicKey.toString(),
120+
wrapAndUnwrapSol: true,
121+
})
122+
);
123+
124+
const txid = await invokeSwapDao(
125+
connection,
126+
authority,
127+
statePDA,
128+
walletPDA,
129+
instructionData
130+
);
131+
132+
console.log("DAO Swap completed successfully!");
133+
console.log(`Transaction ID: ${txid}`);
134+
135+
return true;
136+
} catch (error) {
137+
console.error("Error during DAO token swap:", error);
138+
return false;
139+
}
140+
},
141+
examples: [
142+
[
143+
{
144+
user: "{{user1}}",
145+
content: {
146+
inputTokenSymbol: "SOL",
147+
outputTokenSymbol: "USDC",
148+
inputToken: "So11111111111111111111111111111111111111112",
149+
outputToken: "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
150+
amount: 0.1,
151+
},
152+
},
153+
{
154+
user: "{{user2}}",
155+
content: {
156+
text: "Swapping 0.1 SOL for USDC using DAO...",
157+
action: "TOKEN_SWAP_DAO",
158+
},
159+
},
160+
{
161+
user: "{{user2}}",
162+
content: {
163+
text: "DAO Swap completed successfully! Transaction ID: ...",
164+
},
165+
},
166+
],
167+
] as ActionExample[][],
168+
} as Action;

core/src/actions/swapUtils.ts

+2
Original file line numberDiff line numberDiff line change
@@ -227,6 +227,7 @@ export const fetchBuyTransaction = async (
227227

228228
// deserialize the transaction
229229
const swapTransactionBuf = Buffer.from(swapTransaction, "base64");
230+
// @ts-expect-error ts-migrate(7006) FIXME: Parameter 'swapTransactionBuf' implicitly has an 'any' type.
230231
var transaction = VersionedTransaction.deserialize(swapTransactionBuf);
231232

232233
// sign the transaction
@@ -273,6 +274,7 @@ export const fetchSellTransaction = async (
273274

274275
// deserialize the transaction
275276
const swapTransactionBuf = Buffer.from(swapTransaction, "base64");
277+
// @ts-expect-error ts-migrate(7006) FIXME: Parameter 'swapTransactionBuf' implicitly has an 'any' type.
276278
var transaction = VersionedTransaction.deserialize(swapTransactionBuf);
277279

278280
// sign the transaction

core/src/providers/token.ts

+4-2
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { Connection } from "@solana/web3.js";
22
// import fetch from "cross-fetch";
33
import { IAgentRuntime, Memory, Provider, State } from "../core/types.ts";
44
import settings from "../core/settings.ts";
5-
import { toBN, BN } from '../utils/bignumber.js';
5+
import { toBN } from "../utils/bignumber.js";
66
import {
77
ProcessedTokenData,
88
TokenSecurityData,
@@ -620,7 +620,9 @@ export class TokenProvider {
620620
})
621621
.map((holder) => ({
622622
holderAddress: holder.address,
623-
balanceUsd: toBN(holder.balance).multipliedBy(tokenPriceUsd).toFixed(2),
623+
balanceUsd: toBN(holder.balance)
624+
.multipliedBy(tokenPriceUsd)
625+
.toFixed(2),
624626
}));
625627

626628
return highValueHolders;

0 commit comments

Comments
 (0)