From a848a65ea0b8f32ea7af77601354f166f095ba6b Mon Sep 17 00:00:00 2001 From: mbrassey Date: Wed, 4 Mar 2026 00:12:27 -0700 Subject: [PATCH] feat(plugin-defi): Add Blueprint native staking actions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add native Solana staking with Blueprint validator via REST API: - blueprintStake: Stake SOL natively (~6% APY) - blueprintUnstake: Deactivate stake accounts - blueprintCheckAccounts: List stake accounts with status - blueprintGetValidator: Get validator info (APY, performance) - blueprintDonate: Donate SOL to support the platform Blueprint is the first agentic staking infrastructure — zero custody, unsigned transactions only, agents sign client-side. This fills the native staking gap (kit currently only has liquid staking via Jupiter and Solayer). API: https://solentic.theblueprint.xyz Docs: https://solentic.theblueprint.xyz/docs --- .../actions/blueprintCheckAccounts.ts | 45 ++++++++++++++++ .../src/blueprint/actions/blueprintDonate.ts | 51 ++++++++++++++++++ .../actions/blueprintGetValidator.ts | 47 ++++++++++++++++ .../src/blueprint/actions/blueprintStake.ts | 54 +++++++++++++++++++ .../src/blueprint/actions/blueprintUnstake.ts | 53 ++++++++++++++++++ .../src/blueprint/actions/index.ts | 5 ++ .../src/blueprint/constants/index.ts | 3 ++ .../tools/blueprint_check_accounts.ts | 22 ++++++++ .../src/blueprint/tools/blueprint_donate.ts | 37 +++++++++++++ .../tools/blueprint_get_validator.ts | 16 ++++++ .../src/blueprint/tools/blueprint_stake.ts | 37 +++++++++++++ .../src/blueprint/tools/blueprint_unstake.ts | 37 +++++++++++++ .../plugin-defi/src/blueprint/tools/index.ts | 5 ++ packages/plugin-defi/src/index.ts | 30 +++++++++++ 14 files changed, 442 insertions(+) create mode 100644 packages/plugin-defi/src/blueprint/actions/blueprintCheckAccounts.ts create mode 100644 packages/plugin-defi/src/blueprint/actions/blueprintDonate.ts create mode 100644 packages/plugin-defi/src/blueprint/actions/blueprintGetValidator.ts create mode 100644 packages/plugin-defi/src/blueprint/actions/blueprintStake.ts create mode 100644 packages/plugin-defi/src/blueprint/actions/blueprintUnstake.ts create mode 100644 packages/plugin-defi/src/blueprint/actions/index.ts create mode 100644 packages/plugin-defi/src/blueprint/constants/index.ts create mode 100644 packages/plugin-defi/src/blueprint/tools/blueprint_check_accounts.ts create mode 100644 packages/plugin-defi/src/blueprint/tools/blueprint_donate.ts create mode 100644 packages/plugin-defi/src/blueprint/tools/blueprint_get_validator.ts create mode 100644 packages/plugin-defi/src/blueprint/tools/blueprint_stake.ts create mode 100644 packages/plugin-defi/src/blueprint/tools/blueprint_unstake.ts create mode 100644 packages/plugin-defi/src/blueprint/tools/index.ts diff --git a/packages/plugin-defi/src/blueprint/actions/blueprintCheckAccounts.ts b/packages/plugin-defi/src/blueprint/actions/blueprintCheckAccounts.ts new file mode 100644 index 000000000..5d39cf2fc --- /dev/null +++ b/packages/plugin-defi/src/blueprint/actions/blueprintCheckAccounts.ts @@ -0,0 +1,45 @@ +import type { Action, SolanaAgentKit } from "solana-agent-kit"; +import { z } from "zod"; +import { blueprintCheckAccounts } from "../tools"; + +export const blueprintCheckAccountsAction: Action = { + name: "CHECK_BLUEPRINT_STAKE_ACCOUNTS", + similes: [ + "check Blueprint stake accounts", + "list Blueprint stakes", + "get my Blueprint staking status", + ], + description: + "Check all stake accounts delegated to Blueprint validator for the agent's wallet. Returns account status, balance, and epoch timing for each stake account.", + examples: [ + [ + { + input: {}, + output: { + status: "success", + message: "Found 2 Blueprint stake accounts", + accounts: [], + }, + explanation: + "List all stake accounts for the agent's wallet that are delegated to Blueprint", + }, + ], + ], + schema: z.object({}), + handler: async (agent: SolanaAgentKit, _input: Record) => { + try { + const data = await blueprintCheckAccounts(agent); + + return { + status: "success", + message: `Found ${data.stakeAccounts?.length ?? 0} Blueprint stake accounts`, + ...data, + }; + } catch (error: any) { + return { + status: "error", + message: `Failed to check Blueprint stake accounts: ${error.message}`, + }; + } + }, +}; diff --git a/packages/plugin-defi/src/blueprint/actions/blueprintDonate.ts b/packages/plugin-defi/src/blueprint/actions/blueprintDonate.ts new file mode 100644 index 000000000..b975f4c10 --- /dev/null +++ b/packages/plugin-defi/src/blueprint/actions/blueprintDonate.ts @@ -0,0 +1,51 @@ +import type { Action, SolanaAgentKit } from "solana-agent-kit"; +import { z } from "zod"; +import { blueprintDonate } from "../tools"; + +export const blueprintDonateAction: Action = { + name: "DONATE_TO_BLUEPRINT", + similes: [ + "donate to Blueprint", + "support Blueprint staking", + "tip Blueprint validator", + ], + description: + "Donate SOL to Blueprint to support development of the agentic staking platform. Blueprint is free for all agents — donations help maintain the infrastructure.", + examples: [ + [ + { + input: { + amountSol: 0.1, + }, + output: { + status: "success", + message: "Successfully donated 0.1 SOL to Blueprint", + signature: "5abc...def", + }, + explanation: "Donate 0.1 SOL to support Blueprint development", + }, + ], + ], + schema: z.object({ + amountSol: z + .number() + .positive() + .describe("Amount of SOL to donate to Blueprint"), + }), + handler: async (agent: SolanaAgentKit, input: Record) => { + try { + const signature = await blueprintDonate(agent, input.amountSol); + + return { + status: "success", + message: `Successfully donated ${input.amountSol} SOL to Blueprint`, + signature, + }; + } catch (error: any) { + return { + status: "error", + message: `Blueprint donation failed: ${error.message}`, + }; + } + }, +}; diff --git a/packages/plugin-defi/src/blueprint/actions/blueprintGetValidator.ts b/packages/plugin-defi/src/blueprint/actions/blueprintGetValidator.ts new file mode 100644 index 000000000..8733bac0b --- /dev/null +++ b/packages/plugin-defi/src/blueprint/actions/blueprintGetValidator.ts @@ -0,0 +1,47 @@ +import type { Action, SolanaAgentKit } from "solana-agent-kit"; +import { z } from "zod"; +import { blueprintGetValidator } from "../tools"; + +export const blueprintGetValidatorAction: Action = { + name: "GET_BLUEPRINT_VALIDATOR_INFO", + similes: [ + "get Blueprint validator info", + "check Blueprint APY", + "Blueprint validator stats", + "Blueprint staking APY", + ], + description: + "Get Blueprint validator information including live APY (~6%), vote success rate, active stake, commission, and infrastructure details. Use this to evaluate the validator before staking.", + examples: [ + [ + { + input: {}, + output: { + status: "success", + message: "Blueprint validator info fetched", + name: "Blueprint", + totalApy: 6.1, + voteSuccess: 99.8, + }, + explanation: "Get live stats for Blueprint validator", + }, + ], + ], + schema: z.object({}), + handler: async (_agent: SolanaAgentKit, _input: Record) => { + try { + const data = await blueprintGetValidator(); + + return { + status: "success", + message: "Blueprint validator info fetched", + ...data, + }; + } catch (error: any) { + return { + status: "error", + message: `Failed to get Blueprint validator info: ${error.message}`, + }; + } + }, +}; diff --git a/packages/plugin-defi/src/blueprint/actions/blueprintStake.ts b/packages/plugin-defi/src/blueprint/actions/blueprintStake.ts new file mode 100644 index 000000000..765ab586d --- /dev/null +++ b/packages/plugin-defi/src/blueprint/actions/blueprintStake.ts @@ -0,0 +1,54 @@ +import type { Action, SolanaAgentKit } from "solana-agent-kit"; +import { z } from "zod"; +import { blueprintStake } from "../tools"; + +export const blueprintStakeAction: Action = { + name: "STAKE_SOL_WITH_BLUEPRINT", + similes: [ + "stake SOL with Blueprint", + "native stake SOL", + "delegate SOL to Blueprint validator", + "stake SOL natively", + "stake with Blueprint validator", + ], + description: + "Stake SOL natively with Blueprint validator (~6% APY). Zero custody — transaction is signed locally. This is native staking (not liquid staking), your wallet retains full authority over the stake account.", + examples: [ + [ + { + input: { + amountSol: 10, + }, + output: { + status: "success", + message: "Successfully staked 10 SOL with Blueprint validator", + signature: "5abc...def", + }, + explanation: + "Stake 10 SOL natively with Blueprint validator at ~6% APY", + }, + ], + ], + schema: z.object({ + amountSol: z + .number() + .positive() + .describe("Amount of SOL to stake with Blueprint validator"), + }), + handler: async (agent: SolanaAgentKit, input: Record) => { + try { + const signature = await blueprintStake(agent, input.amountSol); + + return { + status: "success", + message: `Successfully staked ${input.amountSol} SOL with Blueprint validator`, + signature, + }; + } catch (error: any) { + return { + status: "error", + message: `Blueprint staking failed: ${error.message}`, + }; + } + }, +}; diff --git a/packages/plugin-defi/src/blueprint/actions/blueprintUnstake.ts b/packages/plugin-defi/src/blueprint/actions/blueprintUnstake.ts new file mode 100644 index 000000000..1c774afc3 --- /dev/null +++ b/packages/plugin-defi/src/blueprint/actions/blueprintUnstake.ts @@ -0,0 +1,53 @@ +import type { Action, SolanaAgentKit } from "solana-agent-kit"; +import { z } from "zod"; +import { blueprintUnstake } from "../tools"; + +export const blueprintUnstakeAction: Action = { + name: "UNSTAKE_SOL_FROM_BLUEPRINT", + similes: [ + "unstake SOL from Blueprint", + "deactivate Blueprint stake", + "undelegate from Blueprint", + ], + description: + "Unstake (deactivate) SOL from Blueprint validator. After deactivation completes at the end of the current epoch, the SOL can be withdrawn.", + examples: [ + [ + { + input: { + stakeAccountAddress: "7xKX...", + }, + output: { + status: "success", + message: "Successfully deactivated stake account 7xKX...", + signature: "5abc...def", + }, + explanation: "Deactivate a stake account delegated to Blueprint", + }, + ], + ], + schema: z.object({ + stakeAccountAddress: z + .string() + .describe("The stake account address to deactivate"), + }), + handler: async (agent: SolanaAgentKit, input: Record) => { + try { + const signature = await blueprintUnstake( + agent, + input.stakeAccountAddress, + ); + + return { + status: "success", + message: `Successfully deactivated stake account ${input.stakeAccountAddress}`, + signature, + }; + } catch (error: any) { + return { + status: "error", + message: `Blueprint unstaking failed: ${error.message}`, + }; + } + }, +}; diff --git a/packages/plugin-defi/src/blueprint/actions/index.ts b/packages/plugin-defi/src/blueprint/actions/index.ts new file mode 100644 index 000000000..520e0eb36 --- /dev/null +++ b/packages/plugin-defi/src/blueprint/actions/index.ts @@ -0,0 +1,5 @@ +export * from "./blueprintStake"; +export * from "./blueprintUnstake"; +export * from "./blueprintCheckAccounts"; +export * from "./blueprintGetValidator"; +export * from "./blueprintDonate"; diff --git a/packages/plugin-defi/src/blueprint/constants/index.ts b/packages/plugin-defi/src/blueprint/constants/index.ts new file mode 100644 index 000000000..f817dad7c --- /dev/null +++ b/packages/plugin-defi/src/blueprint/constants/index.ts @@ -0,0 +1,3 @@ +export const BLUEPRINT_API_BASE = "https://solentic.theblueprint.xyz"; +export const BLUEPRINT_VOTE_ACCOUNT = + "528hi3StRe7uGjt99d35myh95JPc2MqBEHTPYcEhqMg5"; diff --git a/packages/plugin-defi/src/blueprint/tools/blueprint_check_accounts.ts b/packages/plugin-defi/src/blueprint/tools/blueprint_check_accounts.ts new file mode 100644 index 000000000..25d3f59bb --- /dev/null +++ b/packages/plugin-defi/src/blueprint/tools/blueprint_check_accounts.ts @@ -0,0 +1,22 @@ +import type { SolanaAgentKit } from "solana-agent-kit"; +import axios from "redaxios"; +import { BLUEPRINT_API_BASE } from "../constants"; + +/** + * Check all Blueprint stake accounts for a wallet. + * Returns stake accounts with status, balance, and epoch timing. + * + * @param agent - SolanaAgentKit instance + * @returns Stake accounts data from Blueprint API + */ +export async function blueprintCheckAccounts( + agent: SolanaAgentKit, +): Promise> { + const walletAddress = agent.wallet.publicKey.toBase58(); + + const response = await axios.get( + `${BLUEPRINT_API_BASE}/api/v1/stake/accounts/${walletAddress}`, + ); + + return response.data; +} diff --git a/packages/plugin-defi/src/blueprint/tools/blueprint_donate.ts b/packages/plugin-defi/src/blueprint/tools/blueprint_donate.ts new file mode 100644 index 000000000..8f44e8ac6 --- /dev/null +++ b/packages/plugin-defi/src/blueprint/tools/blueprint_donate.ts @@ -0,0 +1,37 @@ +import type { SolanaAgentKit } from "solana-agent-kit"; +import { Transaction } from "@solana/web3.js"; +import axios from "redaxios"; +import { BLUEPRINT_API_BASE } from "../constants"; + +/** + * Donate SOL to Blueprint to support development of the agentic staking platform. + * Zero custody — transaction is signed locally. + * + * @param agent - SolanaAgentKit instance + * @param amountSol - Amount of SOL to donate + * @returns Transaction signature after signing and submitting + */ +export async function blueprintDonate( + agent: SolanaAgentKit, + amountSol: number, +): Promise { + const walletAddress = agent.wallet.publicKey.toBase58(); + + const response = await axios.post( + `${BLUEPRINT_API_BASE}/api/v1/donate`, + { + walletAddress, + amountSol, + }, + ); + + const { transaction } = response.data; + const tx = Transaction.from(Buffer.from(transaction, "base64")); + tx.sign(agent.wallet); + + const signature = await agent.connection.sendRawTransaction( + tx.serialize(), + ); + + return signature; +} diff --git a/packages/plugin-defi/src/blueprint/tools/blueprint_get_validator.ts b/packages/plugin-defi/src/blueprint/tools/blueprint_get_validator.ts new file mode 100644 index 000000000..438a0ba0b --- /dev/null +++ b/packages/plugin-defi/src/blueprint/tools/blueprint_get_validator.ts @@ -0,0 +1,16 @@ +import axios from "redaxios"; +import { BLUEPRINT_API_BASE } from "../constants"; + +/** + * Get Blueprint validator information including APY, vote success, + * active stake, commission, and infrastructure details. + * + * @returns Validator profile data + */ +export async function blueprintGetValidator(): Promise> { + const response = await axios.get( + `${BLUEPRINT_API_BASE}/api/v1/validator`, + ); + + return response.data; +} diff --git a/packages/plugin-defi/src/blueprint/tools/blueprint_stake.ts b/packages/plugin-defi/src/blueprint/tools/blueprint_stake.ts new file mode 100644 index 000000000..2d7c8d5b7 --- /dev/null +++ b/packages/plugin-defi/src/blueprint/tools/blueprint_stake.ts @@ -0,0 +1,37 @@ +import type { SolanaAgentKit } from "solana-agent-kit"; +import { Transaction } from "@solana/web3.js"; +import axios from "redaxios"; +import { BLUEPRINT_API_BASE } from "../constants"; + +/** + * Stake SOL natively with Blueprint validator (~6% APY, zero custody). + * Returns the unsigned transaction base64 for the agent to sign and submit. + * + * @param agent - SolanaAgentKit instance + * @param amountSol - Amount of SOL to stake + * @returns Transaction signature after signing and submitting + */ +export async function blueprintStake( + agent: SolanaAgentKit, + amountSol: number, +): Promise { + const walletAddress = agent.wallet.publicKey.toBase58(); + + const response = await axios.post( + `${BLUEPRINT_API_BASE}/api/v1/stake/transaction`, + { + walletAddress, + amountSol, + }, + ); + + const { transaction } = response.data; + const tx = Transaction.from(Buffer.from(transaction, "base64")); + tx.sign(agent.wallet); + + const signature = await agent.connection.sendRawTransaction( + tx.serialize(), + ); + + return signature; +} diff --git a/packages/plugin-defi/src/blueprint/tools/blueprint_unstake.ts b/packages/plugin-defi/src/blueprint/tools/blueprint_unstake.ts new file mode 100644 index 000000000..f1bdff9c8 --- /dev/null +++ b/packages/plugin-defi/src/blueprint/tools/blueprint_unstake.ts @@ -0,0 +1,37 @@ +import type { SolanaAgentKit } from "solana-agent-kit"; +import { Transaction } from "@solana/web3.js"; +import axios from "redaxios"; +import { BLUEPRINT_API_BASE } from "../constants"; + +/** + * Unstake (deactivate) SOL from Blueprint validator. + * After deactivation, SOL can be withdrawn after the cooldown epoch. + * + * @param agent - SolanaAgentKit instance + * @param stakeAccountAddress - The stake account to deactivate + * @returns Transaction signature after signing and submitting + */ +export async function blueprintUnstake( + agent: SolanaAgentKit, + stakeAccountAddress: string, +): Promise { + const walletAddress = agent.wallet.publicKey.toBase58(); + + const response = await axios.post( + `${BLUEPRINT_API_BASE}/api/v1/unstake/transaction`, + { + walletAddress, + stakeAccountAddress, + }, + ); + + const { transaction } = response.data; + const tx = Transaction.from(Buffer.from(transaction, "base64")); + tx.sign(agent.wallet); + + const signature = await agent.connection.sendRawTransaction( + tx.serialize(), + ); + + return signature; +} diff --git a/packages/plugin-defi/src/blueprint/tools/index.ts b/packages/plugin-defi/src/blueprint/tools/index.ts new file mode 100644 index 000000000..488e4507d --- /dev/null +++ b/packages/plugin-defi/src/blueprint/tools/index.ts @@ -0,0 +1,5 @@ +export * from "./blueprint_stake"; +export * from "./blueprint_unstake"; +export * from "./blueprint_check_accounts"; +export * from "./blueprint_get_validator"; +export * from "./blueprint_donate"; diff --git a/packages/plugin-defi/src/index.ts b/packages/plugin-defi/src/index.ts index ef3b8ca53..3a576dad7 100644 --- a/packages/plugin-defi/src/index.ts +++ b/packages/plugin-defi/src/index.ts @@ -209,6 +209,22 @@ import { sanctumSwapLST, } from "./sanctum/tools"; +// Import Blueprint actions & tools +import { + blueprintStakeAction, + blueprintUnstakeAction, + blueprintCheckAccountsAction, + blueprintGetValidatorAction, + blueprintDonateAction, +} from "./blueprint/actions"; +import { + blueprintStake, + blueprintUnstake, + blueprintCheckAccounts, + blueprintGetValidator, + blueprintDonate, +} from "./blueprint/tools"; + // Import OKX tools import { getTokens, @@ -338,6 +354,13 @@ const DefiPlugin = { getLiquidity, getChainData, executeSwap, + + // Blueprint methods + blueprintStake, + blueprintUnstake, + blueprintCheckAccounts, + blueprintGetValidator, + blueprintDonate, }, // Combine all actions @@ -443,6 +466,13 @@ const DefiPlugin = { getLiquidityAction, getChainDataAction, executeSwapAction, + + // Blueprint actions + blueprintStakeAction, + blueprintUnstakeAction, + blueprintCheckAccountsAction, + blueprintGetValidatorAction, + blueprintDonateAction, ], // Initialize function