Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
9a574f3
Add: DynamicTickArray
AngSin Dec 5, 2025
fadbb3d
Add trait: TickArrayType
AngSin Dec 7, 2025
33c7633
use one interface (TickArrayType) in decrease_liquidity
AngSin Dec 8, 2025
c027f4f
Clean up decrease_liquidity flow
AngSin Dec 8, 2025
738db86
Update tick_state.tick in update_tick fn just to be safe
AngSin Dec 9, 2025
12b0158
start refactoring open_position/increase_liquidity flow
AngSin Dec 13, 2025
9def866
Finish open_position flow
AngSin Jan 19, 2026
99bef99
fix build & devnet deployment
AngSin Jan 28, 2026
0e3137e
Fix swap_v2 ix
AngSin Jan 28, 2026
d08849b
Add DynamicTickArrays to IDL
AngSin Jan 28, 2026
e9bdfdd
Commit script ot add DynamicTickArray's to IDL
AngSin Jan 29, 2026
2d0558d
Fix type generation for DynamicTickArray
AngSin Jan 29, 2026
dc02bdf
Default to DynamicTickArrays for position creation
AngSin Feb 3, 2026
9d41ed3
script to fetch tick array
AngSin Feb 4, 2026
5285c5b
Add tests in dynamic tick array file (#24)
veerbal1 Feb 10, 2026
e334df0
store fee outside ticks correctly (previous is zero for uninitialised…
AngSin Feb 16, 2026
d18ec52
update initialized tick count for fixed arrays in decrease_liquidity
AngSin Feb 16, 2026
85bef18
Remove unnecessary iterative counting in initialized_tick_count()
AngSin Feb 16, 2026
5643731
Fix double mutable ref issues
AngSin Feb 16, 2026
266d45f
Realloc rent to DynamicTickArray on increase/decrease
AngSin Feb 17, 2026
018d5e4
move common tick array fns to tick_array.rs
AngSin Feb 17, 2026
d19cf72
remove unused tick_array_manager.rs
AngSin Feb 17, 2026
1a66184
fix: resolve double mutable borrow in dynamic tick array realloc (#25)
veerbal1 Mar 4, 2026
543fc9d
Add a QAS program id
AngSin Mar 4, 2026
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
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
.idea
CLAUDE.md
.anchor
.DS_Store
target
Expand All @@ -19,4 +20,5 @@ KeyPairs
*/coverage/

# E2E test state
.devnet-test-state.json
.devnet-test-state.json
tests/helpers/test-admin-keypair.json
6 changes: 3 additions & 3 deletions Anchor.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@ anchor_version = "0.31.1"

[features]
seeds = false
devnet = true
devnet = false

[programs.localnet]
amm_v3 = "6dMXqGZ3ga2dikrYS9ovDXgHGh5RUsb2RTUj6hrQXhk6"
amm_v3 = "B7STfA7vKq3nN7sP5uQo1gr5SQySUyC443wDuCR65Exe"

[programs.devnet]
amm_v3 = "6dMXqGZ3ga2dikrYS9ovDXgHGh5RUsb2RTUj6hrQXhk6"
Expand All @@ -19,5 +19,5 @@ amm_v3 = "6dMXqGZ3ga2dikrYS9ovDXgHGh5RUsb2RTUj6hrQXhk6"
url = "https://github.com/stabbleorg/clmm"

[provider]
cluster = "mainnet"
cluster = "localnet"
wallet = ".keypair/id.json"
66 changes: 5 additions & 61 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,62 +1,6 @@
Raydium-Amm-v3 is an open-sourced concentrated liquidity market maker (CLMM) program built for the Solana ecosystem.
## Building:
### Program:
- Run `yarn build-program`

**Concentrated Liquidity Market Maker (CLMM)** pools allow liquidity providers to select a specific price range at which liquidity is active for trades within a pool. This is in contrast to constant product Automated Market Maker (AMM) pools, where all liquidity is spread out on a price curve from 0 to ∞. For LPs, CLMM design enables capital to be deployed with higher efficiency and earn increased yield from trading fees. For traders, CLMMs improve liquidity depth around the current price which translates to better prices and lower price impact on swaps. CLMM pools can be configured for pairs with different volatility.

## Environment Setup

1. Install `Rust`

```shell
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
rustup default 1.81.0
```

2. Install `Solana `

```shell
sh -c "$(curl -sSfL https://release.anza.xyz/v2.1.0/install)"
```

then run `solana-keygen new` to create a keypair at the default location.

3. install `Anchor`

```shell
# Installing using Anchor version manager (avm)
cargo install --git https://github.com/coral-xyz/anchor avm --locked --force
# Install anchor
avm install 0.31.1
```

## Quickstart

Clone the repository and enter the source code directory.

```
git clone https://github.com/raydium-io/raydium-amm-v3
cd raydium-amm-v3
```

Build

```
anchor build
```

After building, the smart contract files are all located in the target directory.

Deploy

```
anchor deploy
```

Attention, check your configuration and confirm the environment you want to deploy.

# CPI

An example of calling clmm can be found [here](https://github.com/raydium-io/raydium-cpi-example/tree/master/clmm-cpi)

# License

The source code is [licensed](https://github.com/raydium-io/raydium-clmm/blob/master/LICENSE) under Apache 2.0.
### SDK:
- Run `yarn build-sdk`
12 changes: 6 additions & 6 deletions client/src/instructions/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -316,7 +316,7 @@ pub fn get_out_put_amount_and_remaining_accounts(
pool_config: &AmmConfig,
pool_state: &PoolState,
tickarray_bitmap_extension: &TickArrayBitmapExtension,
tick_arrays: &mut VecDeque<TickArrayState>,
tick_arrays: &mut VecDeque<&dyn TickArrayType>,
) -> Result<(u64, VecDeque<i32>), &'static str> {
let (is_pool_current_tick_array, current_valid_tick_array_start_index) = pool_state
.get_first_initialized_tick_array(&Some(*tickarray_bitmap_extension), zero_for_one)
Expand Down Expand Up @@ -349,7 +349,7 @@ fn swap_compute(
sqrt_price_limit_x64: u128,
pool_state: &PoolState,
tickarray_bitmap_extension: &TickArrayBitmapExtension,
tick_arrays: &mut VecDeque<TickArrayState>,
tick_arrays: &mut VecDeque<&dyn TickArrayType>,
) -> Result<(u64, VecDeque<i32>), &'static str> {
if amount_specified == 0 {
return Result::Err("amountSpecified must not be 0");
Expand Down Expand Up @@ -389,11 +389,11 @@ fn swap_compute(
};

let mut tick_array_current = tick_arrays.pop_front().unwrap();
if tick_array_current.start_tick_index != current_valid_tick_array_start_index {
if tick_array_current.start_tick_index() != current_valid_tick_array_start_index {
return Result::Err("tick array start tick index does not match");
}
let mut tick_array_start_index_vec = VecDeque::new();
tick_array_start_index_vec.push_back(tick_array_current.start_tick_index);
tick_array_start_index_vec.push_back(tick_array_current.start_tick_index());
let mut loop_count = 0;
// loop across ticks until input liquidity is consumed, or the limit price is reached
while state.amount_specified_remaining != 0
Expand Down Expand Up @@ -436,11 +436,11 @@ fn swap_compute(
if current_valid_tick_array_start_index.is_none() {
return Result::Err("tick array start tick index out of range limit");
}
if tick_array_current.start_tick_index != current_valid_tick_array_start_index.unwrap()
if tick_array_current.start_tick_index() != current_valid_tick_array_start_index.unwrap()
{
return Result::Err("tick array start tick index does not match");
}
tick_array_start_index_vec.push_back(tick_array_current.start_tick_index);
tick_array_start_index_vec.push_back(tick_array_current.start_tick_index());
let mut first_initialized_tick = tick_array_current
.first_initialized_tick(zero_for_one)
.unwrap();
Expand Down
14 changes: 11 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,10 @@
"main": "index.js",
"scripts": {
"cli": "npx ts-node --files cli",
"test": "echo \"Error: no test specified\" && exit 1"
"test": "echo \"Error: no test specified\" && exit 1",
"build-program": "anchor build",
"update-idl": "node scripts/add-dynamic-tick-array-to-idl.js",
"build-sdk": "anchor build && cp target/idl/amm_v3.json sdk/idl/stabble_clmm.json && cd sdk && yarn generate-clients"
},
"repository": {
"type": "git",
Expand All @@ -25,11 +28,16 @@
"@solana-program/token-2022": "^0.5.0",
"@solana/kit": "^3.0.3",
"@solana/spl-token": "^0.4.14",
"commander": "^14.0.1",
"dotenv": "^17.2.2",
"@solana/web3.js": "^1.98.4",
"@types/bn.js": "^5.2.0",
"bn.js": "^5.2.2",
"commander": "^14.0.1",
"decimal.js": "^10.6.0",
"dotenv": "^17.2.2",
"typescript": "^5.9.2"
},
"devDependencies": {
"solana-bankrun": "^0.4.0",
"vitest": "^4.0.18"
}
}
9 changes: 8 additions & 1 deletion programs/clmm/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,19 @@ doctest = false
[features]
no-entrypoint = []
cpi = ["no-entrypoint"]
default = []
# Enable idl-build by default for IDL generation
# DynamicTickArray struct uses conditional compilation:
# - With idl-build: fixed-size array [DynamicTick; TICK_ARRAY_SIZE_USIZE] for IDL
# - Without idl-build: Vec<DynamicTick> for runtime (though never actually deserialized)
# Runtime code uses DynamicTickArrayLoader which handles variable sizing
default = ["idl-build"]
client = []
no-log-ix-name = []
enable-log = []
devnet = []
qas = []
paramset = []
testing = []
idl-build = ["anchor-lang/idl-build", "anchor-spl/idl-build"]

[dependencies]
Expand Down
24 changes: 24 additions & 0 deletions programs/clmm/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -107,4 +107,28 @@ pub enum ErrorCode {
CalculateOverflow,
#[msg("TransferFee calculate not match")]
TransferFeeCalculateNotMatch,

/// tick array related
#[msg("Tick-spacing is not supported")]
InvalidTickSpacing,
#[msg("Invalid tick array sequence provided for instruction.")]
InvalidTickArraySequence,
#[msg("Tick not found within tick array")]
TickNotFound,
#[msg("TickArray account for different pool provided")]
DifferentPoolTickArrayAccount,
#[msg("Invalid start tick index provided.")]
InvalidStartTick,

// Account Errors
#[msg("Invalid account discriminator")]
AccountDiscriminatorNotFound,
#[msg("Account does not have the expected discriminator")]
AccountDiscriminatorMismatch,
#[msg("Account isn't owned by our program")]
AccountOwnedByWrongProgram,

// Rent calculation errors
#[msg("Failed to calculate rent for tick array")]
RentCalculationError,
}
Loading