From d7a4f1c66e107b7d3bf511dc4be2748981ca9608 Mon Sep 17 00:00:00 2001 From: michaelessiet Date: Mon, 27 Jan 2025 14:22:34 +0100 Subject: [PATCH 1/2] chore: orca actions added --- src/actions/index.ts | 11 +++ src/actions/orca/closeOrcaPosition.ts | 57 +++++++++++ src/actions/orca/createOrcaCLMM.ts | 89 +++++++++++++++++ src/actions/orca/fetchOrcaPositions.ts | 54 +++++++++++ .../openOrcaCenteredPositionWithLiquidity.ts | 85 ++++++++++++++++ .../orca/openOrcaSingleSidedPosition.ts | 97 +++++++++++++++++++ 6 files changed, 393 insertions(+) create mode 100644 src/actions/orca/closeOrcaPosition.ts create mode 100644 src/actions/orca/createOrcaCLMM.ts create mode 100644 src/actions/orca/fetchOrcaPositions.ts create mode 100644 src/actions/orca/openOrcaCenteredPositionWithLiquidity.ts create mode 100644 src/actions/orca/openOrcaSingleSidedPosition.ts diff --git a/src/actions/index.ts b/src/actions/index.ts index 8b789898..386fce19 100644 --- a/src/actions/index.ts +++ b/src/actions/index.ts @@ -79,6 +79,11 @@ import getInfoAction from "./agent/get_info"; import getPriceInferenceAction from "./allora/getPriceInference"; import getAllTopicsAction from "./allora/getAllTopics"; import getInferenceByTopicIdAction from "./allora/getInferenceByTopicId"; +import closeOrcaPositionAction from "./orca/closeOrcaPosition"; +import createOrcaCLMMAction from "./orca/createOrcaCLMM"; +import fetchOrcaPositionsAction from "./orca/fetchOrcaPositions"; +import openOrcaCenteredPositionWithLiquidityAction from "./orca/openOrcaCenteredPositionWithLiquidity"; +import openOrcaSingleSidedPositionAction from "./orca/openOrcaSingleSidedPosition"; export const ACTIONS = { GET_INFO_ACTION: getInfoAction, WALLET_ADDRESS_ACTION: getWalletAddressAction, @@ -114,6 +119,12 @@ export const ACTIONS = { RAYDIUM_CREATE_AMM_V4_ACTION: raydiumCreateAmmV4Action, CREATE_ORCA_SINGLE_SIDED_WHIRLPOOL_ACTION: createOrcaSingleSidedWhirlpoolAction, + CLOSE_ORCA_POSITION_ACTION: closeOrcaPositionAction, + CREATE_ORCA_CLMM_ACTION: createOrcaCLMMAction, + FETCH_ORCA_POSITIONS_ACTION: fetchOrcaPositionsAction, + OPEN_ORCA_CENTERED_POSITION_WITH_LIQUIDITY_ACTION: + openOrcaCenteredPositionWithLiquidityAction, + OPEN_ORCA_SINGLE_SIDED_POSITION_ACTION: openOrcaSingleSidedPositionAction, LAUNCH_PUMPFUN_TOKEN_ACTION: launchPumpfunTokenAction, FLASH_OPEN_TRADE_ACTION: flashOpenTradeAction, FLASH_CLOSE_TRADE_ACTION: flashCloseTradeAction, diff --git a/src/actions/orca/closeOrcaPosition.ts b/src/actions/orca/closeOrcaPosition.ts new file mode 100644 index 00000000..bb4f3abe --- /dev/null +++ b/src/actions/orca/closeOrcaPosition.ts @@ -0,0 +1,57 @@ +import { z } from "zod"; +import type { Action } from "../../types"; +import { orcaClosePosition } from "../../tools"; + +const closeOrcaPositionAction: Action = { + name: "CLOSE_ORCA_POSITION_ACTION", + similes: [ + "close orca liquidity position", + "close orca whirlpool position", + "close orca liquidity pool", + "close my orca liquidity position", + ], + description: + "Close an existing liquidity position in an Orca Whirlpool. This functions fetches the position details using the provided mint address and closes the position with a 1% slippage", + examples: [ + [ + { + input: { + positionMintAddress: "EPjasdf...", + }, + output: { + status: "success", + signature: "12Erx...", + message: "Successfully closed Orca whirlpool position", + }, + explanation: "Close a USDC/SOL whirlpool position", + }, + ], + ], + schema: z.object({ + positionMintAddress: z + .string() + .describe("The mint address of the liquidity position to close"), + }), + handler: async (agent, input) => { + try { + const signature = await orcaClosePosition( + agent, + input.positionMintAddress, + ); + + return { + status: "success", + signature, + message: "Successfully closed Orca whirlpool position", + }; + } catch (e) { + return { + status: "error", + // @ts-expect-error - TS doesn't know that `e` has a `message` property + message: `Failed to close Orca whirlpool position: ${e.message}`, + }; + } + }, +}; + +export default closeOrcaPositionAction; diff --git a/src/actions/orca/createOrcaCLMM.ts b/src/actions/orca/createOrcaCLMM.ts new file mode 100644 index 00000000..4acdd36e --- /dev/null +++ b/src/actions/orca/createOrcaCLMM.ts @@ -0,0 +1,89 @@ +import { z } from "zod"; +import type { Action } from "../../types"; +import { PublicKey } from "@solana/web3.js"; +import { orcaCreateCLMM } from "../../tools"; +import Decimal from "decimal.js"; + +const createOrcaCLMMAction: Action = { + name: "CREATE_ORCA_CLMM_ACTION", + description: + "Create a Concentrated Liquidity Market Maker (CLMM) pool on Orca, the most efficient and capital-optimized CLMM on Solana. This function initializes a CLMM pool but does not add liquidity. You can add liquidity later using a centered position or a single-sided position.", + similes: [ + "create orca clmm", + "create orca concentrated pool", + "create orca clmm pool", + "create orca concentrated liquidity", + ], + examples: [ + [ + { + input: { + mintDeploy: "JUPyiwrYJFskUPiHa7hkeR8VUtAeFoSYbKedZNsDvCN", + mintPair: "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", + initialPrice: 1.1, + feeTier: 1, + }, + output: { + status: "success", + message: + "CLMM pool created successfully. Note: No liquidity was added.", + }, + explanation: "Create a CLMM pool with USDC and JUP", + }, + ], + ], + schema: z.object({ + mintDeploy: z + .string() + .describe("The mint address of the token you want to deploy"), + mintPair: z + .string() + .describe( + "The mint address of the token you want to pair the deployed mint with", + ), + initialPrice: z + .number() + .positive() + .describe("Initial price of mintDeploy in terms of mintPair"), + feeTier: z + .number() + .positive() + .min(1) + .describe( + "The fee tier in bps. Options: 1, 2, 4, 5, 16, 30, 65, 100, 200", + ), + }), + handler: async (agent, input) => { + try { + const [mintDeploy, mintPair, initialPrice, feeTier] = [ + new PublicKey(input.mintDeploy), + new PublicKey(input.mintPair), + new Decimal(input.initialPrice), + input.feeTier, + ]; + + const signature = await orcaCreateCLMM( + agent, + mintDeploy, + mintPair, + initialPrice, + feeTier, + ); + + return { + status: "success", + message: + "CLMM pool created successfully. Note: No liquidity was added.", + signature, + }; + } catch (e) { + return { + status: "error", + // @ts-expect-error - TS doesn't know that `e` has a `message` property + message: `Failed to create Orca CLMM pool: ${e.message}`, + }; + } + }, +}; + +export default createOrcaCLMMAction; diff --git a/src/actions/orca/fetchOrcaPositions.ts b/src/actions/orca/fetchOrcaPositions.ts new file mode 100644 index 00000000..0d6e6f66 --- /dev/null +++ b/src/actions/orca/fetchOrcaPositions.ts @@ -0,0 +1,54 @@ +import { z } from "zod"; +import type { Action } from "../../types"; +import { orcaFetchPositions } from "../../tools"; + +const fetchOrcaPositionsAction: Action = { + name: "FETCH_ORCA_POSITIONS_ACTION", + description: + "Fetch all the liquidity positions in an Orca Whirlpool by owner. Returns an object with position mint addresses as keys and position status details as values.", + similes: [ + "fetch orca liquidity positions", + "fetch orca whirlpool positions", + "fetch orca liquidity pools", + "fetch my orca liquidity positions", + ], + examples: [ + [ + { + input: {}, + output: { + status: "success", + message: "Liquidity positions fetched.", + positions: { + positionMintAddress1: { + whirlpoolAddress: "whirlpoolAddress1", + positionInRange: true, + distanceFromCenterBps: 250, + }, + }, + }, + explanation: "Fetch all Orca whirlpool positions", + }, + ], + ], + schema: z.object({}), + handler: async (agent) => { + try { + const positions = JSON.parse(await orcaFetchPositions(agent)); + + return { + status: "success", + message: "Liquidity positions fetched.", + positions, + }; + } catch (e) { + return { + status: "error", + // @ts-expect-error - TS doesn't know that `e` has a `message` property + message: `Failed to fetch Orca whirlpool positions: ${e.message}`, + }; + } + }, +}; + +export default fetchOrcaPositionsAction; diff --git a/src/actions/orca/openOrcaCenteredPositionWithLiquidity.ts b/src/actions/orca/openOrcaCenteredPositionWithLiquidity.ts new file mode 100644 index 00000000..2ccaf175 --- /dev/null +++ b/src/actions/orca/openOrcaCenteredPositionWithLiquidity.ts @@ -0,0 +1,85 @@ +import { z } from "zod"; +import type { Action } from "../../types"; +import { PublicKey } from "@solana/web3.js"; +import { orcaOpenCenteredPositionWithLiquidity } from "../../tools"; +import Decimal from "decimal.js"; + +const openOrcaCenteredPositionWithLiquidityAction: Action = { + name: "OPEN_ORCA_CENTERED_POSITION_WITH_LIQUIDITY_ACTION", + description: + "Open a new Orca whirlpool position with liquidity centered around the current price. This function opens a new liquidity position in an Orca whirlpool with the provided liquidity amount centered around the current price.", + similes: [ + "open orca liquidity position", + "open orca whirlpool position", + "open orca liquidity pool", + "open new orca liquidity position", + "open centered orca liquidity position", + ], + examples: [ + [ + { + input: { + whirlpoolAddress: "EPjasdf...", + priceOffsetBps: 500, + inputTokenMint: "EPjasdf...", + inputAmount: 100.0, + }, + output: { + status: "success", + signature: "12Erx...", + message: "Centered liquidity position opened successfully", + }, + explanation: "Open a USDC/SOL whirlpool position", + }, + ], + ], + schema: z.object({ + whirlpoolAddress: z + .string() + .describe("The address of the Orca whirlpool to open a position in"), + priceOffsetBps: z + .number() + .positive() + .min(100) + .describe("The price offset in basis points for the new position"), + inputTokenMint: z + .string() + .describe("The mint address of the token to deposit"), + inputAmount: z + .number() + .positive() + .describe("The amount of the token to deposit"), + }), + handler: async (agent, input) => { + try { + const [whirlpoolAddress, inputTokenMint, priceOffsetBps, inputAmount] = [ + new PublicKey(input.whirlpoolAddress), + new PublicKey(input.inputTokenMint), + input.priceOffsetBps, + new Decimal(input.inputAmount), + ]; + + const signature = await orcaOpenCenteredPositionWithLiquidity( + agent, + whirlpoolAddress, + priceOffsetBps, + inputTokenMint, + inputAmount, + ); + + return { + status: "success", + signature, + message: "Centered liquidity position opened successfully", + }; + } catch (e) { + return { + status: "error", + // @ts-expect-error - TS doesn't know that `e` has a `message` property + message: `Failed to open centered Orca whirlpool position: ${e.message}`, + }; + } + }, +}; + +export default openOrcaCenteredPositionWithLiquidityAction; diff --git a/src/actions/orca/openOrcaSingleSidedPosition.ts b/src/actions/orca/openOrcaSingleSidedPosition.ts new file mode 100644 index 00000000..b4b05e06 --- /dev/null +++ b/src/actions/orca/openOrcaSingleSidedPosition.ts @@ -0,0 +1,97 @@ +import { z } from "zod"; +import type { Action } from "../../types"; +import { PublicKey } from "@solana/web3.js"; +import { orcaOpenSingleSidedPosition } from "../../tools"; +import Decimal from "decimal.js"; + +const openOrcaSingleSidedPositionAction: Action = { + name: "OPEN_ORCA_SINGLE_SIDED_POSITION_ACTION", + description: "Open a single-sided liquidity position in an Orca Whirlpool", + similes: [ + "open orca single-sided position", + "open orca whirlpool single sided position", + "open orca single sideed liquidity pool", + ], + examples: [ + [ + { + input: { + whirlpoolAddress: "ERjsdF...", + distanceFromCurrentPriceBps: 250, + widthBps: 500, + inputTokenMint: "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", + inputAmount: 100, + }, + output: { + status: "success", + signature: "12Erx...", + message: "Successfully opened Orca whirlpool single-sided position", + }, + explanation: + "Open a single sided USDC position in a USDC/SOL whirlpool", + }, + ], + ], + schema: z.object({ + whirlpoolAddress: z.string().describe("The address of the Orca Whirlpool"), + distanceFromCurrentPriceBps: z + .number() + .positive() + .describe( + "The basis point offset from the current price for the lower bound", + ), + widthBps: z + .number() + .positive() + .describe( + "The width of the range as a percentage increment from the lower bound", + ), + inputTokenMint: z + .string() + .describe("The mint address of the token to deposit"), + inputAmount: z + .number() + .positive() + .describe("The amount of the input token to deposit"), + }), + handler: async (agent, input) => { + try { + const [ + whirlpoolAddress, + distanceFromCurrentPriceBps, + widthBps, + inputTokenMint, + inputAmount, + ] = [ + new PublicKey(input.whirlpoolAddress), + input.distanceFromCurrentPriceBps, + input.widthBps, + new PublicKey(input.inputTokenMint), + new Decimal(input.inputAmount), + ]; + + const signature = await orcaOpenSingleSidedPosition( + agent, + whirlpoolAddress, + distanceFromCurrentPriceBps, + widthBps, + inputTokenMint, + inputAmount, + ); + + return { + status: "success", + signature, + message: "Successfully opened Orca whirlpool single-sided position", + }; + } catch (e) { + return { + status: "error", + // @ts-expect-error - TS doesn't know that `e` has a `message` property + message: `Failed to open Orca whirlpool single-sided position: ${e.message}`, + }; + } + }, +}; + +export default openOrcaSingleSidedPositionAction; From 6a28bc4c41bd0e56f398dbe27527c5ba69e814d9 Mon Sep 17 00:00:00 2001 From: michaelessiet Date: Tue, 28 Jan 2025 20:56:34 +0100 Subject: [PATCH 2/2] fix: convert position mint to pub key --- src/actions/orca/closeOrcaPosition.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/actions/orca/closeOrcaPosition.ts b/src/actions/orca/closeOrcaPosition.ts index bb4f3abe..7d74b412 100644 --- a/src/actions/orca/closeOrcaPosition.ts +++ b/src/actions/orca/closeOrcaPosition.ts @@ -1,6 +1,7 @@ import { z } from "zod"; import type { Action } from "../../types"; import { orcaClosePosition } from "../../tools"; +import { PublicKey } from "@solana/web3.js"; const closeOrcaPositionAction: Action = { name: "CLOSE_ORCA_POSITION_ACTION", @@ -36,7 +37,7 @@ const closeOrcaPositionAction: Action = { try { const signature = await orcaClosePosition( agent, - input.positionMintAddress, + new PublicKey(input.positionMintAddress), ); return {