Skip to content
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
db6d93d
actions
parhim Feb 27, 2025
6fe2cdc
@orca-so actions sdk
parhim Mar 3, 2025
6553638
updated yarn.lock
parhim Mar 3, 2025
990a279
Merge branch 'main' into sam/DX-251
parhim Mar 3, 2025
61de840
Merge branch 'main' into sam/DX-251
parhim Mar 4, 2025
d707722
updated yarn lock
parhim Mar 4, 2025
0ad032c
addresses comments
parhim Mar 4, 2025
fefa209
lock
parhim Mar 4, 2025
86ee47c
changeset
parhim Mar 4, 2025
0e68385
Merge branch 'main' into sam/DX-251
parhim Mar 4, 2025
8b386c2
new lock
parhim Mar 4, 2025
d669e6a
changes web3.js -> kit
parhim Mar 4, 2025
75c2665
formatted
parhim Mar 4, 2025
ffaeaa1
more lint
parhim Mar 4, 2025
6c88ca3
lint
parhim Mar 5, 2025
d1d7084
Merge branch 'main' into sam/DX-251
parhim Mar 5, 2025
ed9f669
new yarn lock
parhim Mar 5, 2025
1b63f18
small readme update
parhim Mar 5, 2025
999ec9b
reverts lint change for whirlpools prog
parhim Mar 7, 2025
cc6dbff
try 2 rever wpools change
parhim Mar 7, 2025
f064bc6
moves actions into regular sdk
parhim Mar 8, 2025
8119efe
Merge branch 'main' into sam/DX-251
parhim Mar 8, 2025
f58383b
rm changeset
parhim Mar 8, 2025
00a4d6c
Merge branch 'main' into sam/DX-251
parhim Mar 8, 2025
d21d16d
changeset
parhim Mar 8, 2025
3d24ec5
revert cargo
parhim Mar 8, 2025
2ce3a74
eof
parhim Mar 8, 2025
cc950b3
Merge branch 'main' into sam/DX-251
parhim Mar 10, 2025
c57778e
new yarn lock
parhim Mar 10, 2025
83f5e09
added typedoc for setPayerFromBytes
parhim Mar 10, 2025
e0f1c92
added actions to readme for wpools ts sdk
parhim Mar 10, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
155 changes: 155 additions & 0 deletions ts-sdk/actions/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
# Orca Actions SDK

The Orca Actions SDK provides a set of utilities for executing common actions with Orca Whirlpools on Solana and Eclipse blockchains. This package simplifies the process of creating and managing transactions for Whirlpool operations.

## Installation

```bash
npm install @orca-so/actions
```

## Usage

### Config

Before using the SDK, you need to configure the payer and RPC settings (and optionally priority fee and jito tip settings).

```ts
import { setPayerFromBytes, setRpc, setPriorityFeeSetting, setJitoTipSetting, setDefaultSlippageToleranceBps } from "@orca-so/actions";

await setPayerFromBytes(
new Uint8Array(Buffer.from(process.env.PAYER_PRIVATE_KEY, "base64"))
);

await setRpc(process.env.RPC_URL);

// optional
await setPriorityFeeSetting({
type: "dynamic";
maxCapLamports: BigInt(5_000_000), // 0.005 SOL
priorityFeePercentile: "75",
});

// optional
await setJitoTipSetting({
type: "dynamic",
maxCapLamports: BigInt(2_000_000), // 0.002 SOL
priorityFeePercentile: "50ema",
});

// you can optionally set a default slippage tolerance; that will be used for all transactions if not overridden
setDefaultSlippageToleranceBps(100)


```

### Harvest Fees

```ts
import { harvestAllPositionFees } from "@orca-so/actions";

const txs = await harvestAllPositionFees();
```

### Create a Splash Liquidity Pool

```ts
import { createSplashPool } from "@orca-so/actions";

const { callback, initializationCost, poolAddress } = await createSplashPool(
tokenMintA,
tokenMintB,
initialPrice
);
// you can check initialization cost of the pool before sending the transaction

await callback();
```

### Open a Concentrated Liquidity Position

