diff --git a/README.md b/README.md
index c35d4fd431..818abfb9f3 100644
--- a/README.md
+++ b/README.md
@@ -102,7 +102,7 @@ XAI_MODEL=
 # For asking Claude stuff
 ANTHROPIC_API_KEY=
 
-WALLET_SECRET_KEY=EXAMPLE_WALLET_SECRET_KEY
+WALLET_PRIVATE_KEY=EXAMPLE_WALLET_PRIVATE_KEY
 WALLET_PUBLIC_KEY=EXAMPLE_WALLET_PUBLIC_KEY
 
 BIRDEYE_API_KEY=
diff --git a/core/.env.example b/core/.env.example
index dacbc26f9e..a26bd8b87d 100644
--- a/core/.env.example
+++ b/core/.env.example
@@ -30,7 +30,7 @@ XAI_MODEL=
 # For asking Claude stuff
 ANTHROPIC_API_KEY=
 
-WALLET_SECRET_KEY=EXAMPLE_WALLET_SECRET_KEY
+WALLET_PRIVATE_KEY=EXAMPLE_WALLET_PRIVATE_KEY
 WALLET_PUBLIC_KEY=EXAMPLE_WALLET_PUBLIC_KEY
 
 BIRDEYE_API_KEY=
diff --git a/core/src/actions/swap.ts b/core/src/actions/swap.ts
index a8540afb42..6a5a72e309 100644
--- a/core/src/actions/swap.ts
+++ b/core/src/actions/swap.ts
@@ -1,45 +1,181 @@
-import { Connection, Keypair, PublicKey, Transaction } from "@solana/web3.js";
+import {
+    Connection,
+    Keypair,
+    PublicKey,
+    Transaction,
+    VersionedTransaction,
+} from "@solana/web3.js";
 import fetch from "cross-fetch";
 import {
     ActionExample,
     IAgentRuntime,
     Memory,
     type Action,
+    State,
+    ModelClass,
+    HandlerCallback,
 } from "../core/types.ts";