```ts
import { openConcentratedPosition } from "@orca-so/actions";

const { callback, quote, initializationCost, positionMint } =
await openConcentratedPosition(
poolAddress,
tokenAmount,
lowerPrice,
upperPrice
);
// you can check quote and initialization cost of the position before sending the transaction

// callback builds and sends the transaction and returns the transaction signature
await callback();
```

### Open a Full Range Liquidity Position

```ts
import { openFullRangePosition } from "@orca-so/actions";

const { callback, quote, initializationCost } = await openFullRangePosition(
poolAddress,
tokenAmount
);
// you can check quote and initialization cost of the position before sending the transaction

// callback builds and sends the transaction and returns the transaction signature
await callback();
```

### Close a Liquidity Position

```ts
import { closePositionAndCollectFees } from "@orca-so/actions";

const { callback, quote, feesQuote, rewardsQuote } =
await closePositionAndCollectFees(positionMintAddress);
// you can check quote, feesQuote, and rewardsQuote of the position before sending the transaction

// callback builds and sends the transaction and returns the transaction signature
await callback();
```

### Increase Liquidity

```ts
import { increasePosLiquidity } from "@orca-so/actions";

const { callback, quote } = await increasePosLiquidity(
positionMintAddress,
tokenAmount
);
// you can check quote of the position before sending the transaction

// callback builds and sends the transaction and returns the transaction signature
await callback();
```

### Decrease Liquidity

```ts
import { decreasePosLiquidity } from "@orca-so/actions";

const { callback, quote } = await decreasePosLiquidity(
positionMintAddress,
tokenAmount
);

await callback();
```

### Swap

```ts
import { swap } from "@orca-so/actions";

const { callback, quote } = await swap(
poolAddress,
tokenAmount,
slippageToleranceBps // optional
);

await callback();
```
38 changes: 38 additions & 0 deletions ts-sdk/actions/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
{
"name": "@orca-so/actions",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we do @orca-so/whirlpools-actions?

"version": "0.0.2",
"type": "module",
"main": "./dist/index.cjs",
"module": "./dist/index.js",
"types": "./dist/index.d.ts",
"exports": {
"import": {
"types": "./dist/index.d.ts",
"import": "./dist/index.js"
},
"require": {
"types": "./dist/index.d.cts",
"require": "./dist/index.cjs"
}
},
"sideEffects": false,
"files": [
"dist",
"README.md"
],
"scripts": {
"build": "tsup src/index.ts --format cjs,esm --dts --sourcemap",
"clean": "rimraf dist"
},
"dependencies": {
"@orca-so/tx-sender": "*",
"@orca-so/whirlpools": "*",
"@solana/web3.js": "^2.0.0"
},
"peerDependencies": {
"@solana/web3.js": "^2.0.0"
},
"devDependencies": {
"tsup": "^8.3.6"
}
}
31 changes: 31 additions & 0 deletions ts-sdk/actions/src/config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import {
createKeyPairFromBytes,
createSignerFromKeyPair,
KeyPairSigner,
} from "@solana/web3.js";
export {
setComputeUnitMarginMultiplier,
setJitoBlockEngineUrl,
setJitoTipSetting,
setPriorityFeeSetting,
setRpc,
setJitoFeePercentile,
setPriorityFeePercentile,
getRpcConfig,
} from "@orca-so/tx-sender";

let _payer: KeyPairSigner | undefined;

export async function setPayerFromBytes(pkBytes: Uint8Array<ArrayBuffer>) {
const kp = await createKeyPairFromBytes(pkBytes);
const signer = await createSignerFromKeyPair(kp);
_payer = signer;
return signer;
}

export function getPayer(): KeyPairSigner {
if (!_payer) {
throw new Error("Payer not set. Call setPayer() first.");
}
return _payer;
}
44 changes: 44 additions & 0 deletions ts-sdk/actions/src/harvestFees.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import {
getRpcConfig,
rpcFromUrl,
buildAndSendTransaction,
} from "@orca-so/tx-sender";
import {
fetchPositionsForOwner,
harvestPositionInstructions,
} from "@orca-so/whirlpools";
import { IInstruction } from "@solana/web3.js";
import { getPayer } from "./config";
import { wouldExceedTransactionSize } from "./helpers";