+import { walletProvider } from "../providers/wallet.ts";
+import { composeContext } from "../core/context.ts";
+import { generateObject, generateObjectArray } from "../core/generation.ts";
+import { getTokenDecimals } from "./swapUtils.ts";
+import settings from "../core/settings.ts";
+import { bs58 } from "@coral-xyz/anchor/dist/cjs/utils/bytes/index.js";
+import BigNumber from "bignumber.js";
+import { WalletProvider } from "../providers/wallet.ts";
+import { TrustScoreProvider } from "../providers/trustScoreProvider";
+import { TokenProvider } from "../providers/token";
+import { TrustScoreDatabase } from "../adapters/trustScoreDatabase";
+import { v4 as uuidv4 } from "uuid";
 
 async function swapToken(
     connection: Connection,
     walletPublicKey: PublicKey,
-    inputTokenSymbol: string,
-    outputTokenSymbol: string,
+    inputTokenCA: string,
+    outputTokenCA: string,
     amount: number
 ): Promise<any> {
-    const quoteResponse = await fetch(
-        `https://quote-api.jup.ag/v6/quote?inputMint=${inputTokenSymbol}&outputMint=${outputTokenSymbol}&amount=${amount * 10 ** 6}&slippageBps=50`
-    );
-    const quoteData = await quoteResponse.json();
-
-    const swapResponse = await fetch("https://quote-api.jup.ag/v6/swap", {
-        method: "POST",
-        headers: {
-            "Content-Type": "application/json",
-        },
-        body: JSON.stringify({
-            quoteResponse: quoteData.data,
+    try {
+        // Get the decimals for the input token
+        const decimals =
+            inputTokenCA === settings.SOL_ADDRESS
+                ? new BigNumber(9)
+                : new BigNumber(
+                      await getTokenDecimals(connection, inputTokenCA)
+                  );
+
+        console.log("Decimals:", decimals.toString());
+
+        // Use BigNumber for adjustedAmount: amount * (10 ** decimals)
+        const amountBN = new BigNumber(amount);
+        const adjustedAmount = amountBN.multipliedBy(
+            new BigNumber(10).pow(decimals)
+        );
+
+        console.log("Fetching quote with params:", {
+            inputMint: inputTokenCA,
+            outputMint: outputTokenCA,
+            amount: adjustedAmount,
+        });
+
+        const quoteResponse = await fetch(
+            `https://quote-api.jup.ag/v6/quote?inputMint=${inputTokenCA}&outputMint=${outputTokenCA}&amount=${adjustedAmount}&slippageBps=50`
+        );
+        const quoteData = await quoteResponse.json();
+
+        if (!quoteData || quoteData.error) {
+            console.error("Quote error:", quoteData);
+            throw new Error(
+                `Failed to get quote: ${quoteData?.error || "Unknown error"}`
+            );
+        }
+
+        console.log("Quote received:", quoteData);
+
+        const swapRequestBody = {
+            quoteResponse: quoteData,
             userPublicKey: walletPublicKey.toString(),
             wrapAndUnwrapSol: true,
-        }),
-    });
+            computeUnitPriceMicroLamports: 1000,
+            dynamicComputeUnitLimit: true,
+        };
+
+        console.log("Requesting swap with body:", swapRequestBody);
+
+        const swapResponse = await fetch("https://quote-api.jup.ag/v6/swap", {
+            method: "POST",
+            headers: {
+                "Content-Type": "application/json",
+            },
+            body: JSON.stringify(swapRequestBody),
+        });
+
+        const swapData = await swapResponse.json();
+
+        if (!swapData || !swapData.swapTransaction) {
+            console.error("Swap error:", swapData);
+            throw new Error(
+                `Failed to get swap transaction: ${swapData?.error || "No swap transaction returned"}`
+            );
+        }
+
+        console.log("Swap transaction received");
+        return swapData;
+    } catch (error) {
+        console.error("Error in swapToken:", error);
+        throw error;
+    }
+}
+
+const swapTemplate = `Respond with a JSON markdown block containing only the extracted values. Use null for any values that cannot be determined.
 
-    return await swapResponse.json();
+Example response:
+\`\`\`json
+{
+    "inputTokenSymbol": "SOL",
+    "outputTokenSymbol": "USDC", 
+    "inputTokenCA": "So11111111111111111111111111111111111111112",
+    "outputTokenCA": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
+    "amount": 1.5
 }
+\`\`\`
 
-async function promptConfirmation(): Promise<boolean> {
-    // Implement your own confirmation logic here
-    // This is just a placeholder example
-    const confirmSwap = window.confirm("Confirm the token swap?");
-    return confirmSwap;
+{{recentMessages}}
+
+Given the recent messages and wallet information below:
+
+{{walletInfo}}
+
+Extract the following information about the requested token swap:
+- Input token symbol (the token being sold)
+- Output token symbol (the token being bought) 
+- Input token contract address if provided
+- Output token contract address if provided
+- Amount to swap
+
+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:
+\`\`\`json
+{
+    "inputTokenSymbol": string | null,
+    "outputTokenSymbol": string | null, 
+    "inputTokenCA": string | null,
+    "outputTokenCA": string | null,
+    "amount": number | string | null
 }
+\`\`\``;
+
+// if we get the token symbol but not the CA, check walet for matching token, and if we have, get the CA for it
+
+// get all the tokens in the wallet using the wallet provider
+async function getTokensInWallet(runtime: IAgentRuntime) {
+    const walletProvider = new WalletProvider(
+        new Connection("https://api.mainnet-beta.solana.com"),
+        new PublicKey(runtime.getSetting("WALLET_PUBLIC_KEY"))
+    );
+
+    const walletInfo = await walletProvider.fetchPortfolioValue(runtime);
+    const items = walletInfo.items;
+    return items;
+}
+
+// check if the token symbol is in the wallet
+async function getTokenFromWallet(runtime: IAgentRuntime, tokenSymbol: string) {
+    try {
+        const items = await getTokensInWallet(runtime);
+        const token = items.find((item) => item.symbol === tokenSymbol);
+
+        if (token) {
+            return token.address;
+        } else {
+            return null;
+        }
+    } catch (error) {
+        console.error("Error checking token in wallet:", error);
+        return null;
+    }
+}
+
+// swapToken should took CA, not symbol
 
 export const executeSwap: Action = {
     name: "EXECUTE_SWAP",
@@ -52,10 +188,107 @@ export const executeSwap: Action = {
     description: "Perform a token swap.",
     handler: async (
         runtime: IAgentRuntime,
-        message: Memory
+        message: Memory,
+        state: State,
+        _options: { [key: string]: unknown },
+        callback?: HandlerCallback
     ): Promise<boolean> => {
-        const { inputTokenSymbol, outputTokenSymbol, amount } = message.content;
+        // composeState
+        if (!state) {
+            state = (await runtime.composeState(message)) as State;
+        } else {
+            state = await runtime.updateRecentMessageState(state);
+        }
+
+        const walletInfo = await walletProvider.get(runtime, message, state);
+
+        state.walletInfo = walletInfo;
+
+        const swapContext = composeContext({
+            state,
+            template: swapTemplate,
+        });
+
+        const response = await generateObject({
+            runtime,
+            context: swapContext,
+            modelClass: ModelClass.LARGE,
+        });
+
+        console.log("Response:", response);
+        const type =
+            response.inputTokenSymbol?.toUpperCase() === "SOL" ? "buy" : "sell";
+
+        // Add SOL handling logic
+        if (response.inputTokenSymbol?.toUpperCase() === "SOL") {
+            response.inputTokenCA = settings.SOL_ADDRESS;
+        }
+        if (response.outputTokenSymbol?.toUpperCase() === "SOL") {
+            response.outputTokenCA = settings.SOL_ADDRESS;
+        }
 
+        // if both contract addresses are set, lets execute the swap
+        // TODO: try to resolve CA from symbol based on existing symbol in wallet
+        if (!response.inputTokenCA && response.inputTokenSymbol) {
+            console.log(
+                `Attempting to resolve CA for input token symbol: ${response.inputTokenSymbol}`
+            );
+            response.inputTokenCA = await getTokenFromWallet(
+                runtime,
+                response.inputTokenSymbol
+            );
+            if (response.inputTokenCA) {
+                console.log(`Resolved inputTokenCA: ${response.inputTokenCA}`);
+            } else {
+                console.log("No contract addresses provided, skipping swap");
+                const responseMsg = {
+                    text: "I need the contract addresses to perform the swap",
+                };
+                callback?.(responseMsg);
+                return true;
+            }
+        }
+
+        if (!response.outputTokenCA && response.outputTokenSymbol) {
+            console.log(
+                `Attempting to resolve CA for output token symbol: ${response.outputTokenSymbol}`
+            );
+            response.outputTokenCA = await getTokenFromWallet(
+                runtime,
+                response.outputTokenSymbol
+            );
+            if (response.outputTokenCA) {
+                console.log(
+                    `Resolved outputTokenCA: ${response.outputTokenCA}`
+                );
+            } else {
+                console.log("No contract addresses provided, skipping swap");
+                const responseMsg = {
+                    text: "I need the contract addresses to perform the swap",
+                };
+                callback?.(responseMsg);
+                return true;
+            }
+        }
+
+        if (!response.amount) {
+            console.log("No amount provided, skipping swap");
+            const responseMsg = {
+                text: "I need the amount to perform the swap",
+            };
+            callback?.(responseMsg);
+            return true;
+        }
+
+        // TODO: if response amount is half, all, etc, semantically retrieve amount and return as number
+        if (!response.amount) {
+            console.log("Amount is not a number, skipping swap");
+            const responseMsg = {
+                text: "The amount must be a number",
+            };
+            callback?.(responseMsg);
+            return true;
+        }
         try {
             const connection = new Connection(
                 "https://api.mainnet-beta.solana.com"
@@ -64,40 +297,174 @@ export const executeSwap: Action = {
                 runtime.getSetting("WALLET_PUBLIC_KEY")
             );
 
+            console.log("Wallet Public Key:", walletPublicKey);
+            console.log("inputTokenSymbol:", response.inputTokenCA);
+            console.log("outputTokenSymbol:", response.outputTokenCA);
+            console.log("amount:", response.amount);
+
             const swapResult = await swapToken(
                 connection,
                 walletPublicKey,
-                inputTokenSymbol as string,
-                outputTokenSymbol as string,
-                amount as number
+                response.inputTokenCA as string,
+                response.outputTokenCA as string,
+                response.amount as number
             );
 
-            console.log("Swap Quote:");
-            console.log(swapResult.quote);
+            console.log("Deserializing transaction...");
+            const transactionBuf = Buffer.from(
+                swapResult.swapTransaction,
+                "base64"
+            );
+            const transaction =
+                VersionedTransaction.deserialize(transactionBuf);
 
-            const confirmSwap = await promptConfirmation();
-            if (!confirmSwap) {
-                console.log("Swap canceled by user");
-                return false;
+            console.log("Preparing to sign transaction...");
+            const privateKeyString = runtime.getSetting("WALLET_PRIVATE_KEY");
+
+            // Handle different private key formats
+            let secretKey: Uint8Array;
+            try {
+                // First try to decode as base58
+                secretKey = bs58.decode(privateKeyString);
+            } catch (e) {
+                try {
+                    // If that fails, try base64
+                    secretKey = Uint8Array.from(
+                        Buffer.from(privateKeyString, "base64")
+                    );
+                } catch (e2) {
+                    throw new Error("Invalid private key format");
+                }
             }
 
-            const transaction = Transaction.from(
-                Buffer.from(swapResult.swapTransaction, "base64")
-            );
-            const privateKey = runtime.getSetting("WALLET_PRIVATE_KEY");
-            const keypair = Keypair.fromSecretKey(
-                Uint8Array.from(Buffer.from(privateKey, "base64"))
-            );
-            transaction.sign(keypair);
+            // Verify the key length
+            if (secretKey.length !== 64) {
+                console.error("Invalid key length:", secretKey.length);
+                throw new Error(
+                    `Invalid private key length: ${secretKey.length}. Expected 64 bytes.`
+                );
+            }
+
+            console.log("Creating keypair...");
+            const keypair = Keypair.fromSecretKey(secretKey);
+
+            // Verify the public key matches what we expect
+            const expectedPublicKey = runtime.getSetting("WALLET_PUBLIC_KEY");
+            if (keypair.publicKey.toBase58() !== expectedPublicKey) {
+                throw new Error(
+                    "Generated public key doesn't match expected public key"
+                );
+            }
+
+            console.log("Signing transaction...");
+            transaction.sign([keypair]);
 
-            const txid = await connection.sendRawTransaction(
-                transaction.serialize()
+            console.log("Sending transaction...");
+
+            const latestBlockhash = await connection.getLatestBlockhash();
+
+            const txid = await connection.sendTransaction(transaction, {
+                skipPreflight: false,
+                maxRetries: 3,
+                preflightCommitment: "confirmed",
+            });
+
+            console.log("Transaction sent:", txid);
+
+            // Confirm transaction using the blockhash
+            const confirmation = await connection.confirmTransaction(
+                {
+                    signature: txid,
+                    blockhash: latestBlockhash.blockhash,
+                    lastValidBlockHeight: latestBlockhash.lastValidBlockHeight,
+                },
+                "confirmed"
             );
-            await connection.confirmTransaction(txid);
+
+            if (confirmation.value.err) {
+                throw new Error(
+                    `Transaction failed: ${confirmation.value.err}`
+                );
+            }
+
+            if (confirmation.value.err) {
+                throw new Error(
+                    `Transaction failed: ${confirmation.value.err}`
+                );
+            }
+
+            if (type === "buy") {
+                const tokenProvider = new TokenProvider(response.outputTokenCA);
+                const module = await import("better-sqlite3");
+                const Database = module.default;
+                const trustScoreDb = new TrustScoreDatabase(
+                    new Database(":memory:")
+                );
+                // add or get recommender
+                const uuid = uuidv4();
+                const recommender = await trustScoreDb.getOrCreateRecommender({
+                    id: uuid,
+                    address: walletPublicKey.toString(),
+                    solanaPubkey: walletPublicKey.toString(),
+                });
+
+                const trustScoreDatabase = new TrustScoreProvider(
+                    tokenProvider,
+                    trustScoreDb
+                );
+                // save the trade
+                const tradeData = {
+                    buy_amount: response.amount,
+                    is_simulation: false,
+                };
+                await trustScoreDatabase.createTradePerformance(
+                    response.outputTokenCA,
+                    recommender.id,
+                    tradeData
+                );
+            } else if (type === "sell") {
+                const tokenProvider = new TokenProvider(response.inputTokenCA);
+                const module = await import("better-sqlite3");
+                const Database = module.default;
+                const trustScoreDb = new TrustScoreDatabase(
+                    new Database(":memory:")
+                );
+                // add or get recommender
+                const uuid = uuidv4();
+                const recommender = await trustScoreDb.getOrCreateRecommender({
+                    id: uuid,
+                    address: walletPublicKey.toString(),
+                    solanaPubkey: walletPublicKey.toString(),
+                });
+
+                const trustScoreDatabase = new TrustScoreProvider(
+                    tokenProvider,
+                    trustScoreDb
+                );
+                // save the trade
+                const sellDetails = {
+                    sell_amount: response.amount,
+                    sell_recommender_id: recommender.id,
+                };
+                const sellTimeStamp = new Date().getTime().toString();
+                await trustScoreDatabase.updateSellDetails(
+                    response.inputTokenCA,
+                    recommender.id,
+                    sellTimeStamp,
+                    sellDetails,
+                    false
+                );
+            }
 
             console.log("Swap completed successfully!");
             console.log(`Transaction ID: ${txid}`);
 
+            const responseMsg = {
+                text: `Swap completed successfully! Transaction ID: ${txid}`,
+            };
+
+            callback?.(responseMsg);
+
             return true;
         } catch (error) {
             console.error("Error during token swap:", error);
diff --git a/core/src/actions/swapDao.ts b/core/src/actions/swapDao.ts
new file mode 100644
index 0000000000..18d58187b5
--- /dev/null
+++ b/core/src/actions/swapDao.ts
@@ -0,0 +1,157 @@
+import { Connection, Keypair, PublicKey, Transaction } from "@solana/web3.js";
+import fetch from "cross-fetch";
+import {
+    ActionExample,
+    IAgentRuntime,
+    Memory,
+    type Action,
+} from "../core/types.ts";
+import { getQuote } from "./swapUtils.ts";
+
+async function invokeSwapDao(
+    connection: Connection,
+    authority: Keypair,
+    statePDA: PublicKey,
+    walletPDA: PublicKey,
+    instructionData: Buffer
+): Promise<string> {
+    const discriminator = new Uint8Array([
+        25, 143, 207, 190, 174, 228, 130, 107,
+    ]);
+
+    // Combine discriminator and instructionData into a single Uint8Array
+    const combinedData = new Uint8Array(
+        discriminator.length + instructionData.length
+    );
+    combinedData.set(discriminator, 0);
+    combinedData.set(instructionData, discriminator.length);
+
+    const transaction = new Transaction().add({
+        programId: new PublicKey("PROGRAM_ID"),
+        keys: [
+            { pubkey: authority.publicKey, isSigner: true, isWritable: true },
+            { pubkey: statePDA, isSigner: false, isWritable: true },
+            { pubkey: walletPDA, isSigner: false, isWritable: true },
+        ],
+        data: Buffer.from(combinedData),
+    });
+
+    const signature = await connection.sendTransaction(transaction, [
+        authority,
+    ]);
+    await connection.confirmTransaction(signature);
+    return signature;
+}
+
+async function promptConfirmation(): Promise<boolean> {
+    // confirmation logic here
+    const confirmSwap = window.confirm("Confirm the token swap?");
+    return confirmSwap;
+}
+
+export const executeSwap: Action = {
+    name: "EXECUTE_SWAP_DAO",
+    similes: ["SWAP_TOKENS_DAO", "TOKEN_SWAP_DAO"],
+    validate: async (runtime: IAgentRuntime, message: Memory) => {
+        console.log("Message:", message);
+        return true;
+    },
+    description: "Perform a DAO token swap using execute_invoke.",
+    handler: async (
+        runtime: IAgentRuntime,
+        message: Memory
+    ): Promise<boolean> => {
+        const { inputToken, outputToken, amount } = message.content;
+
+        try {
+            const connection = new Connection(
+                "https://api.mainnet-beta.solana.com" // better if we use a better rpc
+            );
+            const authority = Keypair.fromSecretKey(
+                Uint8Array.from(
+                    Buffer.from(
+                        runtime.getSetting("WALLET_PRIVATE_KEY"), // should be the authority private key
+                        "base64"
+                    )
+                )
+            );
+            const daoMint = new PublicKey(runtime.getSetting("DAO_MINT")); // DAO mint address
+
+            // Derive PDAs
+            const [statePDA] = await PublicKey.findProgramAddress(
+                [Buffer.from("state"), daoMint.toBuffer()],
+                authority.publicKey
+            );
+            const [walletPDA] = await PublicKey.findProgramAddress(
+                [Buffer.from("wallet"), daoMint.toBuffer()],
+                authority.publicKey
+            );
+
+            const quoteData = await getQuote(
+                connection as Connection,
+                inputToken as string,
+                outputToken as string,
+                amount as number
+            );
+            console.log("Swap Quote:", quoteData);
+
+            const confirmSwap = await promptConfirmation();
+            if (!confirmSwap) {
+                console.log("Swap canceled by user");
+                return false;
+            }
+
+            // Prepare instruction data for swap
+            const instructionData = Buffer.from(
+                JSON.stringify({
+                    quote: quoteData.data,
+                    userPublicKey: authority.publicKey.toString(),
+                    wrapAndUnwrapSol: true,
+                })
+            );
+
+            const txid = await invokeSwapDao(
+                connection,
+                authority,
+                statePDA,
+                walletPDA,
+                instructionData
+            );
+
+            console.log("DAO Swap completed successfully!");
+            console.log(`Transaction ID: ${txid}`);
+
+            return true;
+        } catch (error) {
+            console.error("Error during DAO token swap:", error);
+            return false;
+        }
+    },
+    examples: [
+        [
+            {
+                user: "{{user1}}",
+                content: {
+                    inputTokenSymbol: "SOL",
+                    outputTokenSymbol: "USDC",
+                    inputToken: "So11111111111111111111111111111111111111112",
+                    outputToken: "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
+                    amount: 0.1,
+                },
+            },
+            {
+                user: "{{user2}}",
+                content: {
+                    text: "Swapping 0.1 SOL for USDC using DAO...",
+                    action: "TOKEN_SWAP_DAO",
+                },
+            },
+            {
+                user: "{{user2}}",
+                content: {
+                    text: "DAO Swap completed successfully! Transaction ID: ...",
+                },
+            },
+        ],
+    ] as ActionExample[][],
+} as Action;
diff --git a/core/src/actions/swapUtils.ts b/core/src/actions/swapUtils.ts
index 1f025b3f6a..1a583eb841 100644
--- a/core/src/actions/swapUtils.ts
+++ b/core/src/actions/swapUtils.ts
@@ -26,6 +26,46 @@ export async function delayedCall<T>(
     return method(...args);
 }
 
+export async function getTokenDecimals(
+    connection: Connection,
+    mintAddress: string
+): Promise<number> {
+    const mintPublicKey = new PublicKey(mintAddress);
+    const tokenAccountInfo =
+        await connection.getParsedAccountInfo(mintPublicKey);
+
+    // Check if the data is parsed and contains the expected structure
+    if (
+        tokenAccountInfo.value &&
+        typeof tokenAccountInfo.value.data === "object" &&
+        "parsed" in tokenAccountInfo.value.data
+    ) {
+        const parsedInfo = tokenAccountInfo.value.data.parsed?.info;
+        if (parsedInfo && typeof parsedInfo.decimals === "number") {
+            return parsedInfo.decimals;
+        }
+    }
+
+    throw new Error("Unable to fetch token decimals");
+}
+
+export async function getQuote(
+    connection: Connection,
+    baseToken: string,
+    outputToken: string,
+    amount: number
+): Promise<any> {
+    const decimals = await getTokenDecimals(connection, baseToken);
+    const adjustedAmount = amount * 10 ** decimals;
+
+    const quoteResponse = await fetch(
+        `https://quote-api.jup.ag/v6/quote?inputMint=${baseToken}&outputMint=${outputToken}&amount=${adjustedAmount}&slippageBps=50`
+    );
+    const swapTransaction = await quoteResponse.json();
+    const swapTransactionBuf = Buffer.from(swapTransaction, "base64");
+    return new Uint8Array(swapTransactionBuf);
+}
+
 export const executeSwap = async (
     transaction: VersionedTransaction,
     type: "buy" | "sell"
@@ -227,7 +267,8 @@ export const fetchBuyTransaction = async (
 
         // deserialize the transaction
         const swapTransactionBuf = Buffer.from(swapTransaction, "base64");
-        var transaction = VersionedTransaction.deserialize(swapTransactionBuf);
+        const transaction =
+            VersionedTransaction.deserialize(swapTransactionBuf);
 
         // sign the transaction
         transaction.sign([wallet]);
@@ -273,7 +314,8 @@ export const fetchSellTransaction = async (
 
         // deserialize the transaction
         const swapTransactionBuf = Buffer.from(swapTransaction, "base64");
-        var transaction = VersionedTransaction.deserialize(swapTransactionBuf);
+        const transaction =
+            VersionedTransaction.deserialize(swapTransactionBuf);
 
         // sign the transaction
         transaction.sign([wallet]);
diff --git a/core/src/adapters/trustScoreDatabase.ts b/core/src/adapters/trustScoreDatabase.ts
index b206fd1923..5ef6231f5e 100644
--- a/core/src/adapters/trustScoreDatabase.ts
+++ b/core/src/adapters/trustScoreDatabase.ts
@@ -172,7 +172,7 @@ export class TrustScoreDatabase {
                 risk_score REAL DEFAULT 0,
                 consistency_score REAL DEFAULT 0,
                 virtual_confidence REAL DEFAULT 0,
-                last_active_date DATETIME DEFAULT CURRENT_TIMESTAMP
+                last_active_date DATETIME DEFAULT CURRENT_TIMESTAMP,
                 trust_decay REAL DEFAULT 0,
                 last_updated DATETIME DEFAULT CURRENT_TIMESTAMP,
                 FOREIGN KEY (recommender_id) REFERENCES recommenders(id) ON DELETE CASCADE
@@ -349,6 +349,61 @@ export class TrustScoreDatabase {
         return recommender || null;
     }
 
+    /**
+     * Retrieves an existing recommender or creates a new one if not found.
+     * Also initializes metrics for the recommender if they haven't been initialized yet.
+     * @param recommender Recommender object containing at least one identifier
+     * @returns Recommender object with all details, or null if failed
+     */
+    getOrCreateRecommender(recommender: Recommender): Recommender | null {
+        try {
+            // Begin a transaction
+            const transaction = this.db.transaction(() => {
+                // Attempt to retrieve the recommender
+                const existingRecommender = this.getRecommender(
+                    recommender.address
+                );
+                if (existingRecommender) {
+                    // Recommender exists, ensure metrics are initialized
+                    this.initializeRecommenderMetrics(existingRecommender.id!);
+                    return existingRecommender;
+                }
+
+                // Recommender does not exist, create a new one
+                const newRecommenderId = this.addRecommender(recommender);
+                if (!newRecommenderId) {
+                    throw new Error("Failed to add new recommender.");
+                }
+
+                // Initialize metrics for the new recommender
+                const metricsInitialized =
+                    this.initializeRecommenderMetrics(newRecommenderId);
+                if (!metricsInitialized) {
+                    throw new Error(
+                        "Failed to initialize recommender metrics."
+                    );
+                }
+
+                // Retrieve and return the newly created recommender
+                const newRecommender = this.getRecommender(newRecommenderId);
+                if (!newRecommender) {
+                    throw new Error(
+                        "Failed to retrieve the newly created recommender."
+                    );
+                }
+
+                return newRecommender;
+            });
+
+            // Execute the transaction and return the recommender
+            const recommenderResult = transaction();
+            return recommenderResult;
+        } catch (error) {
+            console.error("Error in getOrCreateRecommender:", error);
+            return null;
+        }
+    }
+
     /**
      * Initializes metrics for a recommender if not present.
      * @param recommenderId Recommender's UUID
@@ -548,6 +603,8 @@ export class TrustScoreDatabase {
                 performance.tokenAddress,
                 performance.priceChange24h,
                 performance.volumeChange24h,
+                performance.trade_24h_change,
+                performance.liquidity,
                 performance.liquidityChange24h,
                 performance.holderChange24h, // Ensure column name matches schema
                 performance.rugPull ? 1 : 0,
@@ -916,7 +973,7 @@ export class TrustScoreDatabase {
             market_cap_change = ?,
             sell_liquidity = ?,
             liquidity_change = ?,
-            rapidDump = ?
+            rapidDump = ?,
             sell_recommender_id = ?
         WHERE
             token_address = ?
@@ -1016,6 +1073,56 @@ export class TrustScoreDatabase {
         };
     }
 
+    /**
+     * Retrieves the latest trade performance metrics without requiring buyTimeStamp.
+     * @param tokenAddress Token's address
+     * @param recommenderId Recommender's UUID
+     * @param isSimulation Whether the trade is a simulation. If true, retrieves from simulation_trade; otherwise, from trade.
+     * @returns TradePerformance object or null
+     */
+    getLatestTradePerformance(
+        tokenAddress: string,
+        recommenderId: string,
+        isSimulation: boolean
+    ): TradePerformance | null {
+        const tableName = isSimulation ? "simulation_trade" : "trade";
+        const sql = `
+        SELECT * FROM ${tableName}
+        WHERE token_address = ? AND recommender_id = ?
+        ORDER BY buy_timeStamp DESC
+        LIMIT 1;
+    `;
+        const row = this.db.prepare(sql).get(tokenAddress, recommenderId) as
+            | TradePerformance
+            | undefined;
+        if (!row) return null;
+
+        return {
+            token_address: row.token_address,
+            recommender_id: row.recommender_id,
+            buy_price: row.buy_price,
+            sell_price: row.sell_price,
+            buy_timeStamp: row.buy_timeStamp,
+            sell_timeStamp: row.sell_timeStamp,
+            buy_amount: row.buy_amount,
+            sell_amount: row.sell_amount,
+            buy_sol: row.buy_sol,
+            received_sol: row.received_sol,
+            buy_value_usd: row.buy_value_usd,
+            sell_value_usd: row.sell_value_usd,
+            profit_usd: row.profit_usd,
+            profit_percent: row.profit_percent,
+            buy_market_cap: row.buy_market_cap,
+            sell_market_cap: row.sell_market_cap,
+            market_cap_change: row.market_cap_change,
+            buy_liquidity: row.buy_liquidity,
+            sell_liquidity: row.sell_liquidity,
+            liquidity_change: row.liquidity_change,
+            last_updated: row.last_updated,
+            rapidDump: row.rapidDump,
+        };
+    }
+
     /**
      * Close the database connection gracefully.
      */
diff --git a/core/src/cli/index.ts b/core/src/cli/index.ts
index 953bd04adb..5ecfd99cf2 100644
--- a/core/src/cli/index.ts
+++ b/core/src/cli/index.ts
@@ -166,7 +166,12 @@ export async function createDirectRuntime(
         modelProvider: character.modelProvider,
         evaluators: [],
         character,
-        providers: [Provider.timeProvider, Provider.boredomProvider],
+        providers: [
+            Provider.timeProvider,
+            Provider.boredomProvider,
+            character.settings?.secrets?.WALLET_PUBLIC_KEY &&
+                Provider.walletProvider,
+        ].filter(Boolean),
         actions: [
             ...defaultActions,
             // Custom actions
diff --git a/core/src/clients/direct/index.ts b/core/src/clients/direct/index.ts
index 8be31891ec..cff77fc23a 100644
--- a/core/src/clients/direct/index.ts
+++ b/core/src/clients/direct/index.ts
@@ -18,11 +18,11 @@ const upload = multer({ storage: multer.memoryStorage() });
 
 export const messageHandlerTemplate =
     // {{goals}}
-    //   `# Action Examples
-    // {{actionExamples}}
-    // (Action examples are for reference only. Do not use the information from them in your response.)
+    `# Action Examples
+{{actionExamples}}
+(Action examples are for reference only. Do not use the information from them in your response.)
 
-    `# Task: Generate dialog and actions for the character {{agentName}}.
+# Task: Generate dialog and actions for the character {{agentName}}.
 About {{agentName}}:
 {{bio}}
 {{lore}}
@@ -205,8 +205,25 @@ class DirectClient {
                     );
                     return;
                 }
+                
+                let message = null as Content | null;
+
+                const result = await runtime.processActions(
+                    memory,
+                    [responseMessage],
+                    state,
+                    async (newMessages) => {
+                        message = newMessages;
+                        return [memory];
+                    }
+                )
+
+                if (message) {
+                    res.json([message, response]);
+                } else {
+                    res.json([response]);
+                }
 
-                res.json(response);
             }
         );
 
diff --git a/core/src/core/generation.ts b/core/src/core/generation.ts
index 0c7b728c4d..817dec242d 100644
--- a/core/src/core/generation.ts
+++ b/core/src/core/generation.ts
@@ -403,6 +403,42 @@ export async function generateTextArray({
     }
 }
 
+export async function generateObject({
+    runtime,
+    context,
+    modelClass,
+}: {
+    runtime: IAgentRuntime;
+    context: string;
+    modelClass: string;
+}): Promise<any> {
+    if (!context) {
+        prettyConsole.error("generateObject context is empty");
+        return null;
+    }
+    let retryDelay = 1000;
+
+    while (true) {
+        try {
+            // this is slightly different than generateObjectArray, in that we parse object, not object array
+            const response = await generateText({
+        runtime,
+        context,
+        modelClass,
+    });
+    const parsedResponse = parseJSONObjectFromText(response);
+    if (parsedResponse) {
+                return parsedResponse;
+            }
+        } catch (error) {
+            prettyConsole.error("Error in generateObject:", error);
+        }
+
+        await new Promise((resolve) => setTimeout(resolve, retryDelay));
+        retryDelay *= 2;
+    }
+}
+
 export async function generateObjectArray({
     runtime,
     context,
diff --git a/core/src/core/parsing.ts b/core/src/core/parsing.ts
index 5835e8ed54..1cf110868d 100644
--- a/core/src/core/parsing.ts
+++ b/core/src/core/parsing.ts
@@ -2,10 +2,11 @@ const jsonBlockPattern = /```json\n([\s\S]*?)\n```/;
 
 export const messageCompletionFooter = `\nResponse format should be formatted in a JSON block like this:
 \`\`\`json
-{ "user": "{{agentName}}", "text": string, "action": string }
+{ "user": "{{agentName}}", "text": string, "action": "string" }
 \`\`\``;
 
 export const shouldRespondFooter = `The available options are [RESPOND], [IGNORE], or [STOP]. Choose the most appropriate option.
+If {{agentName}} is talking too much, you can choose [IGNORE]
 
 Your response must include one of the options.`;
 
diff --git a/core/src/index.ts b/core/src/index.ts
index f74ca17504..45d0997ec9 100644
--- a/core/src/index.ts
+++ b/core/src/index.ts
@@ -88,7 +88,9 @@ function chat() {
         );
 
         const data = await response.json();
-        console.log(`${characters[0].name}: ${data.text}`);
+        for (const message of data) {
+            console.log(`${characters[0].name}: ${message.text}`);
+        }
         chat();
     });
 }
diff --git a/core/src/providers/token.ts b/core/src/providers/token.ts
index d20aedaeba..615d5f2217 100644
--- a/core/src/providers/token.ts
+++ b/core/src/providers/token.ts
@@ -2,7 +2,7 @@ import { Connection } from "@solana/web3.js";
 // import fetch from "cross-fetch";
 import { IAgentRuntime, Memory, Provider, State } from "../core/types.ts";
 import settings from "../core/settings.ts";
-import { toBN, BN } from '../utils/bignumber.js';
+import { toBN } from "../utils/bignumber.js";
 import {
     ProcessedTokenData,
     TokenSecurityData,
@@ -517,7 +517,7 @@ export class TokenProvider {
         const limit = 1000;
         let cursor;
         //HELIOUS_API_KEY needs to be added
-        const url = `https://mainnet.helius-rpc.com/?api-key=${settings.HELIOUS_API_KEY || ""}`;
+        const url = `https://mainnet.helius-rpc.com/?api-key=${settings.HELIUS_API_KEY || ""}`;
         console.log({ url });
 
         try {
@@ -620,7 +620,9 @@ export class TokenProvider {
             })
             .map((holder) => ({
                 holderAddress: holder.address,
-                balanceUsd: toBN(holder.balance).multipliedBy(tokenPriceUsd).toFixed(2),
+                balanceUsd: toBN(holder.balance)
+                    .multipliedBy(tokenPriceUsd)
+                    .toFixed(2),
             }));
 
         return highValueHolders;
diff --git a/core/src/providers/trustScoreProvider.ts b/core/src/providers/trustScoreProvider.ts
index 1932d9ba58..f941111ac2 100644
--- a/core/src/providers/trustScoreProvider.ts
+++ b/core/src/providers/trustScoreProvider.ts
@@ -363,8 +363,7 @@ export class TrustScoreProvider {
         recommenderId: string,
         sellTimeStamp: string,
         sellDetails: sellDetails,
-        isSimulation: boolean,
-        buyTimeStamp: string
+        isSimulation: boolean
     ) {
         const processedData: ProcessedTokenData =
             await this.tokenProvider.getProcessedTokenData();
@@ -377,12 +376,12 @@ export class TrustScoreProvider {
         const sellSol = sellDetails.sell_amount / parseFloat(solPrice);
         const sell_value_usd =
             sellDetails.sell_amount * processedData.tradeData.price;
-        const trade = await this.trustScoreDb.getTradePerformance(
+        const trade = await this.trustScoreDb.getLatestTradePerformance(
             tokenAddress,
             recommenderId,
-            buyTimeStamp,
             isSimulation
         );
+        const buyTimeStamp = trade.buy_timeStamp;
         const marketCap =
             processedData.dexScreenerData.pairs[0]?.marketCap || 0;
         const liquidity =
diff --git a/core/src/providers/wallet.ts b/core/src/providers/wallet.ts
index a0a6ff08b8..3c9114c400 100644
--- a/core/src/providers/wallet.ts
+++ b/core/src/providers/wallet.ts
@@ -18,6 +18,7 @@ const PROVIDER_CONFIG = {
 
 interface Item {
     name: string;
+    address: string;
     symbol: string;
     decimals: number;
     balance: string;
@@ -48,7 +49,7 @@ interface Prices {
     ethereum: { usd: string };
 }
 
-class WalletProvider {
+export class WalletProvider {
     constructor(
         private connection: Connection,
         private walletPublicKey: PublicKey
diff --git a/docs/docs/api/index.md b/docs/docs/api/index.md
index 4c89359413..9d416ea06e 100644
--- a/docs/docs/api/index.md
+++ b/docs/docs/api/index.md
@@ -101,7 +101,7 @@ XAI_MODEL=
 # For asking Claude stuff
 ANTHROPIC_API_KEY=
 
-WALLET_SECRET_KEY=EXAMPLE_WALLET_SECRET_KEY
+WALLET_PRIVATE_KEY=EXAMPLE_WALLET_PRIVATE_KEY
 WALLET_PUBLIC_KEY=EXAMPLE_WALLET_PUBLIC_KEY
 
 BIRDEYE_API_KEY=