// Harvest fees from all positions owned by an address
export async function harvestAllPositionFees(): Promise<string[]> {
const { rpcUrl } = getRpcConfig();
const rpc = rpcFromUrl(rpcUrl);
const owner = getPayer();

const positions = await fetchPositionsForOwner(rpc, owner.address);
const instructionSets: IInstruction[][] = [];
let currentInstructions: IInstruction[] = [];
for (const position of positions) {
if ("positionMint" in position.data) {
const { instructions } = await harvestPositionInstructions(
rpc,
position.data.positionMint,
owner
);
if (wouldExceedTransactionSize(currentInstructions, instructions)) {
instructionSets.push(currentInstructions);
currentInstructions = [...instructions];
} else {
currentInstructions.push(...instructions);
}
}
}
return Promise.all(
instructionSets.map(async (instructions) => {
let txHash = await buildAndSendTransaction(instructions, owner);
return String(txHash);
})
);
}
24 changes: 24 additions & 0 deletions ts-sdk/actions/src/helpers.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { IInstruction } from "@solana/web3.js";

/**
* Check if adding additional instructions would exceed transaction size limits
* @param currentInstructions Current list of instructions in transaction
* @param instructionsToAdd Instructions to check if they can be added
* @returns True if adding instructions would exceed size limit, false otherwise
*/
export function wouldExceedTransactionSize(
currentInstructions: IInstruction[],
instructionsToAdd: IInstruction[]
): boolean {
// Current Solana transaction size limit is 1232 bytes
const MAX_TRANSACTION_SIZE = 1232;
const INSTRUCTION_OVERHEAD = 40; // Each instruction has ~40 bytes overhead

// Calculate total size in one pass
const totalSize = [...currentInstructions, ...instructionsToAdd].reduce(
(sum, ix) => sum + INSTRUCTION_OVERHEAD + (ix.data?.length ?? 0),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure this calculation is correct. Looks like this doesn't take instruction account addresses

0
);

return totalSize > MAX_TRANSACTION_SIZE;
}
5 changes: 5 additions & 0 deletions ts-sdk/actions/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export * from "./pools";
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would it make sense to follow the same file structure as high-level sdk?

We might even want to reexport some of the 'fetch' functions here but I think we have a separate project for that

export * from "./positions";
export * from "./swap";
export * from "./harvestFees";
export * from "./config";
66 changes: 66 additions & 0 deletions ts-sdk/actions/src/pools.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import { Address } from "@solana/web3.js";
import { getPayer } from "./config";
import {
buildAndSendTransaction,
getRpcConfig,
rpcFromUrl,
} from "@orca-so/tx-sender";
import {
createSplashPoolInstructions,
createConcentratedLiquidityPoolInstructions,
} from "@orca-so/whirlpools";
export { setDefaultSlippageToleranceBps } from "@orca-so/whirlpools";

// Create a splash liquidity pool
export async function createSplashPool(
tokenMintA: Address,
tokenMintB: Address,
initialPrice: number
) {
const { rpcUrl } = getRpcConfig();
const rpc = rpcFromUrl(rpcUrl);
const owner = getPayer();

const { instructions, initializationCost, poolAddress } =
await createSplashPoolInstructions(
rpc,
tokenMintA,
tokenMintB,
initialPrice,
owner
);

return {
callback: () => buildAndSendTransaction(instructions, owner),
initializationCost,
poolAddress,
};
}

// Create a concentrated liquidity pool
export async function createConcentratedLiquidityPool(
tokenMintA: Address,
tokenMintB: Address,
tickSpacing: number,
initialPrice: number
) {
const { rpcUrl } = getRpcConfig();
const rpc = rpcFromUrl(rpcUrl);
const owner = getPayer();

const { instructions, initializationCost, poolAddress } =
await createConcentratedLiquidityPoolInstructions(
rpc,
tokenMintA,
tokenMintB,
tickSpacing,
initialPrice,
owner
);

return {
callback: () => buildAndSendTransaction(instructions, owner),
initializationCost,
poolAddress,
};
}
Loading
Loading