@meteora-ag/dlmm
Version:
<p align="center"> <img align="center" src="https://app.meteora.ag/icons/logo.svg" width="180" height="180" /> </p> <br>
23,350 lines • 713 kB
JavaScript
"use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }// src/dlmm/index.ts
var _anchor = require('@coral-xyz/anchor');
var _spltoken = require('@solana/spl-token');
var _web3js = require('@solana/web3.js');
var _decimaljs = require('decimal.js'); var _decimaljs2 = _interopRequireDefault(_decimaljs);
// src/dlmm/constants/index.ts
// src/dlmm/idl/idl.json
var idl_default = {
address: "LBUZKhRxPF3XUpBCjp4YzTKgLccjZhTSDM9YuVaPwxo",
metadata: {
name: "lb_clmm",
version: "0.12.0",
spec: "0.1.0",
description: "Created with Anchor"
},
instructions: [
{
name: "add_liquidity",
discriminator: [181, 157, 89, 67, 143, 182, 52, 72],
accounts: [
{
name: "position",
writable: true
},
{
name: "lb_pair",
writable: true,
relations: [
"position",
"bin_array_bitmap_extension",
"bin_array_lower",
"bin_array_upper"
]
},
{
name: "bin_array_bitmap_extension",
writable: true,
optional: true
},
{
name: "user_token_x",
writable: true
},
{
name: "user_token_y",
writable: true
},
{
name: "reserve_x",
writable: true,
relations: ["lb_pair"]
},
{
name: "reserve_y",
writable: true,
relations: ["lb_pair"]
},
{
name: "token_x_mint",
relations: ["lb_pair"]
},
{
name: "token_y_mint",
relations: ["lb_pair"]
},
{
name: "bin_array_lower",
writable: true
},
{
name: "bin_array_upper",
writable: true
},
{
name: "sender",
signer: true
},
{
name: "token_x_program",
address: "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"
},
{
name: "token_y_program",
address: "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"
},
{
name: "event_authority",
pda: {
seeds: [
{
kind: "const",
value: [
95,
95,
101,
118,
101,
110,
116,
95,
97,
117,
116,
104,
111,
114,
105,
116,
121
]
}
]
}
},
{
name: "program"
}
],
args: [
{
name: "liquidity_parameter",
type: {
defined: {
name: "LiquidityParameter"
}
}
}
]
},
{
name: "add_liquidity2",
discriminator: [228, 162, 78, 28, 70, 219, 116, 115],
accounts: [
{
name: "position",
writable: true
},
{
name: "lb_pair",
writable: true,
relations: ["position", "bin_array_bitmap_extension"]
},
{
name: "bin_array_bitmap_extension",
writable: true,
optional: true
},
{
name: "user_token_x",
writable: true
},
{
name: "user_token_y",
writable: true
},
{
name: "reserve_x",
writable: true,
relations: ["lb_pair"]
},
{
name: "reserve_y",
writable: true,
relations: ["lb_pair"]
},
{
name: "token_x_mint",
relations: ["lb_pair"]
},
{
name: "token_y_mint",
relations: ["lb_pair"]
},
{
name: "sender",
signer: true
},
{
name: "token_x_program"
},
{
name: "token_y_program"
},
{
name: "event_authority",
pda: {
seeds: [
{
kind: "const",
value: [
95,
95,
101,
118,
101,
110,
116,
95,
97,
117,
116,
104,
111,
114,
105,
116,
121
]
}
]
}
},
{
name: "program"
}
],
args: [
{
name: "liquidity_parameter",
type: {
defined: {
name: "LiquidityParameter"
}
}
},
{
name: "remaining_accounts_info",
type: {
defined: {
name: "RemainingAccountsInfo"
}
}
}
]
},
{
name: "add_liquidity_by_strategy",
discriminator: [7, 3, 150, 127, 148, 40, 61, 200],
accounts: [
{
name: "position",
writable: true
},
{
name: "lb_pair",
writable: true,
relations: [
"position",
"bin_array_bitmap_extension",
"bin_array_lower",
"bin_array_upper"
]
},
{
name: "bin_array_bitmap_extension",
writable: true,
optional: true
},
{
name: "user_token_x",
writable: true
},
{
name: "user_token_y",
writable: true
},
{
name: "reserve_x",
writable: true,
relations: ["lb_pair"]
},
{
name: "reserve_y",
writable: true,
relations: ["lb_pair"]
},
{
name: "token_x_mint",
relations: ["lb_pair"]
},
{
name: "token_y_mint",
relations: ["lb_pair"]
},
{
name: "bin_array_lower",
writable: true
},
{
name: "bin_array_upper",
writable: true
},
{
name: "sender",
signer: true
},
{
name: "token_x_program",
address: "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"
},
{
name: "token_y_program",
address: "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"
},
{
name: "event_authority",
pda: {
seeds: [
{
kind: "const",
value: [
95,
95,
101,
118,
101,
110,
116,
95,
97,
117,
116,
104,
111,
114,
105,
116,
121
]
}
]
}
},
{
name: "program"
}
],
args: [
{
name: "liquidity_parameter",
type: {
defined: {
name: "LiquidityParameterByStrategy"
}
}
}
]
},
{
name: "add_liquidity_by_strategy2",
discriminator: [3, 221, 149, 218, 111, 141, 118, 213],
accounts: [
{
name: "position",
writable: true
},
{
name: "lb_pair",
writable: true,
relations: ["position", "bin_array_bitmap_extension"]
},
{
name: "bin_array_bitmap_extension",
writable: true,
optional: true
},
{
name: "user_token_x",
writable: true
},
{
name: "user_token_y",
writable: true
},
{
name: "reserve_x",
writable: true,
relations: ["lb_pair"]
},
{
name: "reserve_y",
writable: true,
relations: ["lb_pair"]
},
{
name: "token_x_mint",
relations: ["lb_pair"]
},
{
name: "token_y_mint",
relations: ["lb_pair"]
},
{
name: "sender",
signer: true
},
{
name: "token_x_program"
},
{
name: "token_y_program"
},
{
name: "event_authority",
pda: {
seeds: [
{
kind: "const",
value: [
95,
95,
101,
118,
101,
110,
116,
95,
97,
117,
116,
104,
111,
114,
105,
116,
121
]
}
]
}
},
{
name: "program"
}
],
args: [
{
name: "liquidity_parameter",
type: {
defined: {
name: "LiquidityParameterByStrategy"
}
}
},
{
name: "remaining_accounts_info",
type: {
defined: {
name: "RemainingAccountsInfo"
}
}
}
]
},
{
name: "add_liquidity_by_strategy_one_side",
discriminator: [41, 5, 238, 175, 100, 225, 6, 205],
accounts: [
{
name: "position",
writable: true
},
{
name: "lb_pair",
writable: true,
relations: [
"position",
"bin_array_bitmap_extension",
"bin_array_lower",
"bin_array_upper"
]
},
{
name: "bin_array_bitmap_extension",
writable: true,
optional: true
},
{
name: "user_token",
writable: true
},
{
name: "reserve",
writable: true
},
{
name: "token_mint"
},
{
name: "bin_array_lower",
writable: true
},
{
name: "bin_array_upper",
writable: true
},
{
name: "sender",
signer: true
},
{
name: "token_program",
address: "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"
},
{
name: "event_authority",
pda: {
seeds: [
{
kind: "const",
value: [
95,
95,
101,
118,
101,
110,
116,
95,
97,
117,
116,
104,
111,
114,
105,
116,
121
]
}
]
}
},
{
name: "program"
}
],
args: [
{
name: "liquidity_parameter",
type: {
defined: {
name: "LiquidityParameterByStrategyOneSide"
}
}
}
]
},
{
name: "add_liquidity_by_weight",
discriminator: [28, 140, 238, 99, 231, 162, 21, 149],
accounts: [
{
name: "position",
writable: true
},
{
name: "lb_pair",
writable: true,
relations: [
"position",
"bin_array_bitmap_extension",
"bin_array_lower",
"bin_array_upper"
]
},
{
name: "bin_array_bitmap_extension",
writable: true,
optional: true
},
{
name: "user_token_x",
writable: true
},
{
name: "user_token_y",
writable: true
},
{
name: "reserve_x",
writable: true,
relations: ["lb_pair"]
},
{
name: "reserve_y",
writable: true,
relations: ["lb_pair"]
},
{
name: "token_x_mint",
relations: ["lb_pair"]
},
{
name: "token_y_mint",
relations: ["lb_pair"]
},
{
name: "bin_array_lower",
writable: true
},
{
name: "bin_array_upper",
writable: true
},
{
name: "sender",
signer: true
},
{
name: "token_x_program",
address: "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"
},
{
name: "token_y_program",
address: "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"
},
{
name: "event_authority",
pda: {
seeds: [
{
kind: "const",
value: [
95,
95,
101,
118,
101,
110,
116,
95,
97,
117,
116,
104,
111,
114,
105,
116,
121
]
}
]
}
},
{
name: "program"
}
],
args: [
{
name: "liquidity_parameter",
type: {
defined: {
name: "LiquidityParameterByWeight"
}
}
}
]
},
{
name: "add_liquidity_by_weight2",
discriminator: [209, 59, 63, 91, 111, 200, 153, 228],
accounts: [
{
name: "position",
writable: true
},
{
name: "lb_pair",
writable: true,
relations: ["position", "bin_array_bitmap_extension"]
},
{
name: "bin_array_bitmap_extension",
writable: true,
optional: true
},
{
name: "user_token_x",
writable: true
},
{
name: "user_token_y",
writable: true
},
{
name: "reserve_x",
writable: true,
relations: ["lb_pair"]
},
{
name: "reserve_y",
writable: true,
relations: ["lb_pair"]
},
{
name: "token_x_mint",
relations: ["lb_pair"]
},
{
name: "token_y_mint",
relations: ["lb_pair"]
},
{
name: "sender",
signer: true
},
{
name: "token_x_program"
},
{
name: "token_y_program"
},
{
name: "event_authority",
pda: {
seeds: [
{
kind: "const",
value: [
95,
95,
101,
118,
101,
110,
116,
95,
97,
117,
116,
104,
111,
114,
105,
116,
121
]
}
]
}
},
{
name: "program"
}
],
args: [
{
name: "liquidity_parameter",
type: {
defined: {
name: "LiquidityParameterByWeight"
}
}
},
{
name: "remaining_accounts_info",
type: {
defined: {
name: "RemainingAccountsInfo"
}
}
}
]
},
{
name: "add_liquidity_one_side",
discriminator: [94, 155, 103, 151, 70, 95, 220, 165],
accounts: [
{
name: "position",
writable: true
},
{
name: "lb_pair",
writable: true,
relations: [
"position",
"bin_array_bitmap_extension",
"bin_array_lower",
"bin_array_upper"
]
},
{
name: "bin_array_bitmap_extension",
writable: true,
optional: true
},
{
name: "user_token",
writable: true
},
{
name: "reserve",
writable: true
},
{
name: "token_mint"
},
{
name: "bin_array_lower",
writable: true
},
{
name: "bin_array_upper",
writable: true
},
{
name: "sender",
signer: true
},
{
name: "token_program",
address: "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"
},
{
name: "event_authority",
pda: {
seeds: [
{
kind: "const",
value: [
95,
95,
101,
118,
101,
110,
116,
95,
97,
117,
116,
104,
111,
114,
105,
116,
121
]
}
]
}
},
{
name: "program"
}
],
args: [
{
name: "liquidity_parameter",
type: {
defined: {
name: "LiquidityOneSideParameter"
}
}
}
]
},
{
name: "add_liquidity_one_side_precise",
discriminator: [161, 194, 103, 84, 171, 71, 250, 154],
accounts: [
{
name: "position",
writable: true
},
{
name: "lb_pair",
writable: true,
relations: [
"position",
"bin_array_bitmap_extension",
"bin_array_lower",
"bin_array_upper"
]
},
{
name: "bin_array_bitmap_extension",
writable: true,
optional: true
},
{
name: "user_token",
writable: true
},
{
name: "reserve",
writable: true
},
{
name: "token_mint"
},
{
name: "bin_array_lower",
writable: true
},
{
name: "bin_array_upper",
writable: true
},
{
name: "sender",
signer: true
},
{
name: "token_program",
address: "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"
},
{
name: "event_authority",
pda: {
seeds: [
{
kind: "const",
value: [
95,
95,
101,
118,
101,
110,
116,
95,
97,
117,
116,
104,
111,
114,
105,
116,
121
]
}
]
}
},
{
name: "program"
}
],
args: [
{
name: "parameter",
type: {
defined: {
name: "AddLiquiditySingleSidePreciseParameter"
}
}
}
]
},
{
name: "add_liquidity_one_side_precise2",
discriminator: [33, 51, 163, 201, 117, 98, 125, 231],
accounts: [
{
name: "position",
writable: true
},
{
name: "lb_pair",
writable: true,
relations: ["position", "bin_array_bitmap_extension"]
},
{
name: "bin_array_bitmap_extension",
writable: true,
optional: true
},
{
name: "user_token",
writable: true
},
{
name: "reserve",
writable: true
},
{
name: "token_mint"
},
{
name: "sender",
signer: true
},
{
name: "token_program"
},
{
name: "event_authority",
pda: {
seeds: [
{
kind: "const",
value: [
95,
95,
101,
118,
101,
110,
116,
95,
97,
117,
116,
104,
111,
114,
105,
116,
121
]
}
]
}
},
{
name: "program"
}
],
args: [
{
name: "liquidity_parameter",
type: {
defined: {
name: "AddLiquiditySingleSidePreciseParameter2"
}
}
},
{
name: "remaining_accounts_info",
type: {
defined: {
name: "RemainingAccountsInfo"
}
}
}
]
},
{
name: "cancel_limit_order",
discriminator: [132, 156, 132, 31, 67, 40, 232, 97],
accounts: [
{
name: "lb_pair",
writable: true,
relations: ["bin_array_bitmap_extension", "limit_order"]
},
{
name: "bin_array_bitmap_extension",
writable: true,
optional: true
},
{
name: "reserve_x",
writable: true,
relations: ["lb_pair"]
},
{
name: "reserve_y",
writable: true,
relations: ["lb_pair"]
},
{
name: "token_x_mint",
relations: ["lb_pair"]
},
{
name: "token_y_mint",
relations: ["lb_pair"]
},
{
name: "limit_order",
writable: true
},
{
name: "owner_token_x",
docs: [
"When dont set it tokenAccount to prevent unnecessary create token account (rent fee) when user only withdraw token y"
],
writable: true
},
{
name: "owner_token_y",
writable: true
},
{
name: "owner",
signer: true
},
{
name: "token_x_program"
},
{
name: "token_y_program"
},
{
name: "memo_program",
address: "MemoSq4gqABAXKb96qnH8TysNcWxMyWCqXgDLGmfcHr"
},
{
name: "event_authority",
pda: {
seeds: [
{
kind: "const",
value: [
95,
95,
101,
118,
101,
110,
116,
95,
97,
117,
116,
104,
111,
114,
105,
116,
121
]
}
]
}
},
{
name: "program"
}
],
args: [
{
name: "bins",
type: {
vec: "i32"
}
},
{
name: "remaining_accounts_info",
type: {
defined: {
name: "RemainingAccountsInfo"
}
}
}
]
},
{
name: "claim_fee",
discriminator: [169, 32, 79, 137, 136, 232, 70, 137],
accounts: [
{
name: "lb_pair",
writable: true,
relations: ["position", "bin_array_lower", "bin_array_upper"]
},
{
name: "position",
writable: true
},
{
name: "bin_array_lower",
writable: true
},
{
name: "bin_array_upper",
writable: true
},
{
name: "sender",
signer: true
},
{
name: "reserve_x",
writable: true,
relations: ["lb_pair"]
},
{
name: "reserve_y",
writable: true,
relations: ["lb_pair"]
},
{
name: "user_token_x",
writable: true
},
{
name: "user_token_y",
writable: true
},
{
name: "token_x_mint",
relations: ["lb_pair"]
},
{
name: "token_y_mint",
relations: ["lb_pair"]
},
{
name: "token_program",
address: "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"
},
{
name: "event_authority",
pda: {
seeds: [
{
kind: "const",
value: [
95,
95,
101,
118,
101,
110,
116,
95,
97,
117,
116,
104,
111,
114,
105,
116,
121
]
}
]
}
},
{
name: "program"
}
],
args: []
},
{
name: "claim_fee2",
discriminator: [112, 191, 101, 171, 28, 144, 127, 187],
accounts: [
{
name: "lb_pair",
writable: true,
relations: ["position"]
},
{
name: "position",
writable: true
},
{
name: "sender",
signer: true
},
{
name: "reserve_x",
writable: true,
relations: ["lb_pair"]
},
{
name: "reserve_y",
writable: true,
relations: ["lb_pair"]
},
{
name: "user_token_x",
writable: true
},
{
name: "user_token_y",
writable: true
},
{
name: "token_x_mint",
relations: ["lb_pair"]
},
{
name: "token_y_mint",
relations: ["lb_pair"]
},
{
name: "token_program_x"
},
{
name: "token_program_y"
},
{
name: "memo_program",
address: "MemoSq4gqABAXKb96qnH8TysNcWxMyWCqXgDLGmfcHr"
},
{
name: "event_authority",
pda: {
seeds: [
{
kind: "const",
value: [
95,
95,
101,
118,
101,
110,
116,
95,
97,
117,
116,
104,
111,
114,
105,
116,
121
]
}
]
}
},
{
name: "program"
}
],
args: [
{
name: "min_bin_id",
type: "i32"
},
{
name: "max_bin_id",
type: "i32"
},
{
name: "remaining_accounts_info",
type: {
defined: {
name: "RemainingAccountsInfo"
}
}
}
]
},
{
name: "claim_reward",
discriminator: [149, 95, 181, 242, 94, 90, 158, 162],
accounts: [
{
name: "lb_pair",
writable: true,
relations: ["position", "bin_array_lower", "bin_array_upper"]
},
{
name: "position",
writable: true
},
{
name: "bin_array_lower",
writable: true
},
{
name: "bin_array_upper",
writable: true
},
{
name: "sender",
signer: true
},
{
name: "reward_vault",
writable: true
},
{
name: "reward_mint"
},
{
name: "user_token_account",
writable: true
},
{
name: "token_program",
address: "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"
},
{
name: "event_authority",
pda: {
seeds: [
{
kind: "const",
value: [
95,
95,
101,
118,
101,
110,
116,
95,
97,
117,
116,
104,
111,
114,
105,
116,
121
]
}
]
}
},
{
name: "program"
}
],
args: [
{
name: "reward_index",
type: "u64"
}
]
},
{
name: "claim_reward2",
discriminator: [190, 3, 127, 119, 178, 87, 157, 183],
accounts: [
{
name: "lb_pair",
writable: true,
relations: ["position"]
},
{
name: "position",
writable: true
},
{
name: "sender",
signer: true
},
{
name: "reward_vault",
writable: true
},
{
name: "reward_mint"
},
{
name: "user_token_account",
writable: true
},
{
name: "token_program"
},
{
name: "memo_program",
address: "MemoSq4gqABAXKb96qnH8TysNcWxMyWCqXgDLGmfcHr"
},
{
name: "event_authority",
pda: {
seeds: [
{
kind: "const",
value: [
95,
95,
101,
118,
101,
110,
116,
95,
97,
117,
116,
104,
111,
114,
105,
116,
121
]
}
]
}
},
{
name: "program"
}
],
args: [
{
name: "reward_index",
type: "u64"
},
{
name: "min_bin_id",
type: "i32"
},
{
name: "max_bin_id",
type: "i32"
},
{
name: "remaining_accounts_info",
type: {
defined: {
name: "RemainingAccountsInfo"
}
}
}
]
},
{
name: "close_bin_array",
discriminator: [68, 174, 88, 80, 181, 204, 19, 224],
accounts: [
{
name: "lb_pair",
relations: ["bin_array"]
},
{
name: "bin_array",
writable: true
},
{
name: "rent_receiver",
writable: true,
signer: true
},
{
name: "signer",
signer: true
}
],
args: []
},
{
name: "close_claim_fee_operator_account",
discriminator: [184, 213, 88, 31, 179, 101, 130, 36],
accounts: [
{
name: "claim_fee_operator",
writable: true
},
{
name: "rent_receiver",
writable: true
},
{
name: "signer",
signer: true
}
],
args: []
},
{
name: "close_limit_order_if_empty",
discriminator: [57, 124, 36, 155, 126, 249, 93, 171],
accounts: [
{
name: "limit_order",
writable: true
},
{
name: "owner",
signer: true
},
{
name: "rent_receiver",
writable: true
},
{
name: "event_authority",
pda: {
seeds: [
{
kind: "const",
value: [
95,
95,
101,
118,
101,
110,
116,
95,
97,
117,
116,
104,
111,
114,
105,
116,
121
]
}
]
}
},
{
name: "program"
}
],
args: []
},
{
name: "close_operator_account",
discriminator: [171, 9, 213, 74, 120, 23, 3, 29],
accounts: [
{
name: "operator",
writable: true
},
{
name: "signer",
signer: true
},
{
name: "rent_receiver",
writable: true
}
],
args: []
},
{
name: "close_position",
discriminator: [123, 134, 81, 0, 49, 68, 98, 98],
accounts: [
{
name: "position",
writable: true
},
{
name: "lb_pair",
writable: true
},
{
name: "bin_array_lower",
writable: true
},
{
name: "bin_array_upper",
writable: true
},
{
name: "sender",
signer: true
},
{
name: "rent_receiver",
writable: true
},
{
name: "event_authority",
pda: {
seeds: [
{
kind: "const",
value: [
95,
95,
101,
118,
101,
110,
116,
95,
97,
117,
116,
104,
111,
114,
105,
116,
121
]
}
]
}
},
{
name: "program"
}
],
args: []
},
{
name: "close_position2",
discriminator: [174, 90, 35, 115, 186, 40, 147, 226],
accounts: [
{
name: "position",
writable: true
},
{
name: "sender",
signer: true
},
{
name: "rent_receiver",
writable: true
},
{
name: "event_authority",
pda: {
seeds: [
{
kind: "const",
value: [
95,
95,
101,
118,
101,
110,
116,
95,
97,
117,
116,
104,
111,
114,
105,
116,
121
]
}
]
}
},
{
name: "program"
}
],
args: []
},
{
name: "close_position_if_empty",
discriminator: [59, 124, 212, 118, 91, 152, 110, 157],
accounts: [
{
name: "position",
writable: true
},
{
name: "sender",
signer: true
},
{
name: "rent_receiver",
writable: true
},
{
name: "event_authority",
pda: {
seeds: [
{
kind: "const",
value: [
95,
95,
101,
118,
101,
110,
116,
95,
97,
117,
116,
104,
111,
114,
105,
116,
121
]
}
]
}
},
{
name: "program"
}
],
args: []
},
{
name: "close_preset_parameter",
discriminator: [4, 148, 145, 100, 134, 26, 181, 61],
accounts: [
{
name: "preset_parameter",
writable: true
},
{
name: "operator"
},
{
name: "signer",
signer: true
},
{
name: "rent_receiver",
writable: true
}
],
args: []
},
{
name: "close_preset_parameter2",
discriminator: [39, 25, 95, 107, 116, 17, 115, 28],
accounts: [
{
name: "preset_parameter",
writable: true
},
{
name: "operator"
},
{
name: "signer",
signer: true
},
{
name: "rent_receiver",
writable: true
}
],
args: []
},
{
name: "close_token_badge",
discriminator: [108, 146, 86, 110, 179, 254, 10, 104],
accounts: [
{
name: "token_badge",
writable: true
},
{
name: "rent_receiver",
writable: true
},
{
name: "operator"
},
{
name: "signer",
signer: true
}
],
args: []
},
{
name: "create_operator_account",
discriminator: [221, 64, 246, 149, 240, 153, 229, 163],
accounts: [
{
name: "operator",
writable: true,
pda: {
seeds: [
{
kind: "const",
value: [111, 112, 101, 114, 97, 116, 111, 114]
},
{
kind: "account",
path: "whitelisted_signer"
}
]
}
},
{
name: "whitelisted_signer"
},
{
name: "signer",
signer: true
},
{
name: "payer",
writable: true,
signer: true
},
{
name: "system_program",
address: "11111111111111111111111111111111"
}
],
args: [
{
name: "permission",
type: "u128"
}
]
},
{
name: "decrease_position_length",
discriminator: [194, 219, 136, 32, 25, 96, 105, 37],
accounts: [
{
name: "rent_receiver",
writable: true
},
{
name: "position",
writable: true
},
{
name: "owner",
signer: true,
relations: ["position"]
},
{
name: "system_program",
address: "11111111111111111111111111111111"
},
{
name: "event_authority",
pda: {
seeds: [
{
kind: "const",
value: [
95,
95,
101,
118,
101,
110,
116,
95,
97,
117,
116,
104,
111,
114,
105,
116,
121
]
}
]
}
},
{
name: "program"
}
],
args: [
{
name: "length_to_remove",
type: "u16"
},
{
name: "side",
type: "u8"
}
]
},
{
name: "for_idl_type_generation_do_not_call",
discriminator: [180, 105, 69, 80, 95, 50, 73, 108],
accounts: [
{
name: "dummy_zc_account"
}
],
args: [
{
name: "_ix",
type: {
defined: {
name: "DummyIx"
}
}
}
]
},
{
name: "fund_reward",
discriminator: [188, 50, 249, 165, 93, 151, 38, 63],
accounts: [
{
name: "lb_pair",
writable: true,
relations: ["bin_array"]
},
{
name: "reward_vault",
writable: true
},
{
name: "reward_mint"
},
{
name: "funder_token_account",
writable: true
},
{
name: "funder",
signer: true
},
{
name: "bin_array",
writable: true
},
{
name: "token_program"
},
{
name: "event_authority",
pda: {
seeds: [
{
kind: "const",
value: [
95,
95,
101,
118,
101,
110,
116,
95,
97,
117,
116,
104,
111,
114,
105,
116,
121
]
}
]
}
},
{
name: "program"
}
],
args: [
{
name: "reward_index",
type: "u64"
},
{
name: "amount",
type: "u64"
},
{
name: "carry_forward",
type: "bool"
},
{
name: "remaining_accounts_info",
type: {
defined: {
name: "RemainingAccountsInfo"
}
}
}
]
},
{
name: "go_to_a_bin",
discriminator: [146, 72, 174, 224, 40, 253, 84, 174],
accounts: [
{
name: "lb_pair",
writable: true,
relations: [
"bin_array_bitmap_extension",
"from_bin_array",
"to_bin_array"
]
},
{
name: "bin_array_bitmap_extension",
optional: true
},
{
name: "from_bin_array",
optional: true
},
{
name: "to_bin_array",
optional: true
},
{
name: "event_authority",
pda: {
seeds: [
{
kind: "const",
value: [
95,
95,
101,
118,
101,
110,
116,
95,
97,
117,
116,
104,
111,
114,
105,
116,
121
]
}
]
}
},
{
name: "program"
}
],
args: [
{
name: "bin_id",
type: "i32"
}
]
},
{
name: "increase_oracle_length",
discriminator: [190, 61, 125, 87, 103, 79, 158, 173],
accounts: [
{
name: "oracle",
writable: true
},
{
name: "funder",
writable: true,
signer: true
},
{
name: "system_program",
address: "11111111111111111111111111111111"
},
{
name: "event_authority",
pda: {
seeds: [
{
kind: "const",
value: [
95,
95,
101,
118,
101,
110,
116,
95,
97,
117,
116,
104,
111,
114,
105,
116,
121
]
}
]
}
},
{
name: "program"
}
],
args: [
{
name: "length_to_add",
type: "u64"
}
]
},
{
name: "increase_position_length",
discriminator: [80, 83, 117, 211, 66, 13, 33, 149],
accounts: [
{
name: "funder",
writable: true,
signer: true
},
{
name: "lb_pair",
relations: ["position"]
},
{
name: "position",
writable: true
},
{
name: "owner",
signer: true,
relations: ["position"]
},
{
name: "system_program",
address: "11111111111111111111111111111111"
},
{
name: "event_authority",
pda: {
seeds: [
{
kind: "const",
value: [
95,
95,
101,
118,
101,
110,
116,
95,
97,
117,
116,
104,
111,
114,
105,
116,
121
]
}
]
}
},
{
name: "program"
}
],
args: [
{
name: "length_to_add",
type: "u16"
},
{
name: "side",
type: "u8"
}
]
},
{
name: "increase_position_length2",
discriminator: [255, 210, 204, 71, 115, 137, 225, 113],
accounts: [
{
name: "funder",
writable: true,
signer: true
},
{
name: "lb_pair",
relations: ["position"]
},
{
name: "position",
writable: true
},
{
name: "owner",
signer: true,
relations: ["position"]
},
{
name: "system_program",
address: "11111111111111111111111111111111"
},
{
name: "event_authority",
pda: {
seeds: [
{
kind: "const",
value: [
95,
95,
101,
118,
101,
110,
116,
95,
97,
117,
116,
104,
111,
114,
105,
116,
121
]
}
]
}
},
{
name: "program"
}
],
args: [
{
name: "minimum_upper_bin_id",
type: "i32"
}
]
},
{
name: "initialize_bin_array",
discriminator: [35, 86, 19, 185, 78, 212, 75, 211],
accounts: [
{
name: "lb_pair"
},
{
name: "bin_array",
writable: true,
pda: {
seeds: [
{
kind: "const",
value: [98, 105, 110, 95, 97, 114, 114, 97, 121]
},
{
kind: "account",
path: "lb_pair"
},
{
kind: "arg",
path: "index"
}
]
}
},
{
name: "funder",
writable: true,
signer: true
},
{
name: "system_program",
address: "11111111111111111111111111111111"
}
],
args: [
{
name: "index",
type: "i64"
}
]
},
{
name: "initialize_bin_array_bitmap_extension",
discriminator: [47, 157, 226, 180, 12, 240, 33, 71],
accounts: [
{
name: "lb_pair"
},
{
name: "bin_array_bitmap_extension",
docs: [
"Initialize an account to store if a bin array is initialized."
],
writable: true,
pda: {
seeds: [
{
kind: "const",
value: [98, 105, 116, 109, 97, 112]
},
{
kind: "account",
path: "lb_pair"
}
]
}
},
{
name: "funder",
writable: true,
signer: true
},
{
name: "system_program",
address: "11111111111111111111111111111111"
},
{
name: "rent"
}
],
args: []
},
{
name: "initialize_customizable_permissionless_lb_pair",
discriminator: [46, 39, 41, 135, 111, 183, 200, 64],
accounts: [
{
name: "lb_pair",
writable: true
},
{
name: "bin_array_bitmap_extension",
writable: true,
optional: true,
pda: {
seeds: [
{
kind: "const",
value: [98, 105, 116, 109, 97, 112]
},
{
kind: "account",
path: "lb_pair"
}
]
}
},
{
name: "token_mint_x"
},
{
name: "token_mint_y"
},
{
name: "reserve_x",
writable: true,
pda: {
seeds: [
{
kind: "account",
path: "lb_pair"
},
{
kind: "account",
path: "token_mint_x"
}
]
}
},
{
name: "reserve_y",
writable: true,
pda: {
seeds: [
{
kind: "account",
path: "lb_pair"
},
{
kind: "account",
path: "token_mint_y"
}
]
}
},
{
name: "oracle",
writable: true,
pda: {
seeds: [
{
kind: "const",
value: [111, 114, 97, 99, 108, 101]
},
{
kind: "account",
path: "lb_pair"
}
]
}
},
{
name: "user_token_x"
},
{
name: "funder",
writable: true,
signer: true
},
{
name: "token_program",
address: "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"
},
{
name: "system_program",
address: "11111111111111111111111111111111"
},
{
name: "user_token_y"
},
{
name: "event_authority",
pda: {
seeds: [
{
kind: "const",
value: [
95,
95,
101,
118,
101,
110,
116,
95,
97,
117,
116,
104,
111,
114,
105,
116,
121
]
}
]
}
},
{
name: "program"
}
],
args: [
{
name: "params",
type: {
defined: {
name: "CustomizableParams"
}
}
}
]
},
{
name: "initialize_customizable_permissionless_lb_pair2",
discriminator: [243, 73, 129, 126, 51, 19, 241, 107],
accounts: [
{
name: "lb_pair",
writable: true
},
{
name: "bin_array_bitmap_extension",
writable: true,
optional: true,
pda: {
seeds: [
{
kind: "const",
value: [98, 105, 116, 109, 97, 112]
},
{
kind: "account",
path: "lb_pair"
}
]
}
},
{
name: "token_mint_x"
},
{
name: "token_mint_y"
},
{
name: "reserve_x",
writable: true,
pda: {
seeds: [
{
kind: "account",
path: "lb_pair"
},
{
kind: "account",
path: "token_mint_x"
}
]
}
},
{
name: "reserve_y",
writable: true,
pda: {
seeds: [
{
kind: "account",
path: "lb_pair"
},
{
kind: "account",
path: "token_mint_y"
}
]
}
},
{
name: "oracle",
writable: true,
pda: {
seeds: [
{
kind: "const",
value: [111, 114, 97, 99, 108, 101]
},
{
kind: "account",
path: "lb_pair"
}
]
}
},
{
name: "user_token_x"
},
{
name: "funder",
writable: true,
signer: true
},
{
name: "token_badge_x",
optional: true
},
{
name: "token_badge_y",
optional: true
},
{
name: "token_program_x"
},
{
name: "token_program_y"
},
{
name: "system_program",
address: "11111111111111111111111111111111"
},
{
name: "user_token_y"
},
{
name: "event_authority",
pda: {
seeds: [
{
kind: "const",
value: [
95,
95,
101,
118,
101,
110,
116,
95,
97,
117,
116,
104,
111,
114,
105,
116,
121
]
}
]
}
},
{
name: "program"
}
],
args: [
{
name: "params",
type: {
defined: {
name: "CustomizableParams"
}
}
}
]
},
{
name: "initialize_lb_pair",
discriminator: [45, 154, 237, 210, 221, 15, 166, 92],
accounts: [
{
name: "lb_pair",
writable: true
},
{
name: "bin_array_bitmap_extension",
writable: true,
optional: true,
pda: {
seeds: [
{
kind: "const",
value: [98, 105, 116, 109, 97, 112]
},
{
kind: "account",
path: "lb_pair"
}
]
}
},
{
name: "token_mint_x"
},
{
name: "token_mint_y"
},
{
name: "reserve_x",
writable: true,
pda: {
seeds: [
{
kind: "account",
path: "lb_pair"
},
{
kind: "account",
path: "token_mint_x"
}
]
}
},
{
name: "reserve_y",
writable: true,
pda: {
seeds: [
{
kind: "account",
path: "lb_pair"
},
{
kind: "account",
path: "token_mint_y"
}
]
}
},
{
name: "oracle",
writable: true,
pda: {
seeds: [
{
kind: "const",
value: [111, 114, 97, 99, 108, 101]
},
{
kind: "account",
path: "lb_pair"
}
]
}
},
{
name: "preset_parameter"
},
{
name: "funder",
writable: true,
signer: true
},
{
name: "token_program",
address: "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"
},
{
name: "system_program",
address: "11111111111111111111111111111111"
},
{
name: "rent"
},
{
name: "event_authority",
pda: {
seeds: [
{
kind: "const",
value: [
95,
95,
101,
118,
101,
110,
116,
95,
97,
117,
116,
104,
111,
114,
105,
116,
121
]
}
]
}
},
{
name: "program"
}
],
args: [
{
name: "active_id",
type: "i32"
},
{
name: "bin_step",
type: "u16"
}
]
},
{
name: "initialize_lb_pair2",
discriminator: [73, 59, 36, 120, 237, 83, 108, 198],
accounts: [
{
name: "lb_pair",
writable: true
},
{
name: "bin_array_bitmap_extension",
writable: true,
optional: true,
pda: {
seeds: [
{
kind: "const",
value: [98, 105, 116, 109, 97, 112]
},
{
kind: "account",
path: "lb_pair"
}
]
}
},
{
name: "token_mint_x"
},
{
name: "token_mint_y"
},
{
name: "reserve_x",
writable: true,
pda: {
seeds: [
{
kind: "account",
path: "lb_pair"
},
{
kind: "account",
path: "token_mint_x"
}
]
}
},
{
name: "reserve_y",
writable: true,
pda: {
seeds: [
{
kind: "account",
path: "lb_pair"
},
{
kind: "account",
path: "token_mint_y"
}
]
}
},
{
name: "oracle",
writable: true,
pda: {
seeds: [
{
kind: "const",
value: [111, 114, 97, 99, 108, 101]
},
{
kind: "account",
path: "lb_pair"
}
]
}
},
{
name: "preset_parameter"
},
{
name: "funder",
writable: true,
signer: true
},
{
name: "token_badge_x",
optional: true
},
{
name: "token_badge_y",
optional: true
},
{
name: "token_program_x"
},
{
name: "token_program_y"
},
{
name: "system_program",
address: "11111111111111111111111111111111"
},
{
name: "event_authority",
pda: {
seeds: [
{
kind: "const",
value: [
95,
95,
101,
118,
101,
110,
116,
95,
97,
117,
116,
104,
111,
114,
105,
116,
121
]
}
]
}
},
{
name: "program"
}
],
args: [
{
name: "params",
type: {
defined: {
name: "InitializeLbPair2Params"
}
}
}
]
},
{
name: "initialize_permission_lb_pair",
discriminator: [108, 102, 213, 85, 251, 3, 53, 21],
accounts: [
{
name: "base",
signer: true
},
{
name: "lb_pair",
writable: true
},
{
name: "bin_array_bitmap_extension",
writable: true,
optional: true,
pda: {
seeds: [
{
kind: "const",
value: [98, 105, 116, 109, 97, 112]
},
{
kind: "account",
path: "lb_pair"
}
]
}
},
{
name: "token_mint_x"
},
{
name: "token_mint_y"
},
{
name: "reserve_x",
writable: true,
pda: {
seeds: [
{
kind: "account",
path: "lb_pair"
},
{
kind: "account",
path: "token_mint_x"
}
]
}
},
{
name: "reserve_y",
writable: true,
pda: {
seeds: [
{
kind: "account",
path: "lb_pair"
},
{
kind: "account",
path: "token_mint_y"
}
]
}
},
{
name: "oracle",
writable: true,
pda: {
seeds: [
{
kind: "const",
value: [111, 114, 97, 99, 108, 101]
},
{
kind: "account",
path: "lb_pair"
}
]
}
},
{
name: "payer",
writable: true,
signer: true
},
{
name: "operator"
},
{
name: "signer",
signer: true
},
{
name: "token_badge_x",
optional: true
},
{
name: "token_badge_y",
optional: true
},
{
name: "token_program_x"
},
{
name: "token_program_y"
},
{
name: "system_program",
address: "11111111111111111111111111111111"
},
{
name: "event_authority",
pda: {
seeds: [
{
kind: "const",
value: [
95,
95,
101,
118,
101,
110,
116,
95,
97,
117,
116,
104,
111,
114,
105,
116,
121
]
}
]
}
},
{
name: "program"
}
],
args: [
{
name: "ix_data",
type: {
defined: {
name: "InitPermissionPairIx"
}
}
}
]
},
{
name: "initialize_position",
discriminator: [219, 192, 234, 71, 190, 191, 102, 80],
accounts: [
{
name: "payer",
writable: true,
signer: true
},
{
name: "position",
writable: true,
signer: true
},
{
name: "lb_pair"
},
{
name: "owner",
signer: true
},
{
name: "system_program",
address: "11111111111111111111111111111111"
},
{
name: "rent"
},
{
name: "event_authority",
pda: {
seeds: [
{
kind: "const",
value: [
95,
95,
101,
118,
101,
110,
116,
95,
97,
117,
116,
104,
111,
114,
105,
116,
121
]
}
]
}
},
{
name: "program"
}
],
args: [
{
name: "lower_bin_id",
type: "i32"
},
{
name: "width",
type: "i32"
}
]
},
{
name: "initialize_position2",
discriminator: [143, 19, 242, 145, 213, 15, 104, 115],
accounts: [
{
name: "payer",
writable: true,
signer: true
},
{
name: "position",
writable: true,
signer: true
},
{
name: "lb_pair"
},
{
name: "owner",
signer: true
},
{
name: "system_program",
address: "11111111111111111111111111111111"
},
{
name: "event_authority",
pda: {
seeds: [
{
kind: "const",
value: [
95,
95,
101,
118,
101,
110,
116,
95,
97,
117,
116,
104,
111,
114,
105,
116,
121
]
}
]
}
},
{
name: "program"
}
],
args: [
{
name: "lower_bin_id",
type: "i32"
},
{
name: "width",
type: "i32"
}
]
},
{
name: "initialize_position_by_operator",
discriminator: [251, 189, 190, 244, 117, 254, 35, 148],
accounts: [
{
name: "payer",
writable: true,
signer: true
},
{
name: "base",
signer: true
},
{
name: "position",
writable: true,
pda: {
seeds: [
{
kind: "const",
value: [112, 111, 115, 105, 116, 105, 111, 110]
},
{
kind: "account",
path: "lb_pair"
},
{
kind: "account",
path: "base"
},
{
kind: "arg",
path: "lower_bin_id"
},
{
kind: "arg",
path: "width"
}
]
}
},
{
name: "lb_pair"
},
{
name: "owner"
},
{
name: "operator",
docs: ["operator"],
signer: true
},
{
name: "operator_token_x"
},
{
name: "owner_token_x"
},
{
name: "system_program",
address: "11111111111111111111111111111111"
},
{
name: "event_authority",
pda: {
seeds: [
{
kind: "const",
value: [
95,
95,
101,
118,
101,
110,
116,
95,
97,
117,
116,
104,
111,
114,
105,
116,
121
]
}
]
}
},
{
name: "program"
}
],
args: [
{
name: "lower_bin_id",
type: "i32"
},
{
name: "width",
type: "i32"
},
{
name: "fee_owner",
type: "pubkey"
},
{
name: "lock_release_point",
type: "u64"
}
]
},
{
name: "initialize_position_pda",
discriminator: [46, 82, 125, 146, 85, 141, 228, 153],
accounts: [
{
name: "payer",
writable: true,
signer: true
},
{
name: "base",
signer: true
},
{
name: "position",
writable: true,
pda: {
seeds: [
{
kind: "const",
value: [112, 111, 115, 105, 116, 105, 111, 110]
},
{
kind: "account",
path: "lb_pair"
},
{
kind: "account",
path: "base"
},
{
kind: "arg",
path: "lower_bin_id"
},
{
kind: "arg",
path: "width"
}
]
}
},
{
name: "lb_pair"
},
{
name: "owner",
docs: ["owner"],
signer: true
},
{
name: "system_program",
address: "11111111111111111111111111111111"
},
{
name: "rent"
},
{
name: "event_authority",
pda: {
seeds: [
{
kind: "const",
value: [
95,
95,
101,
118,
101,
110,
116,
95,
97,
117,
116,
104,
111,
114,
105,
116,
121
]
}
]
}
},
{
name: "program"
}
],
args: [
{
name: "lower_bin_id",
type: "i32"
},
{
name: "width",
type: "i32"
}
]
},
{
name: "initialize_preset_parameter",
discriminator: [66, 188, 71, 211, 98, 109, 14, 186],
accounts: [
{
name: "preset_parameter",
writable: true,
pda: {
seeds: [
{
kind: "const",
value: [
112,
114,
101,
115,
101,
116,
95,
112,
97,
114,
97,
109,
101,
116,
101,
114,
50
]
},
{
kind: "arg",
path: "ix.index"
}
]
}
},
{
name: "operator"
},
{
name: "signer",
signer: true
},
{
name: "payer",
writable: true,
signer: true
},
{
name: "system_program",
address: "11111111111111111111111111111111"
}
],
args: [
{
name: "ix",
type: {
defined: {
name: "InitPresetParametersIx"
}
}
}
]
},
{
name: "initialize_reward",
discriminator: [95, 135, 192, 196, 242, 129, 230, 68],
accounts: [
{
name: "lb_pair",
writable: true
},
{
name: "reward_vault",
writable: true,
pda: {
seeds: [
{
kind: "account",
path: "lb_pair"
},
{
kind: "arg",
path: "reward_index"
}
]
}
},
{
name: "reward_mint"
},
{
name: "token_badge",
optional: true
},
{
name: "operator"
},
{
name: "signer",
signer: true
},
{
name: "payer",
writable: true,
signer: true
},
{
name: "token_program"
},
{
name: "system_program",
address: "11111111111111111111111111111111"
},
{
name: "event_authority",
pda: {
seeds: [
{
kind: "const",
value: [
95,
95,
101,
118,
101,
110,
116,
95,
97,
117,
116,
104,
111,
114,
105,
116,
121
]
}
]
}
},
{
name: "program"
}
],
args: [
{
name: "reward_index",
type: "u64"
},
{
name: "reward_duration",
type: "u64"
},
{
name: "funder",
type: "pubkey"
}
]
},
{
name: "initialize_token_badge",
discriminator: [253, 77, 205, 95, 27, 224, 89, 223],
accounts: [
{
name: "token_mint"
},
{
name: "token_badge",
writable: true,
pda: {
seeds: [
{
kind: "const",
value: [116, 111, 107, 101, 110, 95, 98, 97, 100, 103, 101]
},
{
kind: "account",
path: "token_mint"
}
]
}
},
{
name: "operator"
},
{
name: "signer",
signer: true
},
{
name: "payer",
writable: true,
signer: true
},
{
name: "system_program",
address: "11111111111111111111111111111111"
}
],
args: []
},
{
name: "place_limit_order",
discriminator: [108, 176, 33, 186, 146, 229, 1, 197],
accounts: [
{
name: "lb_pair",
writable: true,
relations: ["bin_array_bitmap_extension"]
},
{
name: "bin_array_bitmap_extension",
writable: true,
optional: true
},
{
name: "reserve",
writable: true
},
{
name: "token_mint"
},
{
name: "limit_order",
writable: true,
signer: true
},
{
name: "payer",
writable: true,
signer: true
},
{
name: "owner"
},
{
name: "user_token",
writable: true
},
{
name: "sender",
signer: true
},
{
name: "token_program"
},
{
name: "system_program",
address: "11111111111111111111111111111111"
},
{
name: "event_authority",
pda: {
seeds: [
{
kind: "const",
value: [
95,
95,
101,
118,
101,
110,
116,
95,
97,
117,
116,
104,
111,
114,
105,
116,
121
]
}
]
}
},
{
name: "program"
}
],
args: [
{
name: "params",
type: {
defined: {
name: "PlaceLimitOrderParams"
}
}
},
{
name: "remaining_accounts_info",
type: {
defined: {
name: "RemainingAccountsInfo"
}
}
}
]
},
{
name: "rebalance_liquidity",
discriminator: [92, 4, 176, 193, 119, 185, 83, 9],
accounts: [
{
name: "position",
writable: true
},
{
name: "lb_pair",
writable: true,
relations: ["position", "bin_array_bitmap_extension"]
},
{
name: "bin_array_bitmap_extension",
writable: true,
optional: true
},
{
name: "user_token_x",
writable: true
},
{
name: "user_token_y",
writable: true
},
{
name: "reserve_x",
writable: true,
relations: ["lb_pair"]
},
{
name: "reserve_y",
writable: true,
relations: ["lb_pair"]
},
{
name: "token_x_mint",
relations: ["lb_pair"]
},
{
name: "token_y_mint",
relations: ["lb_pair"]
},
{
name: "owner",
signer: true,
relations: ["position"]
},
{
name: "rent_payer",
writable: true,
signer: true
},
{
name: "token_x_program"
},
{
name: "token_y_program"
},
{
name: "memo_program",
address: "MemoSq4gqABAXKb96qnH8TysNcWxMyWCqXgDLGmfcHr"
},
{
name: "system_program",
address: "11111111111111111111111111111111"
},
{
name: "event_authority",
pda: {
seeds: [
{
kind: "const",
value: [
95,
95,
101,
118,
101,
110,
116,
95,
97,
117,
116,
104,
111,
114,
105,
116,
121
]
}
]
}
},
{
name: "program"
}
],
args: [
{
name: "params",
type: {
defined: {
name: "RebalanceLiquidityParams"
}
}
},
{
name: "remaining_accounts_info",
type: {
defined: {
name: "RemainingAccountsInfo"
}
}
}
]
},
{
name: "remove_all_liquidity",
discriminator: [10, 51, 61, 35, 112, 105, 24, 85],
accounts: [
{
name: "position",
writable: true
},
{
name: "lb_pair",
writable: true,
relations: [
"position",
"bin_array_bitmap_extension",
"bin_array_lower",
"bin_array_upper"
]
},
{
name: "bin_array_bitmap_extension",
writable: true,
optional: true
},
{
name: "user_token_x",
writable: true
},
{
name: "user_token_y",
writable: true
},
{
name: "reserve_x",
writable: true,
relations: ["lb_pair"]
},
{
name: "reserve_y",
writable: true,
relations: ["lb_pair"]
},
{
name: "token_x_mint",
relations: ["lb_pair"]
},
{
name: "token_y_mint",
relations: ["lb_pair"]
},
{
name: "bin_array_lower",
writable: true
},
{
name: "bin_array_upper",
writable: true
},
{
name: "sender",
signer: true
},
{
name: "token_x_program",
address: "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"
},
{
name: "token_y_program",
address: "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"
},
{
name: "event_authority",
pda: {
seeds: [
{
kind: "const",
value: [
95,
95,
101,
118,
101,
110,
116,
95,
97,
117,
116,
104,
111,
114,
105,
116,
121
]
}
]
}
},
{
name: "program"
}
],
args: []
},
{
name: "remove_liquidity",
discriminator: [80, 85, 209, 72, 24, 206, 177, 108],
accounts: [
{
name: "position",
writable: true
},
{
name: "lb_pair",
writable: true,
relations: [
"position",
"bin_array_bitmap_extension",
"bin_array_lower",
"bin_array_upper"
]
},
{
name: "bin_array_bitmap_extension",
writable: true,
optional: true
},
{
name: "user_token_x",
writable: true
},
{
name: "user_token_y",
writable: true
},
{
name: "reserve_x",
writable: true,
relations: ["lb_pair"]
},
{
name: "reserve_y",
writable: true,
relations: ["lb_pair"]
},
{
name: "token_x_mint",
relations: ["lb_pair"]
},
{
name: "token_y_mint",
relations: ["lb_pair"]
},
{
name: "bin_array_lower",
writable: true
},
{
name: "bin_array_upper",
writable: true
},
{
name: "sender",
signer: true
},
{
name: "token_x_program",
address: "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"
},
{
name: "token_y_program",
address: "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"
},
{
name: "event_authority",
pda: {
seeds: [
{
kind: "const",
value: [
95,
95,
101,
118,
101,
110,
116,
95,
97,
117,
116,
104,
111,
114,
105,
116,
121
]
}
]
}
},
{
name: "program"
}
],
args: [
{
name: "bin_liquidity_removal",
type: {
vec: {
defined: {
name: "BinLiquidityReduction"
}
}
}
}
]
},
{
name: "remove_liquidity2",
discriminator: [230, 215, 82, 127, 241, 101, 227, 146],
accounts: [
{
name: "position",
writable: true
},
{
name: "lb_pair",
writable: true,
relations: ["position", "bin_array_bitmap_extension"]
},
{
name: "bin_array_bitmap_extension",
writable: true,
optional: true
},
{
name: "user_token_x",
writable: true
},
{
name: "user_token_y",
writable: true
},
{
name: "reserve_x",
writable: true,
relations: ["lb_pair"]
},
{
name: "reserve_y",
writable: true,
relations: ["lb_pair"]
},
{
name: "token_x_mint",
relations: ["lb_pair"]
},
{
name: "token_y_mint",
relations: ["lb_pair"]
},
{
name: "sender",
signer: true
},
{
name: "token_x_program"
},
{
name: "token_y_program"
},
{
name: "memo_program",
address: "MemoSq4gqABAXKb96qnH8TysNcWxMyWCqXgDLGmfcHr"
},
{
name: "event_authority",
pda: {
seeds: [
{
kind: "const",
value: [
95,
95,
101,
118,
101,
110,
116,
95,
97,
117,
116,
104,
111,
114,
105,
116,
121
]
}
]
}
},
{
name: "program"
}
],
args: [
{
name: "bin_liquidity_removal",
type: {
vec: {
defined: {
name: "BinLiquidityReduction"
}
}
}
},
{
name: "remaining_accounts_info",
type: {
defined: {
name: "RemainingAccountsInfo"
}
}
}
]
},
{
name: "remove_liquidity_by_range",
discriminator: [26, 82, 102, 152, 240, 74, 105, 26],
accounts: [
{
name: "position",
writable: true
},
{
name: "lb_pair",
writable: true,
relations: [
"position",
"bin_array_bitmap_extension",
"bin_array_lower",
"bin_array_upper"
]
},
{
name: "bin_array_bitmap_extension",
writable: true,
optional: true
},
{
name: "user_token_x",
writable: true
},
{
name: "user_token_y",
writable: true
},
{
name: "reserve_x",
writable: true,
relations: ["lb_pair"]
},
{
name: "reserve_y",
writable: true,
relations: ["lb_pair"]
},
{
name: "token_x_mint",
relations: ["lb_pair"]
},
{
name: "token_y_mint",
relations: ["lb_pair"]
},
{
name: "bin_array_lower",
writable: true
},
{
name: "bin_array_upper",
writable: true
},
{
name: "sender",
signer: true
},
{
name: "token_x_program",
address: "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"
},
{
name: "token_y_program",
address: "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"
},
{
name: "event_authority",
pda: {
seeds: [
{
kind: "const",
value: [
95,
95,
101,
118,
101,
110,
116,
95,
97,
117,
116,
104,
111,
114,
105,
116,
121
]
}
]
}
},
{
name: "program"
}
],
args: [
{
name: "from_bin_id",
type: "i32"
},
{
name: "to_bin_id",
type: "i32"
},
{
name: "bps_to_remove",
type: "u16"
}
]
},
{
name: "remove_liquidity_by_range2",
discriminator: [204, 2, 195, 145, 53, 145, 145, 205],
accounts: [
{
name: "position",
writable: true
},
{
name: "lb_pair",
writable: true,
relations: ["position", "bin_array_bitmap_extension"]
},
{
name: "bin_array_bitmap_extension",
writable: true,
optional: true
},
{
name: "user_token_x",
writable: true
},
{
name: "user_token_y",
writable: true
},
{
name: "reserve_x",
writable: true,
relations: ["lb_pair"]
},
{
name: "reserve_y",
writable: true,
relations: ["lb_pair"]
},
{
name: "token_x_mint",
relations: ["lb_pair"]
},
{
name: "token_y_mint",
relations: ["lb_pair"]
},
{
name: "sender",
signer: true
},
{
name: "token_x_program"
},
{
name: "token_y_program"
},
{
name: "memo_program",
address: "MemoSq4gqABAXKb96qnH8TysNcWxMyWCqXgDLGmfcHr"
},
{
name: "event_authority",
pda: {
seeds: [
{
kind: "const",
value: [
95,
95,
101,
118,
101,
110,
116,
95,
97,
117,
116,
104,
111,
114,
105,
116,
121
]
}
]
}
},
{
name: "program"
}
],
args: [
{
name: "from_bin_id",
type: "i32"
},
{
name: "to_bin_id",
type: "i32"
},
{
name: "bps_to_remove",
type: "u16"
},
{
name: "remaining_accounts_info",
type: {
defined: {
name: "RemainingAccountsInfo"
}
}
}
]
},
{
name: "set_activation_point",
discriminator: [91, 249, 15, 165, 26, 129, 254, 125],
accounts: [
{
name: "lb_pair",
writable: true
},
{
name: "signer",
signer: true
}
],
args: [
{
name: "activation_point",
type: "u64"
}
]
},
{
name: "set_pair_status",
discriminator: [67, 248, 231, 137, 154, 149, 217, 174],
accounts: [
{
name: "lb_pair",
writable: true
},
{
name: "operator"
},
{
name: "signer",
signer: true
}
],
args: [
{
name: "status",
type: "u8"
}
]
},
{
name: "set_pair_status_permissionless",
discriminator: [78, 59, 152, 211, 70, 183, 46, 208],
accounts: [
{
name: "lb_pair",
writable: true
},
{
name: "signer",
signer: true
}
],
args: [
{
name: "status",
type: "u8"
}
]
},
{
name: "set_permissionless_operation_bits",
discriminator: [84, 58, 203, 139, 163, 81, 190, 186],
accounts: [
{
name: "position",
writable: true
},
{
name: "owner",
signer: true,
relations: ["position"]
},
{
name: "event_authority",
pda: {
seeds: [
{
kind: "const",
value: [
95,
95,
101,
118,
101,
110,
116,
95,
97,
117,
116,
104,
111,
114,
105,
116,
121
]
}
]
}
},
{
name: "program"
}
],
args: [
{
name: "bits",
type: "u8"
}
]
},
{
name: "set_pre_activation_duration",
discriminator: [165, 61, 201, 244, 130, 159, 22, 100],
accounts: [
{
name: "lb_pair",
writable: true
},
{
name: "signer",
signer: true
}
],
args: [
{
name: "pre_activation_duration",
type: "u64"
}
]
},
{
name: "set_pre_activation_swap_address",
discriminator: [57, 139, 47, 123, 216, 80, 223, 10],
accounts: [
{
name: "lb_pair",
writable: true
},
{
name: "signer",
signer: true
}
],
args: [
{
name: "pre_activation_swap_address",
type: "pubkey"
}
]
},
{
name: "swap",
discriminator: [248, 198, 158, 145, 225, 117, 135, 200],
accounts: [
{
name: "lb_pair",
writable: true,
relations: ["bin_array_bitmap_extension"]
},
{
name: "bin_array_bitmap_extension",
writable: true,
optional: true
},
{
name: "reserve_x",
writable: true,
relations: ["lb_pair"]
},
{
name: "reserve_y",
writable: true,
relations: ["lb_pair"]
},
{
name: "user_token_in",
writable: true
},
{
name: "user_token_out",
writable: true
},
{
name: "token_x_mint",
relations: ["lb_pair"]
},
{
name: "token_y_mint",
relations: ["lb_pair"]
},
{
name: "oracle",
writable: true,
relations: ["lb_pair"]
},
{
name: "host_fee_in",
writable: true,
optional: true
},
{
name: "user",
signer: true
},
{
name: "token_x_program",
address: "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"
},
{
name: "token_y_program",
address: "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"
},
{
name: "event_authority",
pda: {
seeds: [
{
kind: "const",
value: [
95,
95,
101,
118,
101,
110,
116,
95,
97,
117,
116,
104,
111,
114,
105,
116,
121
]
}
]
}
},
{
name: "program"
}
],
args: [
{
name: "amount_in",
type: "u64"
},
{
name: "min_amount_out",
type: "u64"
}
]
},
{
name: "swap2",
discriminator: [65, 75, 63, 76, 235, 91, 91, 136],
accounts: [
{
name: "lb_pair",
writable: true,
relations: ["bin_array_bitmap_extension"]
},
{
name: "bin_array_bitmap_extension",
writable: true,
optional: true
},
{
name: "reserve_x",
writable: true,
relations: ["lb_pair"]
},
{
name: "reserve_y",
writable: true,
relations: ["lb_pair"]
},
{
name: "user_token_in",
writable: true
},
{
name: "user_token_out",
writable: true
},
{
name: "token_x_mint",
relations: ["lb_pair"]
},
{
name: "token_y_mint",
relations: ["lb_pair"]
},
{
name: "oracle",
writable: true,
relations: ["lb_pair"]
},
{
name: "host_fee_in",
writable: true,
optional: true
},
{
name: "user",
signer: true
},
{
name: "token_x_program"
},
{
name: "token_y_program"
},
{
name: "memo_program",
address: "MemoSq4gqABAXKb96qnH8TysNcWxMyWCqXgDLGmfcHr"
},
{
name: "event_authority",
pda: {
seeds: [
{
kind: "const",
value: [
95,
95,
101,
118,
101,
110,
116,
95,
97,
117,
116,
104,
111,
114,
105,
116,
121
]
}
]
}
},
{
name: "program"
}
],
args: [
{
name: "amount_in",
type: "u64"
},
{
name: "min_amount_out",
type: "u64"
},
{
name: "remaining_accounts_info",
type: {
defined: {
name: "RemainingAccountsInfo"
}
}
}
]
},
{
name: "swap_exact_out",
discriminator: [250, 73, 101, 33, 38, 207, 75, 184],
accounts: [
{
name: "lb_pair",
writable: true,
relations: ["bin_array_bitmap_extension"]
},
{
name: "bin_array_bitmap_extension",
writable: true,
optional: true
},
{
name: "reserve_x",
writable: true,
relations: ["lb_pair"]
},
{
name: "reserve_y",
writable: true,
relations: ["lb_pair"]
},
{
name: "user_token_in",
writable: true
},
{
name: "user_token_out",
writable: true
},
{
name: "token_x_mint",
relations: ["lb_pair"]
},
{
name: "token_y_mint",
relations: ["lb_pair"]
},
{
name: "oracle",
writable: true,
relations: ["lb_pair"]
},
{
name: "host_fee_in",
writable: true,
optional: true
},
{
name: "user",
signer: true
},
{
name: "token_x_program",
address: "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"
},
{
name: "token_y_program",
address: "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"
},
{
name: "event_authority",
pda: {
seeds: [
{
kind: "const",
value: [
95,
95,
101,
118,
101,
110,
116,
95,
97,
117,
116,
104,
111,
114,
105,
116,
121
]
}
]
}
},
{
name: "program"
}
],
args: [
{
name: "max_in_amount",
type: "u64"
},
{
name: "out_amount",
type: "u64"
}
]
},
{
name: "swap_exact_out2",
discriminator: [43, 215, 247, 132, 137, 60, 243, 81],
accounts: [
{
name: "lb_pair",
writable: true,
relations: ["bin_array_bitmap_extension"]
},
{
name: "bin_array_bitmap_extension",
writable: true,
optional: true
},
{
name: "reserve_x",
writable: true,
relations: ["lb_pair"]
},
{
name: "reserve_y",
writable: true,
relations: ["lb_pair"]
},
{
name: "user_token_in",
writable: true
},
{
name: "user_token_out",
writable: true
},
{
name: "token_x_mint",
relations: ["lb_pair"]
},
{
name: "token_y_mint",
relations: ["lb_pair"]
},
{
name: "oracle",
writable: true,
relations: ["lb_pair"]
},
{
name: "host_fee_in",
writable: true,
optional: true
},
{
name: "user",
signer: true
},
{
name: "token_x_program"
},
{
name: "token_y_program"
},
{
name: "memo_program",
address: "MemoSq4gqABAXKb96qnH8TysNcWxMyWCqXgDLGmfcHr"
},
{
name: "event_authority",
pda: {
seeds: [
{
kind: "const",
value: [
95,
95,
101,
118,
101,
110,
116,
95,
97,
117,
116,
104,
111,
114,
105,
116,
121
]
}
]
}
},
{
name: "program"
}
],
args: [
{
name: "max_in_amount",
type: "u64"
},
{
name: "out_amount",
type: "u64"
},
{
name: "remaining_accounts_info",
type: {
defined: {
name: "RemainingAccountsInfo"
}
}
}
]
},
{
name: "swap_with_price_impact",
discriminator: [56, 173, 230, 208, 173, 228, 156, 205],
accounts: [
{
name: "lb_pair",
writable: true,
relations: ["bin_array_bitmap_extension"]
},
{
name: "bin_array_bitmap_extension",
writable: true,
optional: true
},
{
name: "reserve_x",
writable: true,
relations: ["lb_pair"]
},
{
name: "reserve_y",
writable: true,
relations: ["lb_pair"]
},
{
name: "user_token_in",
writable: true
},
{
name: "user_token_out",
writable: true
},
{
name: "token_x_mint",
relations: ["lb_pair"]
},
{
name: "token_y_mint",
relations: ["lb_pair"]
},
{
name: "oracle",
writable: true,
relations: ["lb_pair"]
},
{
name: "host_fee_in",
writable: true,
optional: true
},
{
name: "user",
signer: true
},
{
name: "token_x_program",
address: "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"
},
{
name: "token_y_program",
address: "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"
},
{
name: "event_authority",
pda: {
seeds: [
{
kind: "const",
value: [
95,
95,
101,
118,
101,
110,
116,
95,
97,
117,
116,
104,
111,
114,
105,
116,
121
]
}
]
}
},
{
name: "program"
}
],
args: [
{
name: "amount_in",
type: "u64"
},
{
name: "active_id",
type: {
option: "i32"
}
},
{
name: "max_price_impact_bps",
type: "u16"
}
]
},
{
name: "swap_with_price_impact2",
discriminator: [74, 98, 192, 214, 177, 51, 75, 51],
accounts: [
{
name: "lb_pair",
writable: true,
relations: ["bin_array_bitmap_extension"]
},
{
name: "bin_array_bitmap_extension",
writable: true,
optional: true
},
{
name: "reserve_x",
writable: true,
relations: ["lb_pair"]
},
{
name: "reserve_y",
writable: true,
relations: ["lb_pair"]
},
{
name: "user_token_in",
writable: true
},
{
name: "user_token_out",
writable: true
},
{
name: "token_x_mint",
relations: ["lb_pair"]
},
{
name: "token_y_mint",
relations: ["lb_pair"]
},
{
name: "oracle",
writable: true,
relations: ["lb_pair"]
},
{
name: "host_fee_in",
writable: true,
optional: true
},
{
name: "user",
signer: true
},
{
name: "token_x_program"
},
{
name: "token_y_program"
},
{
name: "memo_program",
address: "MemoSq4gqABAXKb96qnH8TysNcWxMyWCqXgDLGmfcHr"
},
{
name: "event_authority",
pda: {
seeds: [
{
kind: "const",
value: [
95,
95,
101,
118,
101,
110,
116,
95,
97,
117,
116,
104,
111,
114,
105,
116,
121
]
}
]
}
},
{
name: "program"
}
],
args: [
{
name: "amount_in",
type: "u64"
},
{
name: "active_id",
type: {
option: "i32"
}
},
{
name: "max_price_impact_bps",
type: "u16"
},
{
name: "remaining_accounts_info",
type: {
defined: {
name: "RemainingAccountsInfo"
}
}
}
]
},
{
name: "update_base_fee_parameters",
discriminator: [75, 168, 223, 161, 16, 195, 3, 47],
accounts: [
{
name: "lb_pair",
writable: true
},
{
name: "operator"
},
{
name: "signer",
signer: true
},
{
name: "event_authority",
pda: {
seeds: [
{
kind: "const",
value: [
95,
95,
101,
118,
101,
110,
116,
95,
97,
117,
116,
104,
111,
114,
105,
116,
121
]
}
]
}
},
{
name: "program"
}
],
args: [
{
name: "fee_parameter",
type: {
defined: {
name: "BaseFeeParameter"
}
}
}
]
},
{
name: "update_dynamic_fee_parameters",
discriminator: [92, 161, 46, 246, 255, 189, 22, 22],
accounts: [
{
name: "lb_pair",
writable: true
},
{
name: "operator"
},
{
name: "signer",
signer: true
},
{
name: "event_authority",
pda: {
seeds: [
{
kind: "const",
value: [
95,
95,
101,
118,
101,
110,
116,
95,
97,
117,
116,
104,
111,
114,
105,
116,
121
]
}
]
}
},
{
name: "program"
}
],
args: [
{
name: "fee_parameter",
type: {
defined: {
name: "DynamicFeeParameter"
}
}
}
]
},
{
name: "update_fees_and_reward2",
discriminator: [32, 142, 184, 154, 103, 65, 184, 88],
accounts: [
{
name: "position",
writable: true
},
{
name: "lb_pair",
writable: true,
relations: ["position"]
},
{
name: "owner",
signer: true
}
],
args: [
{
name: "min_bin_id",
type: "i32"
},
{
name: "max_bin_id",
type: "i32"
}
]
},
{
name: "update_fees_and_rewards",
discriminator: [154, 230, 250, 13, 236, 209, 75, 223],
accounts: [
{
name: "position",
writable: true
},
{
name: "lb_pair",
writable: true,
relations: ["position", "bin_array_lower", "bin_array_upper"]
},
{
name: "bin_array_lower",
writable: true
},
{
name: "bin_array_upper",
writable: true
},
{
name: "owner",
signer: true
}
],
args: []
},
{
name: "update_position_operator",
discriminator: [202, 184, 103, 143, 180, 191, 116, 217],
accounts: [
{
name: "position",
writable: true
},
{
name: "owner",
signer: true,
relations: ["position"]
},
{
name: "event_authority",
pda: {
seeds: [
{
kind: "const",
value: [
95,
95,
101,
118,
101,
110,
116,
95,
97,
117,
116,
104,
111,
114,
105,
116,
121
]
}
]
}
},
{
name: "program"
}
],
args: [
{
name: "operator",
type: "pubkey"
}
]
},
{
name: "update_reward_duration",
discriminator: [138, 174, 196, 169, 213, 235, 254, 107],
accounts: [
{
name: "lb_pair",
writable: true,
relations: ["bin_array"]
},
{
name: "operator"
},
{
name: "signer",
signer: true
},
{
name: "bin_array",
writable: true
},
{
name: "event_authority",
pda: {
seeds: [
{
kind: "const",
value: [
95,
95,
101,
118,
101,
110,
116,
95,
97,
117,
116,
104,
111,
114,
105,
116,
121
]
}
]
}
},
{
name: "program"
}
],
args: [
{
name: "reward_index",
type: "u64"
},
{
name: "new_duration",
type: "u64"
}
]
},
{
name: "update_reward_funder",
discriminator: [211, 28, 48, 32, 215, 160, 35, 23],
accounts: [
{
name: "lb_pair",
writable: true
},
{
name: "operator"
},
{
name: "signer",
signer: true
},
{
name: "event_authority",
pda: {
seeds: [
{
kind: "const",
value: [
95,
95,
101,
118,
101,
110,
116,
95,
97,
117,
116,
104,
111,
114,
105,
116,
121
]
}
]
}
},
{
name: "program"
}
],
args: [
{
name: "reward_index",
type: "u64"
},
{
name: "new_funder",
type: "pubkey"
}
]
},
{
name: "withdraw_ineligible_reward",
discriminator: [148, 206, 42, 195, 247, 49, 103, 8],
accounts: [
{
name: "lb_pair",
writable: true,
relations: ["bin_array"]
},
{
name: "reward_vault",
writable: true
},
{
name: "reward_mint"
},
{
name: "funder_token_account",
writable: true
},
{
name: "funder",
signer: true
},
{
name: "bin_array",
writable: true
},
{
name: "token_program"
},
{
name: "memo_program",
address: "MemoSq4gqABAXKb96qnH8TysNcWxMyWCqXgDLGmfcHr"
},
{
name: "event_authority",
pda: {
seeds: [
{
kind: "const",
value: [
95,
95,
101,
118,
101,
110,
116,
95,
97,
117,
116,
104,
111,
114,
105,
116,
121
]
}
]
}
},
{
name: "program"
}
],
args: [
{
name: "reward_index",
type: "u64"
},
{
name: "remaining_accounts_info",
type: {
defined: {
name: "RemainingAccountsInfo"
}
}
}
]
},
{
name: "withdraw_protocol_fee",
discriminator: [158, 201, 158, 189, 33, 93, 162, 103],
accounts: [
{
name: "lb_pair",
writable: true
},
{
name: "reserve_x",
writable: true,
relations: ["lb_pair"]
},
{
name: "reserve_y",
writable: true,
relations: ["lb_pair"]
},
{
name: "token_x_mint",
relations: ["lb_pair"]
},
{
name: "token_y_mint",
relations: ["lb_pair"]
},
{
name: "receiver_token_x",
writable: true
},
{
name: "receiver_token_y",
writable: true
},
{
name: "operator"
},
{
name: "signer",
docs: ["operator"],
signer: true
},
{
name: "token_x_program"
},
{
name: "token_y_program"
}
],
args: [
{
name: "max_amount_x",
type: "u64"
},
{
name: "max_amount_y",
type: "u64"
},
{
name: "remaining_accounts_info",
type: {
defined: {
name: "RemainingAccountsInfo"
}
}
}
]
},
{
name: "zap_protocol_fee",
discriminator: [213, 155, 187, 34, 56, 182, 91, 240],
accounts: [
{
name: "lb_pair",
writable: true
},
{
name: "reserve",
writable: true
},
{
name: "token_mint"
},
{
name: "receiver_token",
writable: true
},
{
name: "operator"
},
{
name: "signer",
docs: ["operator"],
signer: true
},
{
name: "token_program"
},
{
name: "sysvar_instructions",
address: "Sysvar1nstructions1111111111111111111111111"
}
],
args: [
{
name: "max_amount",
type: "u64"
},
{
name: "remaining_accounts_info",
type: {
defined: {
name: "RemainingAccountsInfo"
}
}
}
]
}
],
accounts: [
{
name: "BinArray",
discriminator: [92, 142, 92, 220, 5, 148, 70, 181]
},
{
name: "BinArrayBitmapExtension",
discriminator: [80, 111, 124, 113, 55, 237, 18, 5]
},
{
name: "ClaimFeeOperator",
discriminator: [166, 48, 134, 86, 34, 200, 188, 150]
},
{
name: "DummyZcAccount",
discriminator: [94, 107, 238, 80, 208, 48, 180, 8]
},
{
name: "LbPair",
discriminator: [33, 11, 49, 98, 181, 101, 177, 13]
},
{
name: "LimitOrder",
discriminator: [137, 183, 212, 91, 115, 29, 141, 227]
},
{
name: "Operator",
discriminator: [219, 31, 188, 145, 69, 139, 204, 117]
},
{
name: "Oracle",
discriminator: [139, 194, 131, 179, 140, 179, 229, 244]
},
{
name: "PositionV2",
discriminator: [117, 176, 212, 199, 245, 180, 133, 182]
},
{
name: "PresetParameter",
discriminator: [242, 62, 244, 34, 181, 112, 58, 170]
},
{
name: "PresetParameter2",
discriminator: [171, 236, 148, 115, 162, 113, 222, 174]
},
{
name: "TokenBadge",
discriminator: [116, 219, 204, 229, 249, 116, 255, 150]
}
],
events: [
{
name: "AddLiquidity",
discriminator: [31, 94, 125, 90, 227, 52, 61, 186]
},
{
name: "CancelLimitOrderEvt",
discriminator: [131, 234, 194, 133, 9, 14, 189, 209]
},
{
name: "ClaimFee",
discriminator: [75, 122, 154, 48, 140, 74, 123, 163]
},
{
name: "ClaimFee2",
discriminator: [232, 171, 242, 97, 58, 77, 35, 45]
},
{
name: "ClaimReward",
discriminator: [148, 116, 134, 204, 22, 171, 85, 95]
},
{
name: "ClaimReward2",
discriminator: [27, 143, 244, 33, 80, 43, 110, 146]
},
{
name: "CloseLimitOrderEvt",
discriminator: [142, 135, 8, 76, 92, 63, 118, 83]
},
{
name: "CompositionFee",
discriminator: [128, 151, 123, 106, 17, 102, 113, 142]
},
{
name: "DecreasePositionLength",
discriminator: [52, 118, 235, 85, 172, 169, 15, 128]
},
{
name: "DynamicFeeParameterUpdate",
discriminator: [88, 88, 178, 135, 194, 146, 91, 243]
},
{
name: "FeeParameterUpdate",
discriminator: [48, 76, 241, 117, 144, 215, 242, 44]
},
{
name: "FundReward",
discriminator: [246, 228, 58, 130, 145, 170, 79, 204]
},
{
name: "GoToABin",
discriminator: [59, 138, 76, 68, 138, 131, 176, 67]
},
{
name: "IncreaseObservation",
discriminator: [99, 249, 17, 121, 166, 156, 207, 215]
},
{
name: "IncreasePositionLength",
discriminator: [157, 239, 42, 204, 30, 56, 223, 46]
},
{
name: "InitializeReward",
discriminator: [211, 153, 88, 62, 149, 60, 177, 70]
},
{
name: "LbPairCreate",
discriminator: [185, 74, 252, 125, 27, 215, 188, 111]
},
{
name: "PlaceLimitOrderEvt",
discriminator: [43, 79, 27, 169, 244, 28, 225, 63]
},
{
name: "PositionClose",
discriminator: [255, 196, 16, 107, 28, 202, 53, 128]
},
{
name: "PositionCreate",
discriminator: [144, 142, 252, 84, 157, 53, 37, 121]
},
{
name: "Rebalancing",
discriminator: [0, 109, 117, 179, 61, 91, 199, 200]
},
{
name: "RemoveLiquidity",
discriminator: [116, 244, 97, 232, 103, 31, 152, 58]
},
{
name: "SetPositionPermissionlessOperationBitsEvt",
discriminator: [195, 229, 147, 245, 29, 125, 48, 168]
},
{
name: "Swap",
discriminator: [81, 108, 227, 190, 205, 208, 10, 196]
},
{
name: "Swap2Evt",
discriminator: [46, 116, 82, 215, 148, 27, 84, 77]
},
{
name: "UpdatePositionLockReleasePoint",
discriminator: [133, 214, 66, 224, 64, 12, 7, 191]
},
{
name: "UpdatePositionOperator",
discriminator: [39, 115, 48, 204, 246, 47, 66, 57]
},
{
name: "UpdateRewardDuration",
discriminator: [223, 245, 224, 153, 49, 29, 163, 172]
},
{
name: "UpdateRewardFunder",
discriminator: [224, 178, 174, 74, 252, 165, 85, 180]
},
{
name: "WithdrawIneligibleReward",
discriminator: [231, 189, 65, 149, 102, 215, 154, 244]
}
],
errors: [
{
code: 6e3,
name: "InvalidStartBinIndex",
msg: "Invalid start bin index"
},
{
code: 6001,
name: "InvalidBinId",
msg: "Invalid bin id"
},
{
code: 6002,
name: "InvalidInput",
msg: "Invalid input data"
},
{
code: 6003,
name: "ExceededAmountSlippageTolerance",
msg: "Exceeded amount slippage tolerance"
},
{
code: 6004,
name: "ExceededBinSlippageTolerance",
msg: "Exceeded bin slippage tolerance"
},
{
code: 6005,
name: "CompositionFactorFlawed",
msg: "Composition factor flawed"
},
{
code: 6006,
name: "NonPresetBinStep",
msg: "Non preset bin step"
},
{
code: 6007,
name: "ZeroLiquidity",
msg: "Zero liquidity"
},
{
code: 6008,
name: "InvalidPosition",
msg: "Invalid position"
},
{
code: 6009,
name: "BinArrayNotFound",
msg: "Bin array not found"
},
{
code: 6010,
name: "InvalidTokenMint",
msg: "Invalid token mint"
},
{
code: 6011,
name: "InvalidAccountForSingleDeposit",
msg: "Invalid account for single deposit"
},
{
code: 6012,
name: "PairInsufficientLiquidity",
msg: "Pair insufficient liquidity"
},
{
code: 6013,
name: "InvalidFeeOwner",
msg: "Invalid fee owner"
},
{
code: 6014,
name: "InvalidFeeWithdrawAmount",
msg: "Invalid fee withdraw amount"
},
{
code: 6015,
name: "InvalidAdmin",
msg: "Invalid admin"
},
{
code: 6016,
name: "IdenticalFeeOwner",
msg: "Identical fee owner"
},
{
code: 6017,
name: "InvalidBps",
msg: "Invalid basis point"
},
{
code: 6018,
name: "MathOverflow",
msg: "Math operation overflow"
},
{
code: 6019,
name: "TypeCastFailed",
msg: "Type cast error"
},
{
code: 6020,
name: "InvalidRewardIndex",
msg: "Invalid reward index"
},
{
code: 6021,
name: "InvalidRewardDuration",
msg: "Invalid reward duration"
},
{
code: 6022,
name: "RewardInitialized",
msg: "Reward already initialized"
},
{
code: 6023,
name: "RewardUninitialized",
msg: "Reward not initialized"
},
{
code: 6024,
name: "IdenticalFunder",
msg: "Identical funder"
},
{
code: 6025,
name: "RewardCampaignInProgress",
msg: "Reward campaign in progress"
},
{
code: 6026,
name: "IdenticalRewardDuration",
msg: "Reward duration is the same"
},
{
code: 6027,
name: "InvalidBinArray",
msg: "Invalid bin array"
},
{
code: 6028,
name: "NonContinuousBinArrays",
msg: "Bin arrays must be continuous"
},
{
code: 6029,
name: "InvalidRewardVault",
msg: "Invalid reward vault"
},
{
code: 6030,
name: "NonEmptyPosition",
msg: "Position is not empty"
},
{
code: 6031,
name: "UnauthorizedAccess",
msg: "Unauthorized access"
},
{
code: 6032,
name: "InvalidFeeParameter",
msg: "Invalid fee parameter"
},
{
code: 6033,
name: "MissingOracle",
msg: "Missing oracle account"
},
{
code: 6034,
name: "InsufficientSample",
msg: "Insufficient observation sample"
},
{
code: 6035,
name: "InvalidLookupTimestamp",
msg: "Invalid lookup timestamp"
},
{
code: 6036,
name: "BitmapExtensionAccountIsNotProvided",
msg: "Bitmap extension account is not provided"
},
{
code: 6037,
name: "CannotFindNonZeroLiquidityBinArrayId",
msg: "Cannot find non-zero liquidity binArrayId"
},
{
code: 6038,
name: "BinIdOutOfBound",
msg: "Bin id out of bound"
},
{
code: 6039,
name: "InsufficientOutAmount",
msg: "Insufficient amount in for minimum out"
},
{
code: 6040,
name: "InvalidPositionWidth",
msg: "Invalid position width"
},
{
code: 6041,
name: "ExcessiveFeeUpdate",
msg: "Excessive fee update"
},
{
code: 6042,
name: "PoolDisabled",
msg: "Pool disabled"
},
{
code: 6043,
name: "InvalidPoolType",
msg: "Invalid pool type"
},
{
code: 6044,
name: "ExceedMaxWhitelist",
msg: "Whitelist for wallet is full"
},
{
code: 6045,
name: "InvalidIndex",
msg: "Invalid index"
},
{
code: 6046,
name: "RewardNotEnded",
msg: "Reward not ended"
},
{
code: 6047,
name: "MustWithdrawnIneligibleReward",
msg: "Must withdraw ineligible reward"
},
{
code: 6048,
name: "UnauthorizedAddress",
msg: "Unauthorized address"
},
{
code: 6049,
name: "OperatorsAreTheSame",
msg: "Cannot update because operators are the same"
},
{
code: 6050,
name: "WithdrawToWrongTokenAccount",
msg: "Withdraw to wrong token account"
},
{
code: 6051,
name: "WrongRentReceiver",
msg: "Wrong rent receiver"
},
{
code: 6052,
name: "AlreadyPassActivationPoint",
msg: "Already activated"
},
{
code: 6053,
name: "ExceedMaxSwappedAmount",
msg: "Swapped amount is exceeded max swapped amount"
},
{
code: 6054,
name: "InvalidStrategyParameters",
msg: "Invalid strategy parameters"
},
{
code: 6055,
name: "LiquidityLocked",
msg: "Liquidity locked"
},
{
code: 6056,
name: "BinRangeIsNotEmpty",
msg: "Bin range is not empty"
},
{
code: 6057,
name: "NotExactAmountOut",
msg: "Amount out is not matched with exact amount out"
},
{
code: 6058,
name: "InvalidActivationType",
msg: "Invalid activation type"
},
{
code: 6059,
name: "InvalidActivationDuration",
msg: "Invalid activation duration"
},
{
code: 6060,
name: "MissingTokenAmountAsTokenLaunchProof",
msg: "Missing token amount as token launch owner proof"
},
{
code: 6061,
name: "InvalidQuoteToken",
msg: "Quote token must be SOL or USDC"
},
{
code: 6062,
name: "InvalidBinStep",
msg: "Invalid bin step"
},
{
code: 6063,
name: "InvalidBaseFee",
msg: "Invalid base fee"
},
{
code: 6064,
name: "InvalidPreActivationDuration",
msg: "Invalid pre-activation duration"
},
{
code: 6065,
name: "AlreadyPassPreActivationSwapPoint",
msg: "Already pass pre-activation swap point"
},
{
code: 6066,
name: "InvalidStatus",
msg: "Invalid status"
},
{
code: 6067,
name: "ExceededMaxOracleLength",
msg: "Exceed max oracle length"
},
{
code: 6068,
name: "InvalidMinimumLiquidity",
msg: "Invalid minimum liquidity"
},
{
code: 6069,
name: "NotSupportMint",
msg: "Not support token_2022 mint extension"
},
{
code: 6070,
name: "UnsupportedMintExtension",
msg: "Unsupported mint extension"
},
{
code: 6071,
name: "UnsupportNativeMintToken2022",
msg: "Unsupported native mint token2022"
},
{
code: 6072,
name: "UnmatchTokenMint",
msg: "Unmatch token mint"
},
{
code: 6073,
name: "UnsupportedTokenMint",
msg: "Unsupported token mint"
},
{
code: 6074,
name: "InsufficientRemainingAccounts",
msg: "Insufficient remaining accounts"
},
{
code: 6075,
name: "InvalidRemainingAccountSlice",
msg: "Invalid remaining account slice"
},
{
code: 6076,
name: "DuplicatedRemainingAccountTypes",
msg: "Duplicated remaining account types"
},
{
code: 6077,
name: "MissingRemainingAccountForTransferHook",
msg: "Missing remaining account for transfer hook"
},
{
code: 6078,
name: "NoTransferHookProgram",
msg: "Remaining account was passed for transfer hook but there's no hook program"
},
{
code: 6079,
name: "ZeroFundedAmount",
msg: "Zero funded amount"
},
{
code: 6080,
name: "InvalidSide",
msg: "Invalid side"
},
{
code: 6081,
name: "InvalidResizeLength",
msg: "Invalid resize length"
},
{
code: 6082,
name: "NotSupportAtTheMoment",
msg: "Not support at the moment"
},
{
code: 6083,
name: "InvalidRebalanceParameters",
msg: "Invalid rebalance parameters"
},
{
code: 6084,
name: "InvalidRewardAccounts",
msg: "Invalid reward accounts"
},
{
code: 6085,
name: "UndeterminedError",
msg: "Undetermined error"
},
{
code: 6086,
name: "ReallocExceedMaxLengthPerInstruction",
msg: "Realloc exceed max length per instruction"
},
{
code: 6087,
name: "InvalidBaseFeeMantissa",
msg: "Mantissa cannot more than two significant digits"
},
{
code: 6088,
name: "InvalidPositionOwner",
msg: "Invalid position owner"
},
{
code: 6089,
name: "InvalidPoolAddress",
msg: "Invalid pool address"
},
{
code: 6090,
name: "InvalidTokenBadgeType",
msg: "Invalid token badge type"
},
{
code: 6091,
name: "InvalidTransferHookAuthority",
msg: "Invalid transfer hook authority"
},
{
code: 6092,
name: "AmountXIsNegative",
msg: "Amount x is negative"
},
{
code: 6093,
name: "AmountYIsNegative",
msg: "Amount y is negative"
},
{
code: 6094,
name: "InvalidPoolCreator",
msg: "Invalid pool creator"
},
{
code: 6095,
name: "InvalidFunctionType",
msg: "Invalid function type"
},
{
code: 6096,
name: "InvalidPermission",
msg: "Invalid permission"
},
{
code: 6097,
name: "IncorrectATA",
msg: "Incorrect ATA"
},
{
code: 6098,
name: "InvalidWithdrawProtocolFeeZapAccounts",
msg: "Invalid withdraw protocol fee zap accounts"
},
{
code: 6099,
name: "MintRestrictedFromZap",
msg: "SOL,USDC protocol fee cannot be withdrawn via zap"
},
{
code: 6100,
name: "CpiDisabled",
msg: "CPI disabled"
},
{
code: 6101,
name: "MissingZapOutInstruction",
msg: "Missing zap out instruction"
},
{
code: 6102,
name: "InvalidZapAccounts",
msg: "Invalid zap accounts"
},
{
code: 6103,
name: "InvalidZapOutParameters",
msg: "Invalid zap out parameters"
},
{
code: 6104,
name: "InsufficientInAmount",
msg: "Insufficient in amount"
},
{
code: 6105,
name: "InvalidPlaceLimitOrderParameters",
msg: "Invalid place limit order parameters"
},
{
code: 6106,
name: "InvalidLimitOrderOwner",
msg: "Invalid limit order owner"
},
{
code: 6107,
name: "InvalidCancelLimitOrderParameters",
msg: "Invalid cancel limit order parameters"
},
{
code: 6108,
name: "CannotFindLimitOrderByBinId",
msg: "Cannot find limit order by bin id"
},
{
code: 6109,
name: "CancelNonEmptyLimitOrder",
msg: "Cannot cancel non-empty limit order"
},
{
code: 6110,
name: "InvalidCollectFeeMode",
msg: "Invalid collect fee mode"
}
],
types: [
{
name: "AccountsType",
type: {
kind: "enum",
variants: [
{
name: "TransferHookX"
},
{
name: "TransferHookY"
},
{
name: "TransferHookReward"
},
{
name: "TransferHookMultiReward",
fields: ["u8"]
},
{
name: "TransferHookReferral"
}
]
}
},
{
name: "ActivationType",
docs: ["Type of the activation"],
repr: {
kind: "rust"
},
type: {
kind: "enum",
variants: [
{
name: "Slot"
},
{
name: "Timestamp"
}
]
}
},
{
name: "AddLiquidity",
type: {
kind: "struct",
fields: [
{
name: "lb_pair",
type: "pubkey"
},
{
name: "from",
type: "pubkey"
},
{
name: "position",
type: "pubkey"
},
{
name: "amounts",
type: {
array: ["u64", 2]
}
},
{
name: "active_bin_id",
type: "i32"
}
]
}
},
{
name: "AddLiquidityParams",
type: {
kind: "struct",
fields: [
{
name: "min_delta_id",
type: "i32"
},
{
name: "max_delta_id",
type: "i32"
},
{
name: "x0",
type: "u64"
},
{
name: "y0",
type: "u64"
},
{
name: "delta_x",
type: "u64"
},
{
name: "delta_y",
type: "u64"
},
{
name: "bit_flag",
type: "u8"
},
{
name: "favor_x_in_active_id",
type: "bool"
},
{
name: "padding",
type: {
array: ["u8", 16]
}
}
]
}
},
{
name: "AddLiquiditySingleSidePreciseParameter",
type: {
kind: "struct",
fields: [
{
name: "bins",
type: {
vec: {
defined: {
name: "CompressedBinDepositAmount"
}
}
}
},
{
name: "decompress_multiplier",
type: "u64"
}
]
}
},
{
name: "AddLiquiditySingleSidePreciseParameter2",
type: {
kind: "struct",
fields: [
{
name: "bins",
type: {
vec: {
defined: {
name: "CompressedBinDepositAmount"
}
}
}
},
{
name: "decompress_multiplier",
type: "u64"
},
{
name: "max_amount",
type: "u64"
}
]
}
},
{
name: "BaseFeeParameter",
type: {
kind: "struct",
fields: [
{
name: "protocol_share",
docs: [
"Portion of swap fees retained by the protocol by controlling protocol_share parameter. protocol_swap_fee = protocol_share * total_swap_fee"
],
type: "u16"
},
{
name: "base_factor",
docs: ["Base factor for base fee rate"],
type: "u16"
},
{
name: "base_fee_power_factor",
docs: ["Base fee power factor"],
type: "u8"
}
]
}
},
{
name: "Bin",
serialization: "bytemuck",
repr: {
kind: "c"
},
type: {
kind: "struct",
fields: [
{
name: "amount_x",
docs: [
"Amount of token X in the bin for market making. This already excluded protocol fees."
],
type: "u64"
},
{
name: "amount_y",
docs: [
"Amount of token Y in the bin for market making. This already excluded protocol fees."
],
type: "u64"
},
{
name: "price",
docs: ["Bin price"],
type: "u128"
},
{
name: "liquidity_supply",
docs: ["Bin MM liquidity supply."],
type: "u128"
},
{
name: "fulfilled_order_amount_x",
docs: ["Total fulfilled order amount x"],
type: "u64"
},
{
name: "fulfilled_order_amount_y",
docs: ["Total fulfilled order amount y"],
type: "u64"
},
{
name: "limit_order_fee_ask_side",
docs: ["Limit order fee collected by ask side orders"],
type: "u64"
},
{
name: "limit_order_fee_bid_side",
docs: ["Limit order fee collected by bid side orders"],
type: "u64"
},
{
name: "fee_amount_x_per_token_stored",
docs: ["Swap fee amount of token X per liquidity deposited."],
type: "u128"
},
{
name: "fee_amount_y_per_token_stored",
docs: ["Swap fee amount of token Y per liquidity deposited."],
type: "u128"
},
{
name: "open_order_amount",
docs: ["Pending open limit orders amount in the bin."],
type: "u64"
},
{
name: "total_processing_order_amount",
docs: ["Total processing order amount"],
type: "u64"
},
{
name: "processed_order_remaining_amount",
docs: [
"Remaining in processing open limit orders amount in the bin."
],
type: "u64"
},
{
name: "order_age",
docs: ["Age"],
type: "u32"
},
{
name: "limit_order_ask_side",
docs: ["limit order flag"],
type: "u8"
},
{
name: "_padding_1",
docs: ["padding"],
type: {
array: ["u8", 3]
}
}
]
}
},
{
name: "BinArray",
docs: [
"An account to contain a range of bin. For example: Bin 100 <-> 200.",
"For example:",
"BinArray index: 0 contains bin 0 <-> 599",
"index: 2 contains bin 600 <-> 1199, ..."
],
serialization: "bytemuck",
repr: {
kind: "c"
},
type: {
kind: "struct",
fields: [
{
name: "index",
type: "i64"
},
{
name: "version",
type: "u8"
},
{
name: "_padding_1",
type: {
array: ["u8", 7]
}
},
{
name: "lb_pair",
type: "pubkey"
},
{
name: "bins",
type: {
array: [
{
defined: {
name: "Bin"
}
},
70
]
}
}
]
}
},
{
name: "BinArrayBitmapExtension",
serialization: "bytemuck",
repr: {
kind: "c"
},
type: {
kind: "struct",
fields: [
{
name: "lb_pair",
type: "pubkey"
},
{
name: "positive_bin_array_bitmap",
docs: [
"Packed initialized bin array state for start_bin_index is positive"
],
type: {
array: [
{
array: ["u64", 8]
},
12
]
}
},
{
name: "negative_bin_array_bitmap",
docs: [
"Packed initialized bin array state for start_bin_index is negative"
],
type: {
array: [
{
array: ["u64", 8]
},
12
]
}
}
]
}
},
{
name: "BinLimitOrderAmount",
type: {
kind: "struct",
fields: [
{
name: "id",
type: "i32"
},
{
name: "amount",
type: "u64"
}
]
}
},
{
name: "BinLiquidityDistribution",
type: {
kind: "struct",
fields: [
{
name: "bin_id",
docs: ["Define the bin ID wish to deposit to."],
type: "i32"
},
{
name: "distribution_x",
docs: [
"DistributionX (or distributionY) is the percentages of amountX (or amountY) you want to add to each bin."
],
type: "u16"
},
{
name: "distribution_y",
docs: [
"DistributionX (or distributionY) is the percentages of amountX (or amountY) you want to add to each bin."
],
type: "u16"
}
]
}
},
{
name: "BinLiquidityDistributionByWeight",
type: {
kind: "struct",
fields: [
{
name: "bin_id",
docs: ["Define the bin ID wish to deposit to."],
type: "i32"
},
{
name: "weight",
docs: ["weight of liquidity distributed for this bin id"],
type: "u16"
}
]
}
},
{
name: "BinLiquidityReduction",
type: {
kind: "struct",
fields: [
{
name: "bin_id",
type: "i32"
},
{
name: "bps_to_remove",
type: "u16"
}
]
}
},
{
name: "CancelLimitOrderEvt",
type: {
kind: "struct",
fields: [
{
name: "lb_pair",
type: "pubkey"
},
{
name: "from",
type: "pubkey"
},
{
name: "limit_order",
type: "pubkey"
},
{
name: "amounts",
type: {
array: ["u64", 2]
}
},
{
name: "active_id",
type: "i32"
},
{
name: "bins",
type: {
vec: "i32"
}
}
]
}
},
{
name: "ClaimFee",
type: {
kind: "struct",
fields: [
{
name: "lb_pair",
type: "pubkey"
},
{
name: "position",
type: "pubkey"
},
{
name: "owner",
type: "pubkey"
},
{
name: "fee_x",
type: "u64"
},
{
name: "fee_y",
type: "u64"
}
]
}
},
{
name: "ClaimFee2",
type: {
kind: "struct",
fields: [
{
name: "lb_pair",
type: "pubkey"
},
{
name: "position",
type: "pubkey"
},
{
name: "owner",
type: "pubkey"
},
{
name: "fee_x",
type: "u64"
},
{
name: "fee_y",
type: "u64"
},
{
name: "active_bin_id",
type: "i32"
}
]
}
},
{
name: "ClaimFeeOperator",
docs: ["Parameter that set by the protocol"],
serialization: "bytemuck",
repr: {
kind: "c"
},
type: {
kind: "struct",
fields: [
{
name: "operator",
docs: ["operator"],
type: "pubkey"
},
{
name: "_padding",
docs: ["Reserve"],
type: {
array: ["u8", 128]
}
}
]
}
},
{
name: "ClaimReward",
type: {
kind: "struct",
fields: [
{
name: "lb_pair",
type: "pubkey"
},
{
name: "position",
type: "pubkey"
},
{
name: "owner",
type: "pubkey"
},
{
name: "reward_index",
type: "u64"
},
{
name: "total_reward",
type: "u64"
}
]
}
},
{
name: "ClaimReward2",
type: {
kind: "struct",
fields: [
{
name: "lb_pair",
type: "pubkey"
},
{
name: "position",
type: "pubkey"
},
{
name: "owner",
type: "pubkey"
},
{
name: "reward_index",
type: "u64"
},
{
name: "total_reward",
type: "u64"
},
{
name: "active_bin_id",
type: "i32"
}
]
}
},
{
name: "CloseLimitOrderEvt",
type: {
kind: "struct",
fields: [
{
name: "lb_pair",
type: "pubkey"
},
{
name: "owner",
type: "pubkey"
},
{
name: "limit_order",
type: "pubkey"
}
]
}
},
{
name: "CompositionFee",
type: {
kind: "struct",
fields: [
{
name: "from",
type: "pubkey"
},
{
name: "bin_id",
type: "i16"
},
{
name: "token_x_fee_amount",
type: "u64"
},
{
name: "token_y_fee_amount",
type: "u64"
},
{
name: "protocol_token_x_fee_amount",
type: "u64"
},
{
name: "protocol_token_y_fee_amount",
type: "u64"
}
]
}
},
{
name: "CompressedBinDepositAmount",
type: {
kind: "struct",
fields: [
{
name: "bin_id",
type: "i32"
},
{
name: "amount",
type: "u32"
}
]
}
},
{
name: "CustomizableParams",
type: {
kind: "struct",
fields: [
{
name: "active_id",
docs: ["Pool price"],
type: "i32"
},
{
name: "bin_step",
docs: ["Bin step"],
type: "u16"
},
{
name: "base_factor",
docs: ["Base factor"],
type: "u16"
},
{
name: "activation_type",
docs: [
"Activation type. 0 = Slot, 1 = Time. Check ActivationType enum"
],
type: "u8"
},
{
name: "has_alpha_vault",
docs: ["Whether the pool has an alpha vault"],
type: "bool"
},
{
name: "activation_point",
docs: ["Decide when does the pool start trade. None = Now"],
type: {
option: "u64"
}
},
{
name: "creator_pool_on_off_control",
docs: [
"Pool creator have permission to enable/disable pool with restricted program validation. Only applicable for customizable permissionless pool."
],
type: "bool"
},
{
name: "base_fee_power_factor",
docs: ["Base fee power factor"],
type: "u8"
},
{
name: "concrete_function_type",
docs: ["Concrete function type"],
type: "u8"
},
{
name: "collect_fee_mode",
docs: ["Collect fee mode"],
type: "u8"
},
{
name: "padding",
docs: ["Padding, for future use"],
type: {
array: ["u8", 60]
}
}
]
}
},
{
name: "DecreasePositionLength",
type: {
kind: "struct",
fields: [
{
name: "lb_pair",
type: "pubkey"
},
{
name: "position",
type: "pubkey"
},
{
name: "owner",
type: "pubkey"
},
{
name: "length_to_remove",
type: "u16"
},
{
name: "side",
type: "u8"
}
]
}
},
{
name: "DummyIx",
type: {
kind: "struct",
fields: [
{
name: "_pair_status",
type: {
defined: {
name: "PairStatus"
}
}
},
{
name: "_pair_type",
type: {
defined: {
name: "PairType"
}
}
},
{
name: "_activation_type",
type: {
defined: {
name: "ActivationType"
}
}
},
{
name: "_token_program_flag",
type: {
defined: {
name: "TokenProgramFlags"
}
}
},
{
name: "_resize_side",
type: {
defined: {
name: "ResizeSide"
}
}
},
{
name: "_rounding",
type: {
defined: {
name: "Rounding"
}
}
}
]
}
},
{
name: "DummyZcAccount",
serialization: "bytemuck",
repr: {
kind: "c"
},
type: {
kind: "struct",
fields: [
{
name: "position_bin_data",
type: {
defined: {
name: "PositionBinData"
}
}
},
{
name: "limit_order_bin_data",
type: {
defined: {
name: "LimitOrderBinData"
}
}
}
]
}
},
{
name: "DynamicFeeParameter",
type: {
kind: "struct",
fields: [
{
name: "filter_period",
docs: [
"Filter period determine high frequency trading time window."
],
type: "u16"
},
{
name: "decay_period",
docs: [
"Decay period determine when the volatile fee start decay / decrease."
],
type: "u16"
},
{
name: "reduction_factor",
docs: [
"Reduction factor controls the volatile fee rate decrement rate."
],
type: "u16"
},
{
name: "variable_fee_control",
docs: [
"Used to scale the variable fee component depending on the dynamic of the market"
],
type: "u32"
},
{
name: "max_volatility_accumulator",
docs: [
"Maximum number of bin crossed can be accumulated. Used to cap volatile fee rate."
],
type: "u32"
}
]
}
},
{
name: "DynamicFeeParameterUpdate",
type: {
kind: "struct",
fields: [
{
name: "lb_pair",
type: "pubkey"
},
{
name: "filter_period",
docs: [
"Filter period determine high frequency trading time window."
],
type: "u16"
},
{
name: "decay_period",
docs: [
"Decay period determine when the volatile fee start decay / decrease."
],
type: "u16"
},
{
name: "reduction_factor",
docs: [
"Reduction factor controls the volatile fee rate decrement rate."
],
type: "u16"
},
{
name: "variable_fee_control",
docs: [
"Used to scale the variable fee component depending on the dynamic of the market"
],
type: "u32"
},
{
name: "max_volatility_accumulator",
docs: [
"Maximum number of bin crossed can be accumulated. Used to cap volatile fee rate."
],
type: "u32"
}
]
}
},
{
name: "FeeInfo",
serialization: "bytemuck",
repr: {
kind: "c"
},
type: {
kind: "struct",
fields: [
{
name: "fee_x_per_token_complete",
type: "u128"
},
{
name: "fee_y_per_token_complete",
type: "u128"
},
{
name: "fee_x_pending",
type: "u64"
},
{
name: "fee_y_pending",
type: "u64"
}
]
}
},
{
name: "FeeParameterUpdate",
type: {
kind: "struct",
fields: [
{
name: "lb_pair",
type: "pubkey"
},
{
name: "protocol_share",
type: "u16"
},
{
name: "base_factor",
type: "u16"
},
{
name: "base_fee_power_factor",
type: "u8"
}
]
}
},
{
name: "FundReward",
type: {
kind: "struct",
fields: [
{
name: "lb_pair",
type: "pubkey"
},
{
name: "funder",
type: "pubkey"
},
{
name: "reward_index",
type: "u64"
},
{
name: "amount",
type: "u64"
}
]
}
},
{
name: "GoToABin",
type: {
kind: "struct",
fields: [
{
name: "lb_pair",
type: "pubkey"
},
{
name: "from_bin_id",
type: "i32"
},
{
name: "to_bin_id",
type: "i32"
}
]
}
},
{
name: "IncreaseObservation",
type: {
kind: "struct",
fields: [
{
name: "oracle",
type: "pubkey"
},
{
name: "new_observation_length",
type: "u64"
}
]
}
},
{
name: "IncreasePositionLength",
type: {
kind: "struct",
fields: [
{
name: "lb_pair",
type: "pubkey"
},
{
name: "position",
type: "pubkey"
},
{
name: "owner",
type: "pubkey"
},
{
name: "length_to_add",
type: "u16"
},
{
name: "side",
type: "u8"
}
]
}
},
{
name: "InitPermissionPairIx",
type: {
kind: "struct",
fields: [
{
name: "active_id",
type: "i32"
},
{
name: "bin_step",
type: "u16"
},
{
name: "base_factor",
type: "u16"
},
{
name: "base_fee_power_factor",
type: "u8"
},
{
name: "activation_type",
type: "u8"
},
{
name: "padding0",
type: "u16"
},
{
name: "concrete_function_type",
type: "u8"
},
{
name: "collect_fee_mode",
type: "u8"
}
]
}
},
{
name: "InitPresetParametersIx",
type: {
kind: "struct",
fields: [
{
name: "index",
type: "u16"
},
{
name: "bin_step",
docs: ["Bin step. Represent the price increment / decrement."],
type: "u16"
},
{
name: "base_factor",
docs: [
"Used for base fee calculation. base_fee_rate = base_factor * bin_step * 10 * 10^base_fee_power_factor"
],
type: "u16"
},
{
name: "filter_period",
docs: [
"Filter period determine high frequency trading time window."
],
type: "u16"
},
{
name: "decay_period",
docs: [
"Decay period determine when the volatile fee start decay / decrease."
],
type: "u16"
},
{
name: "reduction_factor",
docs: [
"Reduction factor controls the volatile fee rate decrement rate."
],
type: "u16"
},
{
name: "variable_fee_control",
docs: [
"Used to scale the variable fee component depending on the dynamic of the market"
],
type: "u32"
},
{
name: "max_volatility_accumulator",
docs: [
"Maximum number of bin crossed can be accumulated. Used to cap volatile fee rate."
],
type: "u32"
},
{
name: "protocol_share",
docs: [
"Portion of swap fees retained by the protocol by controlling protocol_share parameter. protocol_swap_fee = protocol_share * total_swap_fee"
],
type: "u16"
},
{
name: "base_fee_power_factor",
docs: ["Base fee power factor"],
type: "u8"
},
{
name: "concrete_function_type",
docs: ["function type"],
type: "u8"
},
{
name: "collect_fee_mode",
docs: ["collect fee mode"],
type: "u8"
}
]
}
},
{
name: "InitializeLbPair2Params",
type: {
kind: "struct",
fields: [
{
name: "active_id",
docs: ["Pool price"],
type: "i32"
},
{
name: "padding",
docs: ["Padding, for future use"],
type: {
array: ["u8", 96]
}
}
]
}
},
{
name: "InitializeReward",
type: {
kind: "struct",
fields: [
{
name: "lb_pair",
type: "pubkey"
},
{
name: "reward_mint",
type: "pubkey"
},
{
name: "funder",
type: "pubkey"
},
{
name: "reward_index",
type: "u64"
},
{
name: "reward_duration",
type: "u64"
}
]
}
},
{
name: "LbPair",
serialization: "bytemuck",
repr: {
kind: "c"
},
type: {
kind: "struct",
fields: [
{
name: "parameters",
type: {
defined: {
name: "StaticParameters"
}
}
},
{
name: "v_parameters",
type: {
defined: {
name: "VariableParameters"
}
}
},
{
name: "bump_seed",
type: {
array: ["u8", 1]
}
},
{
name: "bin_step_seed",
docs: ["Bin step signer seed"],
type: {
array: ["u8", 2]
}
},
{
name: "pair_type",
docs: ["Type of the pair"],
type: "u8"
},
{
name: "active_id",
docs: ["Active bin id"],
type: "i32"
},
{
name: "bin_step",
docs: ["Bin step. Represent the price increment / decrement."],
type: "u16"
},
{
name: "status",
docs: ["Status of the pair. Check PairStatus enum."],
type: "u8"
},
{
name: "require_base_factor_seed",
docs: ["Require base factor seed"],
type: "u8"
},
{
name: "base_factor_seed",
docs: ["Base factor seed"],
type: {
array: ["u8", 2]
}
},
{
name: "activation_type",
docs: ["Activation type"],
type: "u8"
},
{
name: "creator_pool_on_off_control",
docs: [
"Allow pool creator to enable/disable pool with restricted validation. Only applicable for customizable permissionless pair type."
],
type: "u8"
},
{
name: "token_x_mint",
docs: ["Token X mint"],
type: "pubkey"
},
{
name: "token_y_mint",
docs: ["Token Y mint"],
type: "pubkey"
},
{
name: "reserve_x",
docs: ["LB token X vault"],
type: "pubkey"
},
{
name: "reserve_y",
docs: ["LB token Y vault"],
type: "pubkey"
},
{
name: "protocol_fee",
docs: ["Uncollected protocol fee"],
type: {
defined: {
name: "ProtocolFee"
}
}
},
{
name: "_padding_1",
docs: ["padding 1"],
type: {
array: ["u8", 32]
}
},
{
name: "reward_infos",
docs: ["Farming reward information"],
type: {
array: [
{
defined: {
name: "RewardInfo"
}
},
2
]
}
},
{
name: "oracle",
docs: ["Oracle pubkey"],
type: "pubkey"
},
{
name: "bin_array_bitmap",
docs: ["Packed initialized bin array state"],
type: {
array: ["u64", 16]
}
},
{
name: "last_updated_at",
docs: ["Last time the pool fee parameter was updated"],
type: "i64"
},
{
name: "_padding_2",
docs: ["_padding_2"],
type: {
array: ["u8", 32]
}
},
{
name: "pre_activation_swap_address",
docs: [
"Address allowed to swap when the current point is greater than or equal to the pre-activation point. The pre-activation point is calculated as `activation_point - pre_activation_duration`."
],
type: "pubkey"
},
{
name: "base_key",
docs: ["Base keypair. Only required for permission pair"],
type: "pubkey"
},
{
name: "activation_point",
docs: [
"Time point to enable the pair. Only applicable for permission pair."
],
type: "u64"
},
{
name: "pre_activation_duration",
docs: [
"Duration before activation activation_point. Used to calculate pre-activation time point for pre_activation_swap_address"
],
type: "u64"
},
{
name: "_padding_3",
docs: ["_padding 3"],
type: {
array: ["u8", 8]
}
},
{
name: "_padding_4",
docs: ["_padding_4"],
type: "u64"
},
{
name: "creator",
docs: ["Pool creator"],
type: "pubkey"
},
{
name: "token_mint_x_program_flag",
docs: ["token_mint_x_program_flag"],
type: "u8"
},
{
name: "token_mint_y_program_flag",
docs: ["token_mint_y_program_flag"],
type: "u8"
},
{
name: "version",
docs: ["version to know whether we have reset tombstone fields"],
type: "u8"
},
{
name: "_reserved",
docs: ["Reserved space for future use"],
type: {
array: ["u8", 21]
}
}
]
}
},
{
name: "LbPairCreate",
type: {
kind: "struct",
fields: [
{
name: "lb_pair",
type: "pubkey"
},
{
name: "bin_step",
type: "u16"
},
{
name: "token_x",
type: "pubkey"
},
{
name: "token_y",
type: "pubkey"
}
]
}
},
{
name: "LimitOrder",
serialization: "bytemuck",
repr: {
kind: "c"
},
type: {
kind: "struct",
fields: [
{
name: "lb_pair",
docs: ["The LB pair of this LO"],
type: "pubkey"
},
{
name: "owner",
docs: [
"Owner of the LO. Client rely on this to to fetch their LOs."
],
type: "pubkey"
},
{
name: "bin_count",
docs: ["Bin count"],
type: "u16"
},
{
name: "_padding_0",
docs: ["Padding"],
type: {
array: ["u8", 14]
}
},
{
name: "padding_1",
docs: ["Reserved space for future use"],
type: {
array: ["u64", 4]
}
}
]
}
},
{
name: "LimitOrderBinData",
serialization: "bytemuck",
repr: {
kind: "c"
},
type: {
kind: "struct",
fields: [
{
name: "amount",
type: "u64"
},
{
name: "age",
type: "u32"
},
{
name: "_padding_0",
type: {
array: ["u8", 4]
}
},
{
name: "bin_id",
type: "i32"
},
{
name: "is_ask",
type: "u8"
},
{
name: "_padding_1",
type: {
array: ["u8", 11]
}
}
]
}
},
{
name: "LiquidityOneSideParameter",
type: {
kind: "struct",
fields: [
{
name: "amount",
docs: ["Amount of X token or Y token to deposit"],
type: "u64"
},
{
name: "active_id",
docs: ["Active bin that integrator observe off-chain"],
type: "i32"
},
{
name: "max_active_bin_slippage",
docs: ["max active bin slippage allowed"],
type: "i32"
},
{
name: "bin_liquidity_dist",
docs: ["Liquidity distribution to each bins"],
type: {
vec: {
defined: {
name: "BinLiquidityDistributionByWeight"
}
}
}
}
]
}
},
{
name: "LiquidityParameter",
type: {
kind: "struct",
fields: [
{
name: "amount_x",
docs: ["Amount of X token to deposit"],
type: "u64"
},
{
name: "amount_y",
docs: ["Amount of Y token to deposit"],
type: "u64"
},
{
name: "bin_liquidity_dist",
docs: ["Liquidity distribution to each bins"],
type: {
vec: {
defined: {
name: "BinLiquidityDistribution"
}
}
}
}
]
}
},
{
name: "LiquidityParameterByStrategy",
type: {
kind: "struct",
fields: [
{
name: "amount_x",
docs: ["Amount of X token to deposit"],
type: "u64"
},
{
name: "amount_y",
docs: ["Amount of Y token to deposit"],
type: "u64"
},
{
name: "active_id",
docs: ["Active bin that integrator observe off-chain"],
type: "i32"
},
{
name: "max_active_bin_slippage",
docs: ["max active bin slippage allowed"],
type: "i32"
},
{
name: "strategy_parameters",
docs: ["strategy parameters"],
type: {
defined: {
name: "StrategyParameters"
}
}
}
]
}
},
{
name: "LiquidityParameterByStrategyOneSide",
type: {
kind: "struct",
fields: [
{
name: "amount",
docs: ["Amount of X token or Y token to deposit"],
type: "u64"
},
{
name: "active_id",
docs: ["Active bin that integrator observe off-chain"],
type: "i32"
},
{
name: "max_active_bin_slippage",
docs: ["max active bin slippage allowed"],
type: "i32"
},
{
name: "strategy_parameters",
docs: ["strategy parameters"],
type: {
defined: {
name: "StrategyParameters"
}
}
}
]
}
},
{
name: "LiquidityParameterByWeight",
type: {
kind: "struct",
fields: [
{
name: "amount_x",
docs: ["Amount of X token to deposit"],
type: "u64"
},
{
name: "amount_y",
docs: ["Amount of Y token to deposit"],
type: "u64"
},
{
name: "active_id",
docs: ["Active bin that integrator observe off-chain"],
type: "i32"
},
{
name: "max_active_bin_slippage",
docs: ["max active bin slippage allowed"],
type: "i32"
},
{
name: "bin_liquidity_dist",
docs: ["Liquidity distribution to each bins"],
type: {
vec: {
defined: {
name: "BinLiquidityDistributionByWeight"
}
}
}
}
]
}
},
{
name: "Operator",
serialization: "bytemuck",
repr: {
kind: "c"
},
type: {
kind: "struct",
fields: [
{
name: "signer",
type: "pubkey"
},
{
name: "permission",
type: "u128"
},
{
name: "padding",
type: {
array: ["u64", 2]
}
}
]
}
},
{
name: "Oracle",
serialization: "bytemuck",
repr: {
kind: "c"
},
type: {
kind: "struct",
fields: [
{
name: "idx",
docs: ["Index of latest observation"],
type: "u64"
},
{
name: "active_size",
docs: [
"Size of active sample. Active sample is initialized observation."
],
type: "u64"
},
{
name: "length",
docs: ["Number of observations"],
type: "u64"
}
]
}
},
{
name: "PairStatus",
docs: [
"Pair status. 0 = Enabled, 1 = Disabled. Putting 0 as enabled for backward compatibility."
],
repr: {
kind: "rust"
},
type: {
kind: "enum",
variants: [
{
name: "Enabled"
},
{
name: "Disabled"
}
]
}
},
{
name: "PairType",
docs: [
"Type of the Pair. 0 = Permissionless, 1 = Permission, 2 = CustomizablePermissionless. Putting 0 as permissionless for backward compatibility."
],
repr: {
kind: "rust"
},
type: {
kind: "enum",
variants: [
{
name: "Permissionless"
},
{
name: "Permission"
},
{
name: "CustomizablePermissionless"
},
{
name: "PermissionlessV2"
}
]
}
},
{
name: "PlaceLimitOrderEvt",
type: {
kind: "struct",
fields: [
{
name: "lb_pair",
type: "pubkey"
},
{
name: "sender",
type: "pubkey"
},
{
name: "owner",
type: "pubkey"
},
{
name: "limit_order",
type: "pubkey"
},
{
name: "active_id",
type: "i32"
},
{
name: "params",
type: {
defined: {
name: "PlaceLimitOrderParams"
}
}
}
]
}
},
{
name: "PlaceLimitOrderParams",
type: {
kind: "struct",
fields: [
{
name: "is_ask_side",
type: "bool"
},
{
name: "padding",
type: {
array: ["u8", 16]
}
},
{
name: "relative_bin",
type: {
option: {
defined: {
name: "RelativeBin"
}
}
}
},
{
name: "bins",
type: {
vec: {
defined: {
name: "BinLimitOrderAmount"
}
}
}
}
]
}
},
{
name: "PositionBinData",
serialization: "bytemuck",
repr: {
kind: "c"
},
type: {
kind: "struct",
fields: [
{
name: "liquidity_share",
type: "u128"
},
{
name: "reward_info",
type: {
defined: {
name: "UserRewardInfo"
}
}
},
{
name: "fee_info",
type: {
defined: {
name: "FeeInfo"
}
}
}
]
}
},
{
name: "PositionClose",
type: {
kind: "struct",
fields: [
{
name: "position",
type: "pubkey"
},
{
name: "owner",
type: "pubkey"
}
]
}
},
{
name: "PositionCreate",
type: {
kind: "struct",
fields: [
{
name: "lb_pair",
type: "pubkey"
},
{
name: "position",
type: "pubkey"
},
{
name: "owner",
type: "pubkey"
}
]
}
},
{
name: "PositionV2",
serialization: "bytemuck",
repr: {
kind: "c"
},
type: {
kind: "struct",
fields: [
{
name: "lb_pair",
docs: ["The LB pair of this position"],
type: "pubkey"
},
{
name: "owner",
docs: [
"Owner of the position. Client rely on this to to fetch their positions."
],
type: "pubkey"
},
{
name: "liquidity_shares",
docs: [
"Liquidity shares of this position in bins (lower_bin_id <-> upper_bin_id). This is the same as LP concept."
],
type: {
array: ["u128", 70]
}
},
{
name: "reward_infos",
docs: ["Farming reward information"],
type: {
array: [
{
defined: {
name: "UserRewardInfo"
}
},
70
]
}
},
{
name: "fee_infos",
docs: ["Swap fee to claim information"],
type: {
array: [
{
defined: {
name: "FeeInfo"
}
},
70
]
}
},
{
name: "lower_bin_id",
docs: ["Lower bin ID"],
type: "i32"
},
{
name: "upper_bin_id",
docs: ["Upper bin ID"],
type: "i32"
},
{
name: "last_updated_at",
docs: ["Last updated timestamp"],
type: "i64"
},
{
name: "total_claimed_fee_x_amount",
docs: ["Total claimed token fee X"],
type: "u64"
},
{
name: "total_claimed_fee_y_amount",
docs: ["Total claimed token fee Y"],
type: "u64"
},
{
name: "total_claimed_rewards",
docs: ["Total claimed rewards"],
type: {
array: ["u64", 2]
}
},
{
name: "operator",
docs: ["Operator of position"],
type: "pubkey"
},
{
name: "lock_release_point",
docs: ["Time point which the locked liquidity can be withdraw"],
type: "u64"
},
{
name: "_padding_0",
docs: [
"_padding_0, previous subjected_to_bootstrap_liquidity_locking, BE CAREFUL FOR TOMBSTONE WHEN REUSE !!"
],
type: "u8"
},
{
name: "fee_owner",
docs: [
"Address is able to claim fee in this position, only valid for bootstrap_liquidity_position"
],
type: "pubkey"
},
{
name: "version",
docs: ["version to know whether we have reset tombstone fields"],
type: "u8"
},
{
name: "permissionless_operation_bits",
type: "u8"
},
{
name: "_reserved",
docs: ["Reserved space for future use"],
type: {
array: ["u8", 85]
}
}
]
}
},
{
name: "PresetParameter",
type: {
kind: "struct",
fields: [
{
name: "bin_step",
docs: ["Bin step. Represent the price increment / decrement."],
type: "u16"
},
{
name: "base_factor",
docs: [
"Used for base fee calculation. base_fee_rate = base_factor * bin_step * 10 * 10^base_fee_power_factor"
],
type: "u16"
},
{
name: "filter_period",
docs: [
"Filter period determine high frequency trading time window."
],
type: "u16"
},
{
name: "decay_period",
docs: [
"Decay period determine when the volatile fee start decay / decrease."
],
type: "u16"
},
{
name: "reduction_factor",
docs: [
"Reduction factor controls the volatile fee rate decrement rate."
],
type: "u16"
},
{
name: "variable_fee_control",
docs: [
"Used to scale the variable fee component depending on the dynamic of the market"
],
type: "u32"
},
{
name: "max_volatility_accumulator",
docs: [
"Maximum number of bin crossed can be accumulated. Used to cap volatile fee rate."
],
type: "u32"
},
{
name: "min_bin_id",
docs: [
"Min bin id supported by the pool based on the configured bin step."
],
type: "i32"
},
{
name: "max_bin_id",
docs: [
"Max bin id supported by the pool based on the configured bin step."
],
type: "i32"
},
{
name: "protocol_share",
docs: [
"Portion of swap fees retained by the protocol by controlling protocol_share parameter. protocol_swap_fee = protocol_share * total_swap_fee"
],
type: "u16"
}
]
}
},
{
name: "PresetParameter2",
serialization: "bytemuck",
repr: {
kind: "c"
},
type: {
kind: "struct",
fields: [
{
name: "bin_step",
docs: ["Bin step. Represent the price increment / decrement."],
type: "u16"
},
{
name: "base_factor",
docs: [
"Used for base fee calculation. base_fee_rate = base_factor * bin_step * 10 * 10^base_fee_power_factor"
],
type: "u16"
},
{
name: "filter_period",
docs: [
"Filter period determine high frequency trading time window."
],
type: "u16"
},
{
name: "decay_period",
docs: [
"Decay period determine when the volatile fee start decay / decrease."
],
type: "u16"
},
{
name: "variable_fee_control",
docs: [
"Used to scale the variable fee component depending on the dynamic of the market"
],
type: "u32"
},
{
name: "max_volatility_accumulator",
docs: [
"Maximum number of bin crossed can be accumulated. Used to cap volatile fee rate."
],
type: "u32"
},
{
name: "reduction_factor",
docs: [
"Reduction factor controls the volatile fee rate decrement rate."
],
type: "u16"
},
{
name: "protocol_share",
docs: [
"Portion of swap fees retained by the protocol by controlling protocol_share parameter. protocol_swap_fee = protocol_share * total_swap_fee"
],
type: "u16"
},
{
name: "index",
docs: ["index"],
type: "u16"
},
{
name: "base_fee_power_factor",
docs: ["Base fee power factor"],
type: "u8"
},
{
name: "concrete_function_type",
docs: [
"function type, to check whether the pool should have LM farming or other functions in the future, refer ConcreteFunctionType"
],
type: "u8"
},
{
name: "collect_fee_mode",
docs: ["collect fee mode"],
type: "u8"
},
{
name: "padding_0",
type: {
array: ["u8", 7]
}
},
{
name: "padding_1",
docs: ["Padding 1 for future use"],
type: {
array: ["u64", 19]
}
}
]
}
},
{
name: "ProtocolFee",
serialization: "bytemuck",
repr: {
kind: "c"
},
type: {
kind: "struct",
fields: [
{
name: "amount_x",
type: "u64"
},
{
name: "amount_y",
type: "u64"
}
]
}
},
{
name: "RebalanceLiquidityParams",
type: {
kind: "struct",
fields: [
{
name: "active_id",
docs: ["active id"],
type: "i32"
},
{
name: "max_active_bin_slippage",
docs: ["max active bin slippage allowed"],
type: "u16"
},
{
name: "should_claim_fee",
docs: ["a flag to indicate that whether fee should be harvested"],
type: "bool"
},
{
name: "should_claim_reward",
docs: [
"a flag to indicate that whether rewards should be harvested"
],
type: "bool"
},
{
name: "min_withdraw_x_amount",
docs: ["threshold for withdraw token x"],
type: "u64"
},
{
name: "max_deposit_x_amount",
docs: ["threshold for deposit token x"],
type: "u64"
},
{
name: "min_withdraw_y_amount",
docs: ["threshold for withdraw token y"],
type: "u64"
},
{
name: "max_deposit_y_amount",
docs: ["threshold for deposit token y"],
type: "u64"
},
{
name: "shrink_mode",
docs: ["shrink mode"],
type: "u8"
},
{
name: "padding",
docs: ["padding 32 bytes for future usage"],
type: {
array: ["u8", 31]
}
},
{
name: "removes",
docs: ["removes"],
type: {
vec: {
defined: {
name: "RemoveLiquidityParams"
}
}
}
},
{
name: "adds",
docs: ["adds"],
type: {
vec: {
defined: {
name: "AddLiquidityParams"
}
}
}
}
]
}
},
{
name: "Rebalancing",
type: {
kind: "struct",
fields: [
{
name: "lb_pair",
type: "pubkey"
},
{
name: "position",
type: "pubkey"
},
{
name: "owner",
type: "pubkey"
},
{
name: "active_bin_id",
type: "i32"
},
{
name: "x_withdrawn_amount",
type: "u64"
},
{
name: "x_added_amount",
type: "u64"
},
{
name: "y_withdrawn_amount",
type: "u64"
},
{
name: "y_added_amount",
type: "u64"
},
{
name: "x_fee_amount",
type: "u64"
},
{
name: "y_fee_amount",
type: "u64"
},
{
name: "old_min_id",
type: "i32"
},
{
name: "old_max_id",
type: "i32"
},
{
name: "new_min_id",
type: "i32"
},
{
name: "new_max_id",
type: "i32"
},
{
name: "rewards",
type: {
array: ["u64", 2]
}
}
]
}
},
{
name: "RelativeBin",
type: {
kind: "struct",
fields: [
{
name: "active_id",
docs: ["Active bin that integrator observe off-chain"],
type: "i32"
},
{
name: "max_active_bin_slippage",
docs: ["max active bin slippage allowed"],
type: "i32"
}
]
}
},
{
name: "RemainingAccountsInfo",
type: {
kind: "struct",
fields: [
{
name: "slices",
type: {
vec: {
defined: {
name: "RemainingAccountsSlice"
}
}
}
}
]
}
},
{
name: "RemainingAccountsSlice",
type: {
kind: "struct",
fields: [
{
name: "accounts_type",
type: {
defined: {
name: "AccountsType"
}
}
},
{
name: "length",
type: "u8"
}
]
}
},
{
name: "RemoveLiquidity",
type: {
kind: "struct",
fields: [
{
name: "lb_pair",
type: "pubkey"
},
{
name: "from",
type: "pubkey"
},
{
name: "position",
type: "pubkey"
},
{
name: "amounts",
type: {
array: ["u64", 2]
}
},
{
name: "active_bin_id",
type: "i32"
}
]
}
},
{
name: "RemoveLiquidityParams",
type: {
kind: "struct",
fields: [
{
name: "min_bin_id",
type: {
option: "i32"
}
},
{
name: "max_bin_id",
type: {
option: "i32"
}
},
{
name: "bps",
type: "u16"
},
{
name: "padding",
type: {
array: ["u8", 16]
}
}
]
}
},
{
name: "ResizeSide",
docs: ["Side of resize, 0 for lower and 1 for upper"],
repr: {
kind: "rust"
},
type: {
kind: "enum",
variants: [
{
name: "Lower"
},
{
name: "Upper"
}
]
}
},
{
name: "RewardInfo",
docs: [
"Stores the state relevant for tracking liquidity mining rewards"
],
serialization: "bytemuck",
repr: {
kind: "c"
},
type: {
kind: "struct",
fields: [
{
name: "mint",
docs: ["Reward token mint."],
type: "pubkey"
},
{
name: "vault",
docs: ["Reward vault token account."],
type: "pubkey"
},
{
name: "funder",
docs: ["Authority account that allows to fund rewards"],
type: "pubkey"
},
{
name: "reward_duration",
docs: ["LM reward duration in seconds."],
type: "u64"
},
{
name: "reward_duration_end",
docs: ["LM reward duration end time."],
type: "u64"
},
{
name: "reward_rate",
docs: ["LM reward rate"],
type: "u128"
},
{
name: "last_update_time",
docs: ["The last time reward states were updated."],
type: "u64"
},
{
name: "cumulative_seconds_with_empty_liquidity_reward",
docs: [
"Accumulated seconds where when farm distribute rewards, but the bin is empty. The reward will be accumulated for next reward time window."
],
type: "u64"
}
]
}
},
{
name: "Rounding",
type: {
kind: "enum",
variants: [
{
name: "Up"
},
{
name: "Down"
}
]
}
},
{
name: "SetPositionPermissionlessOperationBitsEvt",
type: {
kind: "struct",
fields: [
{
name: "position",
type: "pubkey"
},
{
name: "owner",
type: "pubkey"
},
{
name: "old_bits",
type: "u8"
},
{
name: "new_bits",
type: "u8"
}
]
}
},
{
name: "StaticParameters",
docs: ["Parameter that set by the protocol"],
serialization: "bytemuck",
repr: {
kind: "c"
},
type: {
kind: "struct",
fields: [
{
name: "base_factor",
docs: [
"Used for base fee calculation. base_fee_rate = base_factor * bin_step * 10 * 10^base_fee_power_factor"
],
type: "u16"
},
{
name: "filter_period",
docs: [
"Filter period determine high frequency trading time window."
],
type: "u16"
},
{
name: "decay_period",
docs: [
"Decay period determine when the volatile fee start decay / decrease."
],
type: "u16"
},
{
name: "reduction_factor",
docs: [
"Reduction factor controls the volatile fee rate decrement rate."
],
type: "u16"
},
{
name: "variable_fee_control",
docs: [
"Used to scale the variable fee component depending on the dynamic of the market"
],
type: "u32"
},
{
name: "max_volatility_accumulator",
docs: [
"Maximum number of bin crossed can be accumulated. Used to cap volatile fee rate."
],
type: "u32"
},
{
name: "min_bin_id",
docs: [
"Min bin id supported by the pool based on the configured bin step."
],
type: "i32"
},
{
name: "max_bin_id",
docs: [
"Max bin id supported by the pool based on the configured bin step."
],
type: "i32"
},
{
name: "protocol_share",
docs: [
"Portion of swap fees retained by the protocol by controlling protocol_share parameter. protocol_swap_fee = protocol_share * total_swap_fee"
],
type: "u16"
},
{
name: "base_fee_power_factor",
docs: ["Base fee power factor"],
type: "u8"
},
{
name: "function_type",
docs: ["function type"],
type: "u8"
},
{
name: "collect_fee_mode",
docs: ["Collect fee mode"],
type: "u8"
},
{
name: "_padding",
docs: ["Padding for bytemuck safe alignment"],
type: {
array: ["u8", 3]
}
}
]
}
},
{
name: "StrategyParameters",
type: {
kind: "struct",
fields: [
{
name: "min_bin_id",
docs: ["min bin id"],
type: "i32"
},
{
name: "max_bin_id",
docs: ["max bin id"],
type: "i32"
},
{
name: "strategy_type",
docs: ["strategy type"],
type: {
defined: {
name: "StrategyType"
}
}
},
{
name: "parameteres",
docs: ["parameters"],
type: {
array: ["u8", 64]
}
}
]
}
},
{
name: "StrategyType",
type: {
kind: "enum",
variants: [
{
name: "SpotOneSide"
},
{
name: "CurveOneSide"
},
{
name: "BidAskOneSide"
},
{
name: "SpotBalanced"
},
{
name: "CurveBalanced"
},
{
name: "BidAskBalanced"
},
{
name: "SpotImBalanced"
},
{
name: "CurveImBalanced"
},
{
name: "BidAskImBalanced"
}
]
}
},
{
name: "Swap",
type: {
kind: "struct",
fields: [
{
name: "lb_pair",
type: "pubkey"
},
{
name: "from",
type: "pubkey"
},
{
name: "start_bin_id",
type: "i32"
},
{
name: "end_bin_id",
type: "i32"
},
{
name: "amount_in",
type: "u64"
},
{
name: "amount_out",
type: "u64"
},
{
name: "swap_for_y",
type: "bool"
},
{
name: "fee",
type: "u64"
},
{
name: "protocol_fee",
type: "u64"
},
{
name: "fee_bps",
type: "u128"
},
{
name: "host_fee",
type: "u64"
}
]
}
},
{
name: "Swap2Evt",
type: {
kind: "struct",
fields: [
{
name: "lb_pair",
type: "pubkey"
},
{
name: "from",
type: "pubkey"
},
{
name: "start_bin_id",
type: "i32"
},
{
name: "end_bin_id",
type: "i32"
},
{
name: "swap_for_y",
type: "bool"
},
{
name: "fee_bps",
type: "u128"
},
{
name: "amount_in",
docs: ["Total amount, user transfer out"],
type: "u64"
},
{
name: "amount_left",
docs: ["Leftover amount"],
type: "u64"
},
{
name: "amount_out",
docs: ["Total amount transfer to user, including transfer fee"],
type: "u64"
},
{
name: "mm_fee",
docs: ["Market maker fee"],
type: "u64"
},
{
name: "protocol_fee",
docs: ["Total protocol fee"],
type: "u64"
},
{
name: "limit_order_fee",
docs: ["Total limit order fee"],
type: "u64"
},
{
name: "host_fee",
docs: ["Total host fee"],
type: "u64"
},
{
name: "fees_on_input",
docs: ["check if fees on input"],
type: "bool"
},
{
name: "fees_on_token_x",
docs: ["check if fees is on token x"],
type: "bool"
}
]
}
},
{
name: "TokenBadge",
docs: ["Parameter that set by the protocol"],
serialization: "bytemuck",
repr: {
kind: "c"
},
type: {
kind: "struct",
fields: [
{
name: "token_mint",
docs: ["token mint"],
type: "pubkey"
},
{
name: "_padding",
docs: ["Reserve"],
type: {
array: ["u8", 128]
}
}
]
}
},
{
name: "TokenProgramFlags",
repr: {
kind: "rust"
},
type: {
kind: "enum",
variants: [
{
name: "TokenProgram"
},
{
name: "TokenProgram2022"
}
]
}
},
{
name: "UpdatePositionLockReleasePoint",
type: {
kind: "struct",
fields: [
{
name: "position",
type: "pubkey"
},
{
name: "current_point",
type: "u64"
},
{
name: "new_lock_release_point",
type: "u64"
},
{
name: "old_lock_release_point",
type: "u64"
},
{
name: "sender",
type: "pubkey"
}
]
}
},
{
name: "UpdatePositionOperator",
type: {
kind: "struct",
fields: [
{
name: "position",
type: "pubkey"
},
{
name: "old_operator",
type: "pubkey"
},
{
name: "new_operator",
type: "pubkey"
}
]
}
},
{
name: "UpdateRewardDuration",
type: {
kind: "struct",
fields: [
{
name: "lb_pair",
type: "pubkey"
},
{
name: "reward_index",
type: "u64"
},
{
name: "old_reward_duration",
type: "u64"
},
{
name: "new_reward_duration",
type: "u64"
}
]
}
},
{
name: "UpdateRewardFunder",
type: {
kind: "struct",
fields: [
{
name: "lb_pair",
type: "pubkey"
},
{
name: "reward_index",
type: "u64"
},
{
name: "old_funder",
type: "pubkey"
},
{
name: "new_funder",
type: "pubkey"
}
]
}
},
{
name: "UserRewardInfo",
serialization: "bytemuck",
repr: {
kind: "c"
},
type: {
kind: "struct",
fields: [
{
name: "reward_per_token_completes",
type: {
array: ["u128", 2]
}
},
{
name: "reward_pendings",
type: {
array: ["u64", 2]
}
}
]
}
},
{
name: "VariableParameters",
docs: ["Parameters that changes based on dynamic of the market"],
serialization: "bytemuck",
repr: {
kind: "c"
},
type: {
kind: "struct",
fields: [
{
name: "volatility_accumulator",
docs: [
"Volatility accumulator measure the number of bin crossed since reference bin ID. Normally (without filter period taken into consideration), reference bin ID is the active bin of last swap.",
"It affects the variable fee rate"
],
type: "u32"
},
{
name: "volatility_reference",
docs: [
"Volatility reference is decayed volatility accumulator. It is always <= volatility_accumulator"
],
type: "u32"
},
{
name: "index_reference",
docs: ["Active bin id of last swap."],
type: "i32"
},
{
name: "_padding",
docs: ["Padding for bytemuck safe alignment"],
type: {
array: ["u8", 4]
}
},
{
name: "last_update_timestamp",
docs: ["Last timestamp the variable parameters was updated"],
type: "i64"
},
{
name: "_padding_1",
docs: ["Padding for bytemuck safe alignment"],
type: {
array: ["u8", 8]
}
}
]
}
},
{
name: "WithdrawIneligibleReward",
type: {
kind: "struct",
fields: [
{
name: "lb_pair",
type: "pubkey"
},
{
name: "reward_mint",
type: "pubkey"
},
{
name: "amount",
type: "u64"
}
]
}
}
],
constants: [
{
name: "BASIS_POINT_MAX",
type: "u16",
value: "10000"
},
{
name: "BIN_ARRAY",
type: "bytes",
value: "[98, 105, 110, 95, 97, 114, 114, 97, 121]"
},
{
name: "BIN_ARRAY_BITMAP_SEED",
type: "bytes",
value: "[98, 105, 116, 109, 97, 112]"
},
{
name: "BIN_ARRAY_BITMAP_SIZE",
type: "i32",
value: "512"
},
{
name: "CLAIM_PROTOCOL_FEE_OPERATOR",
type: "bytes",
value: "[99, 102, 95, 111, 112, 101, 114, 97, 116, 111, 114]"
},
{
name: "DEFAULT_BIN_PER_POSITION",
type: "u64",
value: "70"
},
{
name: "EXTENSION_BINARRAY_BITMAP_SIZE",
type: "u64",
value: "12"
},
{
name: "FEE_DENOMINATOR",
type: "u64",
value: "1000000000"
},
{
name: "HOST_FEE_BPS",
docs: ["Host fee. 20%"],
type: "u16",
value: "2000"
},
{
name: "ILM_PROTOCOL_SHARE",
type: "u16",
value: "2000"
},
{
name: "LIMIT_ORDER_FEE_SHARE",
type: "u16",
value: "5000"
},
{
name: "MAX_BASE_FEE",
docs: ["Maximum base fee, base_fee / 10^9 = fee_in_percentage"],
type: "u128",
value: "100000000"
},
{
name: "MAX_BIN_ID_PER_BIN_STEP",
docs: [
"Maximum bin ID per bin step. Computed based on 1 bps. Used for bin id bound estimation."
],
type: "i32",
value: "351639"
},
{
name: "MAX_BIN_PER_ARRAY",
type: "u64",
value: "70"
},
{
name: "MAX_BIN_PER_LIMIT_ORDER",
type: "u64",
value: "50"
},
{
name: "MAX_BIN_STEP",
docs: ["Maximum bin step"],
type: "u16",
value: "400"
},
{
name: "MAX_FEE_RATE",
docs: ["Maximum fee rate. 10%"],
type: "u64",
value: "100000000"
},
{
name: "MAX_PROTOCOL_SHARE",
docs: ["Maximum protocol share of the fee. 25%"],
type: "u16",
value: "2500"
},
{
name: "MAX_RESIZE_LENGTH",
type: "u64",
value: "91"
},
{
name: "MAX_REWARD_BIN_SPLIT",
type: "u64",
value: "15"
},
{
name: "MAX_REWARD_DURATION",
type: "u64",
value: "31536000"
},
{
name: "MINIMUM_LIQUIDITY",
type: "u128",
value: "1000000"
},
{
name: "MIN_BASE_FEE",
docs: ["Minimum base fee"],
type: "u128",
value: "100000"
},
{
name: "MIN_REWARD_DURATION",
type: "u64",
value: "1"
},
{
name: "NUM_REWARDS",
type: "u64",
value: "2"
},
{
name: "OPERATOR_PREFIX",
type: "bytes",
value: "[111, 112, 101, 114, 97, 116, 111, 114]"
},
{
name: "ORACLE",
type: "bytes",
value: "[111, 114, 97, 99, 108, 101]"
},
{
name: "POSITION",
type: "bytes",
value: "[112, 111, 115, 105, 116, 105, 111, 110]"
},
{
name: "POSITION_MAX_LENGTH",
type: "u64",
value: "1400"
},
{
name: "PRESET_PARAMETER",
type: "bytes",
value: "[112, 114, 101, 115, 101, 116, 95, 112, 97, 114, 97, 109, 101, 116, 101, 114]"
},
{
name: "PRESET_PARAMETER2",
type: "bytes",
value: "[112, 114, 101, 115, 101, 116, 95, 112, 97, 114, 97, 109, 101, 116, 101, 114, 50]"
},
{
name: "PROTOCOL_SHARE",
type: "u16",
value: "500"
}
]
};
// src/dlmm/constants/index.ts
var LBCLMM_PROGRAM_IDS = {
devnet: "LBUZKhRxPF3XUpBCjp4YzTKgLccjZhTSDM9YuVaPwxo",
localhost: "LbVRzDTvBDEcrthxfZ4RL6yiq3uZw8bS6MwtdY6UhFQ",
"mainnet-beta": "LBUZKhRxPF3XUpBCjp4YzTKgLccjZhTSDM9YuVaPwxo"
};
var ALT_ADDRESS = {
"mainnet-beta": "JA5F83HUK9L78Y12TRLCsJZbu3Tv8pCK1GfK8mVNp1sz",
devnet: "BD6E8oYV52P829MxDq3sEtqWKJrHh9pDSUHeaWR1jRBs"
};
var ADMIN = {
devnet: "6WaLrrRfReGKBYUSkmx2K6AuT21ida4j8at2SUiZdXu8",
localhost: "bossj3JvwiNK7pvjr149DqdtJxf2gdygbcmEPTkb2F1"
};
var Network = /* @__PURE__ */ ((Network2) => {
Network2["MAINNET"] = "mainnet-beta";
Network2["TESTNET"] = "testnet";
Network2["DEVNET"] = "devnet";
Network2["LOCAL"] = "localhost";
return Network2;
})(Network || {});
var BASIS_POINT_MAX = 1e4;
var SCALE_OFFSET = 64;
var SCALE = new (0, _anchor.BN)(1).shln(SCALE_OFFSET);
var FEE_PRECISION = new (0, _anchor.BN)(1e9);
var MAX_FEE_RATE = new (0, _anchor.BN)(1e8);
var BIN_ARRAY_DEFAULT_VERSION = 3;
var BIN_ARRAY_FEE = 0.07143744;
var POSITION_FEE = 0.05740608;
var TOKEN_ACCOUNT_FEE = 203928e-8;
var POOL_FEE = 718272e-8;
var BIN_ARRAY_BITMAP_FEE = 0.01180416;
var BIN_ARRAY_FEE_BN = new (0, _anchor.BN)(
new (0, _decimaljs2.default)(BIN_ARRAY_FEE).mul(_web3js.LAMPORTS_PER_SOL).toString()
);
var POSITION_FEE_BN = new (0, _anchor.BN)(
new (0, _decimaljs2.default)(POSITION_FEE).mul(_web3js.LAMPORTS_PER_SOL).toString()
);
var TOKEN_ACCOUNT_FEE_BN = new (0, _anchor.BN)(
new (0, _decimaljs2.default)(TOKEN_ACCOUNT_FEE).mul(_web3js.LAMPORTS_PER_SOL).toString()
);
var POOL_FEE_BN = new (0, _anchor.BN)(
new (0, _decimaljs2.default)(POOL_FEE).mul(_web3js.LAMPORTS_PER_SOL).toString()
);
var BIN_ARRAY_BITMAP_FEE_BN = new (0, _anchor.BN)(
new (0, _decimaljs2.default)(BIN_ARRAY_BITMAP_FEE).mul(_web3js.LAMPORTS_PER_SOL).toString()
);
var CONSTANTS = Object.entries(idl_default.constants);
var MAX_BIN_ARRAY_SIZE = new (0, _anchor.BN)(
_nullishCoalesce(_optionalChain([CONSTANTS, 'access', _2 => _2.find, 'call', _3 => _3(([_, v]) => v.name == "MAX_BIN_PER_ARRAY"), 'optionalAccess', _4 => _4[1], 'access', _5 => _5.value]), () => ( 0))
);
var DEFAULT_BIN_PER_POSITION = new (0, _anchor.BN)(
_nullishCoalesce(_optionalChain([CONSTANTS, 'access', _6 => _6.find, 'call', _7 => _7(([_, v]) => v.name == "DEFAULT_BIN_PER_POSITION"), 'optionalAccess', _8 => _8[1], 'access', _9 => _9.value]), () => ( 0))
);
var BIN_ARRAY_BITMAP_SIZE = new (0, _anchor.BN)(
_nullishCoalesce(_optionalChain([CONSTANTS, 'access', _10 => _10.find, 'call', _11 => _11(([_, v]) => v.name == "BIN_ARRAY_BITMAP_SIZE"), 'optionalAccess', _12 => _12[1], 'access', _13 => _13.value]), () => ( 0))
);
var EXTENSION_BINARRAY_BITMAP_SIZE = new (0, _anchor.BN)(
_nullishCoalesce(_optionalChain([CONSTANTS, 'access', _14 => _14.find, 'call', _15 => _15(([_, v]) => v.name == "EXTENSION_BINARRAY_BITMAP_SIZE"), 'optionalAccess', _16 => _16[1], 'access', _17 => _17.value]), () => ( 0))
);
var POSITION_MAX_LENGTH = new (0, _anchor.BN)(
_nullishCoalesce(_optionalChain([CONSTANTS, 'access', _18 => _18.find, 'call', _19 => _19(([_, v]) => v.name == "POSITION_MAX_LENGTH"), 'optionalAccess', _20 => _20[1], 'access', _21 => _21.value]), () => ( 0))
);
var MAX_RESIZE_LENGTH = new (0, _anchor.BN)(
_nullishCoalesce(_optionalChain([CONSTANTS, 'access', _22 => _22.find, 'call', _23 => _23(([_, v]) => v.name == "MAX_RESIZE_LENGTH"), 'optionalAccess', _24 => _24[1], 'access', _25 => _25.value]), () => ( 0))
);
var MAX_BIN_ID_PER_BIN_STEP = Number(
_nullishCoalesce(_optionalChain([CONSTANTS, 'access', _26 => _26.find, 'call', _27 => _27(([_, v]) => v.name == "MAX_BIN_ID_PER_BIN_STEP"), 'optionalAccess', _28 => _28[1], 'access', _29 => _29.value]), () => ( 0))
);
var SIMULATION_USER = new (0, _web3js.PublicKey)(
"HrY9qR5TiB2xPzzvbBu5KrBorMfYGQXh9osXydz4jy9s"
);
var PRECISION = new (0, _decimaljs2.default)("18446744073709551616");
var MAX_CLAIM_ALL_ALLOWED = 2;
var MAX_BIN_LENGTH_ALLOWED_IN_ONE_TX = 26;
var MAX_ACTIVE_BIN_SLIPPAGE = 3;
var ILM_BASE = new (0, _web3js.PublicKey)(
"MFGQxwAmB91SwuYX36okv2Qmdc9aMuHTwWGUrp4AtB1"
);
var MAX_EXTRA_BIN_ARRAYS = 3;
var U64_MAX = new (0, _anchor.BN)("18446744073709551615");
var MAX_BINS_PER_POSITION = new (0, _anchor.BN)(
_nullishCoalesce(_optionalChain([CONSTANTS, 'access', _30 => _30.find, 'call', _31 => _31(([_, v]) => v.name == "POSITION_MAX_LENGTH"), 'optionalAccess', _32 => _32[1], 'access', _33 => _33.value]), () => ( 0))
);
var MAX_BIN_PER_LIMIT_ORDER = new (0, _anchor.BN)(
_nullishCoalesce(_optionalChain([CONSTANTS, 'access', _34 => _34.find, 'call', _35 => _35(([_, v]) => v.name == "MAX_BIN_PER_LIMIT_ORDER"), 'optionalAccess', _36 => _36[1], 'access', _37 => _37.value]), () => ( 0))
);
var LIMIT_ORDER_FEE_SHARE = new (0, _anchor.BN)(
_nullishCoalesce(_optionalChain([CONSTANTS, 'access', _38 => _38.find, 'call', _39 => _39(([_, v]) => v.name == "LIMIT_ORDER_FEE_SHARE"), 'optionalAccess', _40 => _40[1], 'access', _41 => _41.value]), () => ( 0))
);
var FunctionType = /* @__PURE__ */ ((FunctionType2) => {
FunctionType2[FunctionType2["Undetermined"] = 0] = "Undetermined";
FunctionType2[FunctionType2["LiquidityMining"] = 1] = "LiquidityMining";
FunctionType2[FunctionType2["LimitOrder"] = 2] = "LimitOrder";
return FunctionType2;
})(FunctionType || {});
var ConcreteFunctionType = /* @__PURE__ */ ((ConcreteFunctionType2) => {
ConcreteFunctionType2[ConcreteFunctionType2["LimitOrder"] = 0] = "LimitOrder";
ConcreteFunctionType2[ConcreteFunctionType2["LiquidityMining"] = 1] = "LiquidityMining";
return ConcreteFunctionType2;
})(ConcreteFunctionType || {});
var CollectFeeMode = /* @__PURE__ */ ((CollectFeeMode2) => {
CollectFeeMode2[CollectFeeMode2["InputOnly"] = 0] = "InputOnly";
CollectFeeMode2[CollectFeeMode2["OnlyY"] = 1] = "OnlyY";
return CollectFeeMode2;
})(CollectFeeMode || {});
// src/dlmm/error.ts
var DLMMError = class extends Error {
constructor(error) {
let _errorCode = 0;
let _errorName = "Something went wrong";
let _errorMessage = "Something went wrong";
if (error instanceof Error) {
const anchorError = _anchor.AnchorError.parse(
JSON.parse(JSON.stringify(error)).logs
);
if (_optionalChain([anchorError, 'optionalAccess', _42 => _42.program, 'access', _43 => _43.toBase58, 'call', _44 => _44()]) === LBCLMM_PROGRAM_IDS["mainnet-beta"]) {
_errorCode = anchorError.error.errorCode.number;
_errorName = anchorError.error.errorCode.code;
_errorMessage = anchorError.error.errorMessage;
}
} else {
const idlError = idl_default.errors.find((err) => err.code === error);
if (idlError) {
_errorCode = idlError.code;
_errorName = idlError.name;
_errorMessage = idlError.msg;
}
}
super(_errorMessage);
this.errorCode = _errorCode;
this.errorName = _errorName;
this.errorMessage = _errorMessage;
}
};
var DlmmSdkError = class extends Error {
constructor(name, message) {
super();
this.name = name;
this.message = message;
}
};
// src/dlmm/helpers/index.ts
// src/dlmm/types/index.ts
var _borsh = require('@coral-xyz/borsh');
var PositionVersion = /* @__PURE__ */ ((PositionVersion3) => {
PositionVersion3[PositionVersion3["V1"] = 0] = "V1";
PositionVersion3[PositionVersion3["V2"] = 1] = "V2";
return PositionVersion3;
})(PositionVersion || {});
var PairType = /* @__PURE__ */ ((PairType2) => {
PairType2[PairType2["Permissionless"] = 0] = "Permissionless";
PairType2[PairType2["Permissioned"] = 1] = "Permissioned";
PairType2[PairType2["CustomizablePermissionless"] = 2] = "CustomizablePermissionless";
PairType2[PairType2["PermissionlessV2"] = 3] = "PermissionlessV2";
return PairType2;
})(PairType || {});
var ShrinkMode = /* @__PURE__ */ ((ShrinkMode2) => {
ShrinkMode2[ShrinkMode2["ShrinkBoth"] = 0] = "ShrinkBoth";
ShrinkMode2[ShrinkMode2["NoShrinkLeft"] = 1] = "NoShrinkLeft";
ShrinkMode2[ShrinkMode2["NoShrinkRight"] = 2] = "NoShrinkRight";
ShrinkMode2[ShrinkMode2["NoShrinkBoth"] = 3] = "NoShrinkBoth";
return ShrinkMode2;
})(ShrinkMode || {});
var Strategy = {
SpotBalanced: { spotBalanced: {} },
CurveBalanced: { curveBalanced: {} },
BidAskBalanced: { bidAskBalanced: {} },
SpotImBalanced: { spotImBalanced: {} },
CurveImBalanced: { curveImBalanced: {} },
BidAskImBalanced: { bidAskImBalanced: {} }
};
var StrategyType = /* @__PURE__ */ ((StrategyType3) => {
StrategyType3[StrategyType3["Spot"] = 0] = "Spot";
StrategyType3[StrategyType3["Curve"] = 1] = "Curve";
StrategyType3[StrategyType3["BidAsk"] = 2] = "BidAsk";
return StrategyType3;
})(StrategyType || {});
var ActivationType = /* @__PURE__ */ ((ActivationType2) => {
ActivationType2[ActivationType2["Slot"] = 0] = "Slot";
ActivationType2[ActivationType2["Timestamp"] = 1] = "Timestamp";
return ActivationType2;
})(ActivationType || {});
var POSITION_MIN_SIZE = 8112;
var POSITION_BIN_DATA_SIZE = 112;
var LIMIT_ORDER_MIN_SIZE = 112;
var LIMIT_ORDER_BIN_DATA_SIZE = 32;
var BinLiquidity;
((BinLiquidity2) => {
function fromBin(bin, binId, binStep, baseTokenDecimal, quoteTokenDecimal, version, lbPair) {
const pricePerLamport = getPriceOfBinByBinId(binId, binStep).toString();
const supportLimitOrder = isSupportLimitOrder(lbPair);
const xAmount = bin.amountX;
const yAmount = bin.amountY;
const supply = bin.liquiditySupply;
const pricePerToken = new (0, _decimaljs2.default)(pricePerLamport).mul(new (0, _decimaljs2.default)(10 ** (baseTokenDecimal - quoteTokenDecimal))).toString();
const feeAmountXPerTokenStored = bin.feeAmountXPerTokenStored;
const feeAmountYPerTokenStored = bin.feeAmountYPerTokenStored;
if (supportLimitOrder) {
return {
binId,
xAmount,
yAmount,
supply,
version,
price: pricePerLamport,
pricePerToken,
feeAmountXPerTokenStored,
feeAmountYPerTokenStored,
rewardPerTokenStored: [new (0, _anchor.BN)(0), new (0, _anchor.BN)(0)],
fulfilledOrderAmountX: bin.fulfilledOrderAmountX,
fulfilledOrderAmountY: bin.fulfilledOrderAmountY,
limitOrderFeeAskSide: bin.limitOrderFeeAskSide,
limitOrderFeeBidSide: bin.limitOrderFeeBidSide,
openOrderAmount: bin.openOrderAmount,
totalProcessingOrderAmount: bin.totalProcessingOrderAmount,
processedOrderRemainingAmount: bin.processedOrderRemainingAmount,
orderAge: bin.orderAge,
limitOrderAskSide: bin.limitOrderAskSide == 1
};
} else {
return {
binId,
xAmount,
yAmount,
supply,
version,
price: pricePerLamport,
pricePerToken,
feeAmountXPerTokenStored,
feeAmountYPerTokenStored,
rewardPerTokenStored: decodeRewardPerTokenStored(bin),
fulfilledOrderAmountX: new (0, _anchor.BN)(0),
fulfilledOrderAmountY: new (0, _anchor.BN)(0),
limitOrderFeeAskSide: new (0, _anchor.BN)(0),
limitOrderFeeBidSide: new (0, _anchor.BN)(0),
openOrderAmount: new (0, _anchor.BN)(0),
totalProcessingOrderAmount: new (0, _anchor.BN)(0),
processedOrderRemainingAmount: new (0, _anchor.BN)(0),
orderAge: 0,
limitOrderAskSide: false
};
}
}
BinLiquidity2.fromBin = fromBin;
function empty(binId, binStep, baseTokenDecimal, quoteTokenDecimal, version) {
const pricePerLamport = getPriceOfBinByBinId(binId, binStep).toString();
return {
binId,
xAmount: new (0, _anchor.BN)(0),
yAmount: new (0, _anchor.BN)(0),
supply: new (0, _anchor.BN)(0),
price: pricePerLamport,
version,
pricePerToken: new (0, _decimaljs2.default)(pricePerLamport).mul(new (0, _decimaljs2.default)(10 ** (baseTokenDecimal - quoteTokenDecimal))).toString(),
feeAmountXPerTokenStored: new (0, _anchor.BN)(0),
feeAmountYPerTokenStored: new (0, _anchor.BN)(0),
rewardPerTokenStored: [new (0, _anchor.BN)(0), new (0, _anchor.BN)(0)],
fulfilledOrderAmountX: new (0, _anchor.BN)(0),
fulfilledOrderAmountY: new (0, _anchor.BN)(0),
limitOrderFeeAskSide: new (0, _anchor.BN)(0),
limitOrderFeeBidSide: new (0, _anchor.BN)(0),
openOrderAmount: new (0, _anchor.BN)(0),
totalProcessingOrderAmount: new (0, _anchor.BN)(0),
processedOrderRemainingAmount: new (0, _anchor.BN)(0),
orderAge: 0,
limitOrderAskSide: false
};
}
BinLiquidity2.empty = empty;
})(BinLiquidity || (BinLiquidity = exports.BinLiquidity = {}));
var BitmapType = /* @__PURE__ */ ((BitmapType2) => {
BitmapType2[BitmapType2["U1024"] = 0] = "U1024";
BitmapType2[BitmapType2["U512"] = 1] = "U512";
return BitmapType2;
})(BitmapType || {});
var ClockLayout = _borsh.struct.call(void 0, [
_borsh.u64.call(void 0, "slot"),
_borsh.i64.call(void 0, "epochStartTimestamp"),
_borsh.u64.call(void 0, "epoch"),
_borsh.u64.call(void 0, "leaderScheduleEpoch"),
_borsh.i64.call(void 0, "unixTimestamp")
]);
var PairStatus = /* @__PURE__ */ ((PairStatus2) => {
PairStatus2[PairStatus2["Enabled"] = 0] = "Enabled";
PairStatus2[PairStatus2["Disabled"] = 1] = "Disabled";
return PairStatus2;
})(PairStatus || {});
var ActionType = /* @__PURE__ */ ((ActionType2) => {
ActionType2[ActionType2["Liquidity"] = 0] = "Liquidity";
ActionType2[ActionType2["Reward"] = 1] = "Reward";
return ActionType2;
})(ActionType || {});
var ResizeSide = /* @__PURE__ */ ((ResizeSide2) => {
ResizeSide2[ResizeSide2["Lower"] = 0] = "Lower";
ResizeSide2[ResizeSide2["Upper"] = 1] = "Upper";
return ResizeSide2;
})(ResizeSide || {});
var MEMO_PROGRAM_ID = new (0, _web3js.PublicKey)(
"MemoSq4gqABAXKb96qnH8TysNcWxMyWCqXgDLGmfcHr"
);
var REBALANCE_POSITION_PADDING = Array(31).fill(0);
var PositionPermission = /* @__PURE__ */ ((PositionPermission3) => {
PositionPermission3[PositionPermission3["ClaimFee"] = 0] = "ClaimFee";
return PositionPermission3;
})(PositionPermission || {});
var LimitOrderStatus = /* @__PURE__ */ ((LimitOrderStatus2) => {
LimitOrderStatus2[LimitOrderStatus2["NotFilled"] = 0] = "NotFilled";
LimitOrderStatus2[LimitOrderStatus2["PartialFilled"] = 1] = "PartialFilled";
LimitOrderStatus2[LimitOrderStatus2["Fulfilled"] = 2] = "Fulfilled";
return LimitOrderStatus2;
})(LimitOrderStatus || {});
// src/dlmm/helpers/binArray.ts
// src/dlmm/helpers/derive.ts
function sortTokenMints(tokenX, tokenY) {
const [minKey, maxKey] = tokenX.toBuffer().compare(tokenY.toBuffer()) == 1 ? [tokenY, tokenX] : [tokenX, tokenY];
return [minKey, maxKey];
}
function derivePresetParameterWithIndex(index, programId) {
return _web3js.PublicKey.findProgramAddressSync(
[
Buffer.from("preset_parameter2"),
new Uint8Array(index.toArrayLike(Buffer, "le", 2))
],
programId
);
}
function deriveLbPairWithPresetParamWithIndexKey(presetParameterKey, tokenX, tokenY, programId) {
const [minKey, maxKey] = sortTokenMints(tokenX, tokenY);
return _web3js.PublicKey.findProgramAddressSync(
[presetParameterKey.toBuffer(), minKey.toBuffer(), maxKey.toBuffer()],
programId
);
}
function derivePresetParameter(binStep, programId) {
return _web3js.PublicKey.findProgramAddressSync(
[
Buffer.from("preset_parameter"),
new Uint8Array(binStep.toArrayLike(Buffer, "le", 2))
],
programId
);
}
function derivePresetParameter2(binStep, baseFactor, programId) {
return _web3js.PublicKey.findProgramAddressSync(
[
Buffer.from("preset_parameter"),
new Uint8Array(binStep.toArrayLike(Buffer, "le", 2)),
new Uint8Array(baseFactor.toArrayLike(Buffer, "le", 2))
],
programId
);
}
function deriveLbPair2(tokenX, tokenY, binStep, baseFactor, programId) {
const [minKey, maxKey] = sortTokenMints(tokenX, tokenY);
return _web3js.PublicKey.findProgramAddressSync(
[
minKey.toBuffer(),
maxKey.toBuffer(),
new Uint8Array(binStep.toArrayLike(Buffer, "le", 2)),
new Uint8Array(baseFactor.toArrayLike(Buffer, "le", 2))
],
programId
);
}
function deriveLbPair(tokenX, tokenY, binStep, programId) {
const [minKey, maxKey] = sortTokenMints(tokenX, tokenY);
return _web3js.PublicKey.findProgramAddressSync(
[
minKey.toBuffer(),
maxKey.toBuffer(),
new Uint8Array(binStep.toArrayLike(Buffer, "le", 2))
],
programId
);
}
function deriveCustomizablePermissionlessLbPair(tokenX, tokenY, programId) {
const [minKey, maxKey] = sortTokenMints(tokenX, tokenY);
return _web3js.PublicKey.findProgramAddressSync(
[ILM_BASE.toBuffer(), minKey.toBuffer(), maxKey.toBuffer()],
programId
);
}
function derivePermissionLbPair(baseKey, tokenX, tokenY, binStep, programId) {
const [minKey, maxKey] = sortTokenMints(tokenX, tokenY);
return _web3js.PublicKey.findProgramAddressSync(
[
baseKey.toBuffer(),
minKey.toBuffer(),
maxKey.toBuffer(),
new Uint8Array(binStep.toArrayLike(Buffer, "le", 2))
],
programId
);
}
function deriveOracle(lbPair, programId) {
return _web3js.PublicKey.findProgramAddressSync(
[Buffer.from("oracle"), lbPair.toBytes()],
programId
);
}
function derivePosition(lbPair, base, lowerBinId, width, programId) {
let lowerBinIdBytes;
if (lowerBinId.isNeg()) {
lowerBinIdBytes = new Uint8Array(
lowerBinId.toTwos(32).toArrayLike(Buffer, "le", 4)
);
} else {
lowerBinIdBytes = new Uint8Array(lowerBinId.toArrayLike(Buffer, "le", 4));
}
return _web3js.PublicKey.findProgramAddressSync(
[
Buffer.from("position"),
lbPair.toBuffer(),
base.toBuffer(),
lowerBinIdBytes,
new Uint8Array(width.toArrayLike(Buffer, "le", 4))
],
programId
);
}
function deriveBinArray(lbPair, index, programId) {
let binArrayBytes;
if (index.isNeg()) {
binArrayBytes = new Uint8Array(
index.toTwos(64).toArrayLike(Buffer, "le", 8)
);
} else {
binArrayBytes = new Uint8Array(index.toArrayLike(Buffer, "le", 8));
}
return _web3js.PublicKey.findProgramAddressSync(
[Buffer.from("bin_array"), lbPair.toBytes(), binArrayBytes],
programId
);
}
function deriveReserve(token, lbPair, programId) {
return _web3js.PublicKey.findProgramAddressSync(
[lbPair.toBuffer(), token.toBuffer()],
programId
);
}
function deriveTokenBadge(mint, programId) {
return _web3js.PublicKey.findProgramAddressSync(
[Buffer.from("token_badge"), mint.toBuffer()],
programId
);
}
function deriveEventAuthority(programId) {
return _web3js.PublicKey.findProgramAddressSync(
[Buffer.from("__event_authority")],
programId
);
}
function deriveRewardVault(lbPair, rewardIndex, programId) {
return _web3js.PublicKey.findProgramAddressSync(
[lbPair.toBuffer(), rewardIndex.toArrayLike(Buffer, "le", 8)],
programId
);
}
function derivePlaceHolderAccountMeta(programId) {
return {
pubkey: programId,
isWritable: false,
isSigner: false
};
}
function deriveOperator(whitelistedSigner, programId) {
return _web3js.PublicKey.findProgramAddressSync(
[Buffer.from("operator"), whitelistedSigner.toBuffer()],
programId
)[0];
}
// src/dlmm/helpers/math.ts
// src/dlmm/helpers/u64xu64_math.ts
var _bnjs = require('bn.js'); var _bnjs2 = _interopRequireDefault(_bnjs);
var MAX_EXPONENTIAL = new (0, _bnjs2.default)(524288);
var ONE = new (0, _bnjs2.default)(1).shln(SCALE_OFFSET);
var MAX = new (0, _bnjs2.default)(2).pow(new (0, _bnjs2.default)(128)).sub(new (0, _bnjs2.default)(1));
function pow(base, exp) {
let invert = exp.isNeg();
if (exp.isZero()) {
return ONE;
}
exp = invert ? exp.abs() : exp;
if (exp.gt(MAX_EXPONENTIAL)) {
return new (0, _bnjs2.default)(0);
}
let squaredBase = base;
let result = ONE;
if (squaredBase.gte(result)) {
squaredBase = MAX.div(squaredBase);
invert = !invert;
}
if (!exp.and(new (0, _bnjs2.default)(1)).isZero()) {
result = result.mul(squaredBase).shrn(SCALE_OFFSET);
}
squaredBase = squaredBase.mul(squaredBase).shrn(SCALE_OFFSET);
if (!exp.and(new (0, _bnjs2.default)(2)).isZero()) {
result = result.mul(squaredBase).shrn(SCALE_OFFSET);
}
squaredBase = squaredBase.mul(squaredBase).shrn(SCALE_OFFSET);
if (!exp.and(new (0, _bnjs2.default)(4)).isZero()) {
result = result.mul(squaredBase).shrn(SCALE_OFFSET);
}
squaredBase = squaredBase.mul(squaredBase).shrn(SCALE_OFFSET);
if (!exp.and(new (0, _bnjs2.default)(8)).isZero()) {
result = result.mul(squaredBase).shrn(SCALE_OFFSET);
}
squaredBase = squaredBase.mul(squaredBase).shrn(SCALE_OFFSET);
if (!exp.and(new (0, _bnjs2.default)(16)).isZero()) {
result = result.mul(squaredBase).shrn(SCALE_OFFSET);
}
squaredBase = squaredBase.mul(squaredBase).shrn(SCALE_OFFSET);
if (!exp.and(new (0, _bnjs2.default)(32)).isZero()) {
result = result.mul(squaredBase).shrn(SCALE_OFFSET);
}
squaredBase = squaredBase.mul(squaredBase).shrn(SCALE_OFFSET);
if (!exp.and(new (0, _bnjs2.default)(64)).isZero()) {
result = result.mul(squaredBase).shrn(SCALE_OFFSET);
}
squaredBase = squaredBase.mul(squaredBase).shrn(SCALE_OFFSET);
if (!exp.and(new (0, _bnjs2.default)(128)).isZero()) {
result = result.mul(squaredBase).shrn(SCALE_OFFSET);
}
squaredBase = squaredBase.mul(squaredBase).shrn(SCALE_OFFSET);
if (!exp.and(new (0, _bnjs2.default)(256)).isZero()) {
result = result.mul(squaredBase).shrn(SCALE_OFFSET);
}
squaredBase = squaredBase.mul(squaredBase).shrn(SCALE_OFFSET);
if (!exp.and(new (0, _bnjs2.default)(512)).isZero()) {
result = result.mul(squaredBase).shrn(SCALE_OFFSET);
}
squaredBase = squaredBase.mul(squaredBase).shrn(SCALE_OFFSET);
if (!exp.and(new (0, _bnjs2.default)(1024)).isZero()) {
result = result.mul(squaredBase).shrn(SCALE_OFFSET);
}
squaredBase = squaredBase.mul(squaredBase).shrn(SCALE_OFFSET);
if (!exp.and(new (0, _bnjs2.default)(2048)).isZero()) {
result = result.mul(squaredBase).shrn(SCALE_OFFSET);
}
squaredBase = squaredBase.mul(squaredBase).shrn(SCALE_OFFSET);
if (!exp.and(new (0, _bnjs2.default)(4096)).isZero()) {
result = result.mul(squaredBase).shrn(SCALE_OFFSET);
}
squaredBase = squaredBase.mul(squaredBase).shrn(SCALE_OFFSET);
if (!exp.and(new (0, _bnjs2.default)(8192)).isZero()) {
result = result.mul(squaredBase).shrn(SCALE_OFFSET);
}
squaredBase = squaredBase.mul(squaredBase).shrn(SCALE_OFFSET);
if (!exp.and(new (0, _bnjs2.default)(16384)).isZero()) {
result = result.mul(squaredBase).shrn(SCALE_OFFSET);
}
squaredBase = squaredBase.mul(squaredBase).shrn(SCALE_OFFSET);
if (!exp.and(new (0, _bnjs2.default)(32768)).isZero()) {
result = result.mul(squaredBase).shrn(SCALE_OFFSET);
}
squaredBase = squaredBase.mul(squaredBase).shrn(SCALE_OFFSET);
if (!exp.and(new (0, _bnjs2.default)(65536)).isZero()) {
result = result.mul(squaredBase).shrn(SCALE_OFFSET);
}
squaredBase = squaredBase.mul(squaredBase).shrn(SCALE_OFFSET);
if (!exp.and(new (0, _bnjs2.default)(131072)).isZero()) {
result = result.mul(squaredBase).shrn(SCALE_OFFSET);
}
squaredBase = squaredBase.mul(squaredBase).shrn(SCALE_OFFSET);
if (!exp.and(new (0, _bnjs2.default)(262144)).isZero()) {
result = result.mul(squaredBase).shrn(SCALE_OFFSET);
}
if (result.isZero()) {
return new (0, _bnjs2.default)(0);
}
if (invert) {
result = MAX.div(result);
}
return result;
}
// src/dlmm/helpers/weight.ts
var _gaussian = require('gaussian'); var _gaussian2 = _interopRequireDefault(_gaussian);
// src/dlmm/helpers/weightToAmounts.ts
// src/dlmm/helpers/token_2022.ts
async function getMultipleMintsExtraAccountMetasForTransferHook(connection, mintAddressesWithAccountInfo) {
const extraAccountMetas = await Promise.all(
mintAddressesWithAccountInfo.map(
({ mintAddress, mintAccountInfo }) => getExtraAccountMetasForTransferHook(
connection,
mintAddress,
mintAccountInfo
)
)
);
const mintsWithHookAccountMap = /* @__PURE__ */ new Map();
for (let i = 0; i < extraAccountMetas.length; i++) {
const { mintAddress } = mintAddressesWithAccountInfo[i];
const transferHooks = extraAccountMetas[i];
mintsWithHookAccountMap.set(mintAddress.toBase58(), transferHooks);
}
return mintsWithHookAccountMap;
}
async function getExtraAccountMetasForTransferHook(connection, mintAddress, mintAccountInfo) {
if (![_spltoken.TOKEN_PROGRAM_ID.toBase58(), _spltoken.TOKEN_2022_PROGRAM_ID.toBase58()].includes(
mintAccountInfo.owner.toBase58()
)) {
return [];
}
const mintState = _spltoken.unpackMint.call(void 0,
mintAddress,
mintAccountInfo,
mintAccountInfo.owner
);
if (mintAccountInfo.owner.equals(_spltoken.TOKEN_PROGRAM_ID)) {
return [];
}
const transferHook = _spltoken.getTransferHook.call(void 0, mintState);
if (!transferHook || transferHook.programId.equals(_web3js.PublicKey.default)) {
return [];
} else {
const instruction = _spltoken.createTransferCheckedInstruction.call(void 0,
_web3js.PublicKey.default,
mintAddress,
_web3js.PublicKey.default,
_web3js.PublicKey.default,
BigInt(0),
mintState.decimals,
[],
mintAccountInfo.owner
);
await _spltoken.addExtraAccountMetasForExecute.call(void 0,
connection,
instruction,
transferHook.programId,
_web3js.PublicKey.default,
mintAddress,
_web3js.PublicKey.default,
_web3js.PublicKey.default,
BigInt(0)
);
const transferHookAccounts = instruction.keys.slice(4);
if (transferHookAccounts.length == 0) {
transferHookAccounts.push({
pubkey: transferHook.programId,
isSigner: false,
isWritable: false
});
}
return transferHookAccounts;
}
}
function calculatePreFeeAmount(transferFee, postFeeAmount) {
if (postFeeAmount.isZero()) {
return new (0, _bnjs2.default)(0);
}
if (transferFee.transferFeeBasisPoints === 0) {
return postFeeAmount;
}
const maximumFee = new (0, _bnjs2.default)(transferFee.maximumFee.toString());
if (transferFee.transferFeeBasisPoints === _spltoken.MAX_FEE_BASIS_POINTS) {
return postFeeAmount.add(maximumFee);
}
const ONE_IN_BASIS_POINTS = new (0, _bnjs2.default)(_spltoken.MAX_FEE_BASIS_POINTS);
const numerator = postFeeAmount.mul(ONE_IN_BASIS_POINTS);
const denominator = ONE_IN_BASIS_POINTS.sub(
new (0, _bnjs2.default)(transferFee.transferFeeBasisPoints)
);
const rawPreFeeAmount = numerator.add(denominator).sub(new (0, _bnjs2.default)(1)).div(denominator);
if (rawPreFeeAmount.sub(postFeeAmount).gte(maximumFee)) {
return postFeeAmount.add(maximumFee);
}
return rawPreFeeAmount;
}
function calculateInverseFee(transferFee, postFeeAmount) {
const preFeeAmount = calculatePreFeeAmount(transferFee, postFeeAmount);
return new (0, _bnjs2.default)(
_spltoken.calculateFee.call(void 0, transferFee, BigInt(preFeeAmount.toString())).toString()
);
}
function calculateTransferFeeIncludedAmount(transferFeeExcludedAmount, mint, currentEpoch) {
if (transferFeeExcludedAmount.isZero()) {
return {
amount: new (0, _bnjs2.default)(0),
transferFee: new (0, _bnjs2.default)(0)
};
}
const transferFeeConfig = _spltoken.getTransferFeeConfig.call(void 0, mint);
if (transferFeeConfig === null) {
return {
amount: transferFeeExcludedAmount,
transferFee: new (0, _bnjs2.default)(0)
};
}
const epochFee = _spltoken.getEpochFee.call(void 0, transferFeeConfig, BigInt(currentEpoch));
const transferFee = epochFee.transferFeeBasisPoints == _spltoken.MAX_FEE_BASIS_POINTS ? new (0, _bnjs2.default)(epochFee.maximumFee.toString()) : calculateInverseFee(epochFee, transferFeeExcludedAmount);
const transferFeeIncludedAmount = transferFeeExcludedAmount.add(transferFee);
return {
amount: transferFeeIncludedAmount,
transferFee
};
}
function calculateTransferFeeExcludedAmount(transferFeeIncludedAmount, mint, currentEpoch) {
const transferFeeConfig = _spltoken.getTransferFeeConfig.call(void 0, mint);
if (transferFeeConfig === null) {
return {
amount: transferFeeIncludedAmount,
transferFee: new (0, _bnjs2.default)(0)
};
}
const transferFeeIncludedAmountN = BigInt(
transferFeeIncludedAmount.toString()
);
const transferFee = _spltoken.calculateFee.call(void 0,
_spltoken.getEpochFee.call(void 0, transferFeeConfig, BigInt(currentEpoch)),
transferFeeIncludedAmountN
);
const transferFeeExcludedAmount = new (0, _bnjs2.default)(
(transferFeeIncludedAmountN - transferFee).toString()
);
return {
amount: transferFeeExcludedAmount,
transferFee: new (0, _bnjs2.default)(transferFee.toString())
};
}
// src/dlmm/helpers/weightToAmounts.ts
function toAmountBidSide(activeId, totalAmount, distributions, mintY, clock) {
totalAmount = calculateTransferFeeExcludedAmount(
totalAmount,
mintY,
clock.epoch.toNumber()
).amount;
const totalWeight = distributions.reduce(function(sum, el) {
return el.binId > activeId ? sum : sum.add(el.weight);
}, new (0, _decimaljs2.default)(0));
if (totalWeight.cmp(new (0, _decimaljs2.default)(0)) != 1) {
throw Error("Invalid parameteres");
}
return distributions.map((bin) => {
if (bin.binId > activeId) {
return {
binId: bin.binId,
amount: new (0, _anchor.BN)(0)
};
} else {
return {
binId: bin.binId,
amount: new (0, _anchor.BN)(
new (0, _decimaljs2.default)(totalAmount.toString()).mul(new (0, _decimaljs2.default)(bin.weight).div(totalWeight)).floor().toString()
)
};
}
});
}
function toAmountAskSide(activeId, binStep, totalAmount, distributions, mintX, clock) {
totalAmount = calculateTransferFeeExcludedAmount(
totalAmount,
mintX,
clock.epoch.toNumber()
).amount;
const totalWeight = distributions.reduce(function(sum, el) {
if (el.binId < activeId) {
return sum;
} else {
const price = getPriceOfBinByBinId(el.binId, binStep);
const weightPerPrice = new (0, _decimaljs2.default)(el.weight).div(price);
return sum.add(weightPerPrice);
}
}, new (0, _decimaljs2.default)(0));
if (totalWeight.cmp(new (0, _decimaljs2.default)(0)) != 1) {
throw Error("Invalid parameteres");
}
return distributions.map((bin) => {
if (bin.binId < activeId) {
return {
binId: bin.binId,
amount: new (0, _anchor.BN)(0)
};
} else {
const price = getPriceOfBinByBinId(bin.binId, binStep);
const weightPerPrice = new (0, _decimaljs2.default)(bin.weight).div(price);
return {
binId: bin.binId,
amount: new (0, _anchor.BN)(
new (0, _decimaljs2.default)(totalAmount.toString()).mul(weightPerPrice).div(totalWeight).floor().toString()
)
};
}
});
}
function toAmountBothSide(activeId, binStep, amountX, amountY, amountXInActiveBin, amountYInActiveBin, distributions, mintX, mintY, clock) {
if (activeId > distributions[distributions.length - 1].binId) {
let amounts = toAmountBidSide(
activeId,
amountY,
distributions,
mintY,
clock
);
return amounts.map((bin) => {
return {
binId: bin.binId,
amountX: new (0, _anchor.BN)(0),
amountY: bin.amount
};
});
}
if (activeId < distributions[0].binId) {
let amounts = toAmountAskSide(
activeId,
binStep,
amountX,
distributions,
mintX,
clock
);
return amounts.map((bin) => {
return {
binId: bin.binId,
amountX: bin.amount,
amountY: new (0, _anchor.BN)(0)
};
});
}
amountX = calculateTransferFeeIncludedAmount(
amountX,
mintX,
clock.epoch.toNumber()
).amount;
amountY = calculateTransferFeeIncludedAmount(
amountY,
mintY,
clock.epoch.toNumber()
).amount;
const activeBins = distributions.filter((element) => {
return element.binId === activeId;
});
if (activeBins.length === 1) {
const p0 = getPriceOfBinByBinId(activeId, binStep);
let wx0 = new (0, _decimaljs2.default)(0);
let wy0 = new (0, _decimaljs2.default)(0);
const activeBin = activeBins[0];
if (amountXInActiveBin.isZero() && amountYInActiveBin.isZero()) {
wx0 = new (0, _decimaljs2.default)(activeBin.weight).div(p0.mul(new (0, _decimaljs2.default)(2)));
wy0 = new (0, _decimaljs2.default)(activeBin.weight).div(new (0, _decimaljs2.default)(2));
} else {
let amountXInActiveBinDec = new (0, _decimaljs2.default)(amountXInActiveBin.toString());
let amountYInActiveBinDec = new (0, _decimaljs2.default)(amountYInActiveBin.toString());
if (!amountXInActiveBin.isZero()) {
wx0 = new (0, _decimaljs2.default)(activeBin.weight).div(
p0.add(amountYInActiveBinDec.div(amountXInActiveBinDec))
);
}
if (!amountYInActiveBin.isZero()) {
wy0 = new (0, _decimaljs2.default)(activeBin.weight).div(
new (0, _decimaljs2.default)(1).add(
p0.mul(amountXInActiveBinDec).div(amountYInActiveBinDec)
)
);
}
}
let totalWeightX = wx0;
let totalWeightY = wy0;
distributions.forEach((element) => {
if (element.binId < activeId) {
totalWeightY = totalWeightY.add(new (0, _decimaljs2.default)(element.weight));
}
if (element.binId > activeId) {
let price = getPriceOfBinByBinId(element.binId, binStep);
let weighPerPrice = new (0, _decimaljs2.default)(element.weight).div(price);
totalWeightX = totalWeightX.add(weighPerPrice);
}
});
const kx = new (0, _decimaljs2.default)(amountX.toString()).div(totalWeightX);
const ky = new (0, _decimaljs2.default)(amountY.toString()).div(totalWeightY);
let k = kx.lessThan(ky) ? kx : ky;
return distributions.map((bin) => {
if (bin.binId < activeId) {
const amount = k.mul(new (0, _decimaljs2.default)(bin.weight));
return {
binId: bin.binId,
amountX: new (0, _anchor.BN)(0),
amountY: new (0, _anchor.BN)(amount.floor().toString())
};
}
if (bin.binId > activeId) {
const price = getPriceOfBinByBinId(bin.binId, binStep);
const weighPerPrice = new (0, _decimaljs2.default)(bin.weight).div(price);
const amount = k.mul(weighPerPrice);
return {
binId: bin.binId,
amountX: new (0, _anchor.BN)(amount.floor().toString()),
amountY: new (0, _anchor.BN)(0)
};
}
const amountXActiveBin = k.mul(wx0);
const amountYActiveBin = k.mul(wy0);
return {
binId: bin.binId,
amountX: new (0, _anchor.BN)(amountXActiveBin.floor().toString()),
amountY: new (0, _anchor.BN)(amountYActiveBin.floor().toString())
};
});
} else {
let totalWeightX = new (0, _decimaljs2.default)(0);
let totalWeightY = new (0, _decimaljs2.default)(0);
distributions.forEach((element) => {
if (element.binId < activeId) {
totalWeightY = totalWeightY.add(new (0, _decimaljs2.default)(element.weight));
} else {
let price = getPriceOfBinByBinId(element.binId, binStep);
let weighPerPrice = new (0, _decimaljs2.default)(element.weight).div(price);
totalWeightX = totalWeightX.add(weighPerPrice);
}
});
let kx = new (0, _decimaljs2.default)(amountX.toString()).div(totalWeightX);
let ky = new (0, _decimaljs2.default)(amountY.toString()).div(totalWeightY);
let k = kx.lessThan(ky) ? kx : ky;
return distributions.map((bin) => {
if (bin.binId < activeId) {
const amount = k.mul(new (0, _decimaljs2.default)(bin.weight));
return {
binId: bin.binId,
amountX: new (0, _anchor.BN)(0),
amountY: new (0, _anchor.BN)(amount.floor().toString())
};
} else {
let price = getPriceOfBinByBinId(bin.binId, binStep);
let weighPerPrice = new (0, _decimaljs2.default)(bin.weight).div(price);
const amount = k.mul(weighPerPrice);
return {
binId: bin.binId,
amountX: new (0, _anchor.BN)(amount.floor().toString()),
amountY: new (0, _anchor.BN)(0)
};
}
});
}
}
function autoFillYByWeight(activeId, binStep, amountX, amountXInActiveBin, amountYInActiveBin, distributions) {
const activeBins = distributions.filter((element) => {
return element.binId === activeId;
});
if (activeBins.length === 1) {
const p0 = getPriceOfBinByBinId(activeId, binStep);
let wx0 = new (0, _decimaljs2.default)(0);
let wy0 = new (0, _decimaljs2.default)(0);
const activeBin = activeBins[0];
if (amountXInActiveBin.isZero() && amountYInActiveBin.isZero()) {
wx0 = new (0, _decimaljs2.default)(activeBin.weight).div(p0.mul(new (0, _decimaljs2.default)(2)));
wy0 = new (0, _decimaljs2.default)(activeBin.weight).div(new (0, _decimaljs2.default)(2));
} else {
let amountXInActiveBinDec = new (0, _decimaljs2.default)(amountXInActiveBin.toString());
let amountYInActiveBinDec = new (0, _decimaljs2.default)(amountYInActiveBin.toString());
if (!amountXInActiveBin.isZero()) {
wx0 = new (0, _decimaljs2.default)(activeBin.weight).div(
p0.add(amountYInActiveBinDec.div(amountXInActiveBinDec))
);
}
if (!amountYInActiveBin.isZero()) {
wy0 = new (0, _decimaljs2.default)(activeBin.weight).div(
new (0, _decimaljs2.default)(1).add(
p0.mul(amountXInActiveBinDec).div(amountYInActiveBinDec)
)
);
}
}
let totalWeightX = wx0;
let totalWeightY = wy0;
distributions.forEach((element) => {
if (element.binId < activeId) {
totalWeightY = totalWeightY.add(new (0, _decimaljs2.default)(element.weight));
}
if (element.binId > activeId) {
const price = getPriceOfBinByBinId(element.binId, binStep);
const weighPerPrice = new (0, _decimaljs2.default)(element.weight).div(price);
totalWeightX = totalWeightX.add(weighPerPrice);
}
});
const kx = totalWeightX.isZero() ? new (0, _decimaljs2.default)(1) : new (0, _decimaljs2.default)(amountX.toString()).div(totalWeightX);
const amountY = kx.mul(totalWeightY);
return new (0, _anchor.BN)(amountY.floor().toString());
} else {
let totalWeightX = new (0, _decimaljs2.default)(0);
let totalWeightY = new (0, _decimaljs2.default)(0);
distributions.forEach((element) => {
if (element.binId < activeId) {
totalWeightY = totalWeightY.add(new (0, _decimaljs2.default)(element.weight));
} else {
const price = getPriceOfBinByBinId(element.binId, binStep);
const weighPerPrice = new (0, _decimaljs2.default)(element.weight).div(price);
totalWeightX = totalWeightX.add(weighPerPrice);
}
});
const kx = totalWeightX.isZero() ? new (0, _decimaljs2.default)(1) : new (0, _decimaljs2.default)(amountX.toString()).div(totalWeightX);
const amountY = kx.mul(totalWeightY);
return new (0, _anchor.BN)(amountY.floor().toString());
}
}
function autoFillXByWeight(activeId, binStep, amountY, amountXInActiveBin, amountYInActiveBin, distributions) {
const activeBins = distributions.filter((element) => {
return element.binId === activeId;
});
if (activeBins.length === 1) {
const p0 = getPriceOfBinByBinId(activeId, binStep);
let wx0 = new (0, _decimaljs2.default)(0);
let wy0 = new (0, _decimaljs2.default)(0);
const activeBin = activeBins[0];
if (amountXInActiveBin.isZero() && amountYInActiveBin.isZero()) {
wx0 = new (0, _decimaljs2.default)(activeBin.weight).div(p0.mul(new (0, _decimaljs2.default)(2)));
wy0 = new (0, _decimaljs2.default)(activeBin.weight).div(new (0, _decimaljs2.default)(2));
} else {
let amountXInActiveBinDec = new (0, _decimaljs2.default)(amountXInActiveBin.toString());
let amountYInActiveBinDec = new (0, _decimaljs2.default)(amountYInActiveBin.toString());
if (!amountXInActiveBin.isZero()) {
wx0 = new (0, _decimaljs2.default)(activeBin.weight).div(
p0.add(amountYInActiveBinDec.div(amountXInActiveBinDec))
);
}
if (!amountYInActiveBin.isZero()) {
wy0 = new (0, _decimaljs2.default)(activeBin.weight).div(
new (0, _decimaljs2.default)(1).add(
p0.mul(amountXInActiveBinDec).div(amountYInActiveBinDec)
)
);
}
}
let totalWeightX = wx0;
let totalWeightY = wy0;
distributions.forEach((element) => {
if (element.binId < activeId) {
totalWeightY = totalWeightY.add(new (0, _decimaljs2.default)(element.weight));
}
if (element.binId > activeId) {
const price = getPriceOfBinByBinId(element.binId, binStep);
const weighPerPrice = new (0, _decimaljs2.default)(element.weight).div(price);
totalWeightX = totalWeightX.add(weighPerPrice);
}
});
const ky = totalWeightY.isZero() ? new (0, _decimaljs2.default)(1) : new (0, _decimaljs2.default)(amountY.toString()).div(totalWeightY);
const amountX = ky.mul(totalWeightX);
return new (0, _anchor.BN)(amountX.floor().toString());
} else {
let totalWeightX = new (0, _decimaljs2.default)(0);
let totalWeightY = new (0, _decimaljs2.default)(0);
distributions.forEach((element) => {
if (element.binId < activeId) {
totalWeightY = totalWeightY.add(new (0, _decimaljs2.default)(element.weight));
} else {
const price = getPriceOfBinByBinId(element.binId, binStep);
const weighPerPrice = new (0, _decimaljs2.default)(element.weight).div(price);
totalWeightX = totalWeightX.add(weighPerPrice);
}
});
const ky = totalWeightY.isZero() ? new (0, _decimaljs2.default)(1) : new (0, _decimaljs2.default)(amountY.toString()).div(totalWeightY);
const amountX = ky.mul(totalWeightX);
return new (0, _anchor.BN)(amountX.floor().toString());
}
}
// src/dlmm/helpers/weight.ts
function getPriceOfBinByBinId(binId, binStep) {
const binStepNum = new (0, _decimaljs2.default)(binStep).div(new (0, _decimaljs2.default)(BASIS_POINT_MAX));
return new (0, _decimaljs2.default)(1).add(new (0, _decimaljs2.default)(binStepNum)).pow(new (0, _decimaljs2.default)(binId));
}
function buildGaussianFromBins(activeBin, binIds) {
const smallestBin = Math.min(...binIds);
const largestBin = Math.max(...binIds);
let mean = 0;
const isAroundActiveBin = binIds.find((bid) => bid == activeBin);
if (isAroundActiveBin) {
mean = activeBin;
} else if (activeBin < smallestBin) {
mean = smallestBin;
} else {
mean = largestBin;
}
const TWO_STANDARD_DEVIATION = 4;
const stdDev = (largestBin - smallestBin) / TWO_STANDARD_DEVIATION;
const variance = Math.max(stdDev ** 2, 1);
return _gaussian2.default.call(void 0, mean, variance);
}
function generateBinLiquidityAllocation(gaussian2, binIds, invert) {
const allocations = binIds.map(
(bid) => invert ? 1 / gaussian2.pdf(bid) : gaussian2.pdf(bid)
);
const totalAllocations = allocations.reduce((acc, v) => acc + v, 0);
return allocations.map((a) => a / totalAllocations);
}
function computeAllocationBps(allocations) {
let totalAllocation = new (0, _anchor.BN)(0);
const bpsAllocations = [];
for (const allocation of allocations) {
const allocBps = new (0, _anchor.BN)(allocation * 1e4);
bpsAllocations.push(allocBps);
totalAllocation = totalAllocation.add(allocBps);
}
const pLoss = new (0, _anchor.BN)(1e4).sub(totalAllocation);
return {
bpsAllocations,
pLoss
};
}
function toWeightDistribution(amountX, amountY, distributions, binStep) {
let totalQuote = new (0, _anchor.BN)(0);
const precision = 1e12;
const quoteDistributions = distributions.map((bin) => {
const price = new (0, _anchor.BN)(
getPriceOfBinByBinId(bin.binId, binStep).mul(precision).floor().toString()
);
const quoteValue = amountX.mul(new (0, _anchor.BN)(bin.xAmountBpsOfTotal)).mul(new (0, _anchor.BN)(price)).div(new (0, _anchor.BN)(BASIS_POINT_MAX)).div(new (0, _anchor.BN)(precision));
const quoteAmount = quoteValue.add(
amountY.mul(new (0, _anchor.BN)(bin.yAmountBpsOfTotal)).div(new (0, _anchor.BN)(BASIS_POINT_MAX))
);
totalQuote = totalQuote.add(quoteAmount);
return {
binId: bin.binId,
quoteAmount
};
});
if (totalQuote.eq(new (0, _anchor.BN)(0))) {
return [];
}
const distributionWeights = quoteDistributions.map((bin) => {
const weight = Math.floor(
bin.quoteAmount.mul(new (0, _anchor.BN)(65535)).div(totalQuote).toNumber()
);
return {
binId: bin.binId,
weight
};
}).filter((item) => item.weight > 0);
return distributionWeights;
}
function calculateSpotDistribution(activeBin, binIds) {
if (!binIds.includes(activeBin)) {
const { div: dist, mod: rem } = new (0, _anchor.BN)(1e4).divmod(
new (0, _anchor.BN)(binIds.length)
);
const loss = rem.isZero() ? new (0, _anchor.BN)(0) : new (0, _anchor.BN)(1);
const distributions = binIds[0] < activeBin ? binIds.map((binId) => ({
binId,
xAmountBpsOfTotal: new (0, _anchor.BN)(0),
yAmountBpsOfTotal: dist
})) : binIds.map((binId) => ({
binId,
xAmountBpsOfTotal: dist,
yAmountBpsOfTotal: new (0, _anchor.BN)(0)
}));
if (binIds[0] < activeBin) {
distributions[0].yAmountBpsOfTotal.add(loss);
} else {
distributions[binIds.length - 1].xAmountBpsOfTotal.add(loss);
}
return distributions;
}
const binYCount = binIds.filter((binId) => binId < activeBin).length;
const binXCount = binIds.filter((binId) => binId > activeBin).length;
const totalYBinCapacity = binYCount + 0.5;
const totalXBinCapacity = binXCount + 0.5;
const yBinBps = new (0, _anchor.BN)(1e4 / totalYBinCapacity);
const yActiveBinBps = new (0, _anchor.BN)(1e4).sub(yBinBps.mul(new (0, _anchor.BN)(binYCount)));
const xBinBps = new (0, _anchor.BN)(1e4 / totalXBinCapacity);
const xActiveBinBps = new (0, _anchor.BN)(1e4).sub(xBinBps.mul(new (0, _anchor.BN)(binXCount)));
return binIds.map((binId) => {
const isYBin = binId < activeBin;
const isXBin = binId > activeBin;
const isActiveBin = binId === activeBin;
if (isYBin) {
return {
binId,
xAmountBpsOfTotal: new (0, _anchor.BN)(0),
yAmountBpsOfTotal: yBinBps
};
}
if (isXBin) {
return {
binId,
xAmountBpsOfTotal: xBinBps,
yAmountBpsOfTotal: new (0, _anchor.BN)(0)
};
}
if (isActiveBin) {
return {
binId,
xAmountBpsOfTotal: xActiveBinBps,
yAmountBpsOfTotal: yActiveBinBps
};
}
});
}
function calculateBidAskDistribution(activeBin, binIds) {
const smallestBin = Math.min(...binIds);
const largestBin = Math.max(...binIds);
const rightOnly = activeBin < smallestBin;
const leftOnly = activeBin > largestBin;
const gaussian2 = buildGaussianFromBins(activeBin, binIds);
const allocations = generateBinLiquidityAllocation(gaussian2, binIds, true);
if (rightOnly) {
const { bpsAllocations, pLoss } = computeAllocationBps(allocations);
const binDistributions = binIds.map((bid, idx2) => ({
binId: bid,
xAmountBpsOfTotal: bpsAllocations[idx2],
yAmountBpsOfTotal: new (0, _anchor.BN)(0)
}));
const idx = binDistributions.length - 1;
binDistributions[idx].xAmountBpsOfTotal = binDistributions[idx].xAmountBpsOfTotal.add(pLoss);
return binDistributions;
}
if (leftOnly) {
const { bpsAllocations, pLoss } = computeAllocationBps(allocations);
const binDistributions = binIds.map((bid, idx) => ({
binId: bid,
xAmountBpsOfTotal: new (0, _anchor.BN)(0),
yAmountBpsOfTotal: bpsAllocations[idx]
}));
binDistributions[0].yAmountBpsOfTotal = binDistributions[0].yAmountBpsOfTotal.add(pLoss);
return binDistributions;
}
const [totalXAllocation, totalYAllocation] = allocations.reduce(
([xAcc, yAcc], allocation, idx) => {
const binId = binIds[idx];
if (binId > activeBin) {
return [xAcc + allocation, yAcc];
} else if (binId < activeBin) {
return [xAcc, yAcc + allocation];
} else {
const half = allocation / 2;
return [xAcc + half, yAcc + half];
}
},
[0, 0]
);
const [normXAllocations, normYAllocations] = allocations.reduce(
([xAllocations, yAllocations], allocation, idx) => {
const binId = binIds[idx];
if (binId > activeBin) {
const distX = new (0, _anchor.BN)(allocation * 1e4 / totalXAllocation);
xAllocations.push(distX);
}
if (binId < activeBin) {
const distY = new (0, _anchor.BN)(allocation * 1e4 / totalYAllocation);
yAllocations.push(distY);
}
if (binId == activeBin) {
const half = allocation / 2;
const distX = new (0, _anchor.BN)(half * 1e4 / totalXAllocation);
const distY = new (0, _anchor.BN)(half * 1e4 / totalYAllocation);
xAllocations.push(distX);
yAllocations.push(distY);
}
return [xAllocations, yAllocations];
},
[[], []]
);
const totalXNormAllocations = normXAllocations.reduce(
(acc, v) => acc.add(v),
new (0, _anchor.BN)(0)
);
const totalYNormAllocations = normYAllocations.reduce(
(acc, v) => acc.add(v),
new (0, _anchor.BN)(0)
);
const xPLoss = new (0, _anchor.BN)(1e4).sub(totalXNormAllocations);
const yPLoss = new (0, _anchor.BN)(1e4).sub(totalYNormAllocations);
const distributions = binIds.map((binId) => {
if (binId === activeBin) {
return {
binId,
xAmountBpsOfTotal: normXAllocations.shift(),
yAmountBpsOfTotal: normYAllocations.shift()
};
}
if (binId > activeBin) {
return {
binId,
xAmountBpsOfTotal: normXAllocations.shift(),
yAmountBpsOfTotal: new (0, _anchor.BN)(0)
};
}
if (binId < activeBin) {
return {
binId,
xAmountBpsOfTotal: new (0, _anchor.BN)(0),
yAmountBpsOfTotal: normYAllocations.shift()
};
}
});
if (!yPLoss.isZero()) {
distributions[0].yAmountBpsOfTotal = distributions[0].yAmountBpsOfTotal.add(yPLoss);
}
if (!xPLoss.isZero()) {
const last = distributions.length - 1;
distributions[last].xAmountBpsOfTotal = distributions[last].xAmountBpsOfTotal.add(xPLoss);
}
return distributions;
}
function calculateNormalDistribution(activeBin, binIds) {
const smallestBin = Math.min(...binIds);
const largestBin = Math.max(...binIds);
const rightOnly = activeBin < smallestBin;
const leftOnly = activeBin > largestBin;
const gaussian2 = buildGaussianFromBins(activeBin, binIds);
const allocations = generateBinLiquidityAllocation(gaussian2, binIds, false);
if (rightOnly) {
const { bpsAllocations, pLoss } = computeAllocationBps(allocations);
const binDistributions = binIds.map((bid, idx) => ({
binId: bid,
xAmountBpsOfTotal: bpsAllocations[idx],
yAmountBpsOfTotal: new (0, _anchor.BN)(0)
}));
binDistributions[0].xAmountBpsOfTotal = binDistributions[0].xAmountBpsOfTotal.add(pLoss);
return binDistributions;
}
if (leftOnly) {
const { bpsAllocations, pLoss } = computeAllocationBps(allocations);
const binDistributions = binIds.map((bid, idx2) => ({
binId: bid,
xAmountBpsOfTotal: new (0, _anchor.BN)(0),
yAmountBpsOfTotal: bpsAllocations[idx2]
}));
const idx = binDistributions.length - 1;
binDistributions[idx].yAmountBpsOfTotal = binDistributions[idx].yAmountBpsOfTotal.add(pLoss);
return binDistributions;
}
const [totalXAllocation, totalYAllocation] = allocations.reduce(
([xAcc, yAcc], allocation, idx) => {
const binId = binIds[idx];
if (binId > activeBin) {
return [xAcc + allocation, yAcc];
} else if (binId < activeBin) {
return [xAcc, yAcc + allocation];
} else {
const half = allocation / 2;
return [xAcc + half, yAcc + half];
}
},
[0, 0]
);
const [normXAllocations, normYAllocations] = allocations.reduce(
([xAllocations, yAllocations], allocation, idx) => {
const binId = binIds[idx];
if (binId > activeBin) {
const distX = new (0, _anchor.BN)(allocation * 1e4 / totalXAllocation);
xAllocations.push(distX);
}
if (binId < activeBin) {
const distY = new (0, _anchor.BN)(allocation * 1e4 / totalYAllocation);
yAllocations.push(distY);
}
return [xAllocations, yAllocations];
},
[[], []]
);
const normXActiveBinAllocation = normXAllocations.reduce(
(maxBps, bps) => maxBps.sub(bps),
new (0, _anchor.BN)(1e4)
);
const normYActiveBinAllocation = normYAllocations.reduce(
(maxBps, bps) => maxBps.sub(bps),
new (0, _anchor.BN)(1e4)
);
return binIds.map((binId) => {
if (binId === activeBin) {
return {
binId,
xAmountBpsOfTotal: normXActiveBinAllocation,
yAmountBpsOfTotal: normYActiveBinAllocation
};
}
if (binId > activeBin) {
return {
binId,
xAmountBpsOfTotal: normXAllocations.shift(),
yAmountBpsOfTotal: new (0, _anchor.BN)(0)
};
}
if (binId < activeBin) {
return {
binId,
xAmountBpsOfTotal: new (0, _anchor.BN)(0),
yAmountBpsOfTotal: normYAllocations.shift()
};
}
});
}
function fromWeightDistributionToAmountOneSide(amount, distributions, binStep, activeId, depositForY, mint, clock) {
if (depositForY) {
return toAmountBidSide(activeId, amount, distributions, mint, clock);
} else {
return toAmountAskSide(
activeId,
binStep,
amount,
distributions,
mint,
clock
);
}
}
function fromWeightDistributionToAmount(amountX, amountY, distributions, binStep, activeId, amountXInActiveBin, amountYInActiveBin, mintX, mintY, clock) {
var distributions = distributions.sort((n1, n2) => {
return n1.binId - n2.binId;
});
if (distributions.length == 0) {
return [];
}
if (activeId > distributions[distributions.length - 1].binId) {
let amounts = toAmountBidSide(
activeId,
amountY,
distributions,
mintY,
clock
);
return amounts.map((bin) => {
return {
binId: bin.binId,
amountX: new (0, _anchor.BN)(0),
amountY: new (0, _anchor.BN)(bin.amount.toString())
};
});
}
if (activeId < distributions[0].binId) {
let amounts = toAmountAskSide(
activeId,
binStep,
amountX,
distributions,
mintX,
clock
);
return amounts.map((bin) => {
return {
binId: bin.binId,
amountX: new (0, _anchor.BN)(bin.amount.toString()),
amountY: new (0, _anchor.BN)(0)
};
});
}
return toAmountBothSide(
activeId,
binStep,
amountX,
amountY,
amountXInActiveBin,
amountYInActiveBin,
distributions,
mintX,
mintY,
clock
);
}
// src/dlmm/helpers/math.ts
var Rounding = /* @__PURE__ */ ((Rounding2) => {
Rounding2[Rounding2["Up"] = 0] = "Up";
Rounding2[Rounding2["Down"] = 1] = "Down";
return Rounding2;
})(Rounding || {});
function mulShr(x, y, offset, rounding) {
const denominator = new (0, _anchor.BN)(1).shln(offset);
return mulDiv(x, y, denominator, rounding);
}
function shlDiv(x, y, offset, rounding) {
const scale = new (0, _anchor.BN)(1).shln(offset);
return mulDiv(x, scale, y, rounding);
}
function mulDiv(x, y, denominator, rounding) {
const { div, mod } = x.mul(y).divmod(denominator);
if (rounding == 0 /* Up */ && !mod.isZero()) {
return div.add(new (0, _anchor.BN)(1));
}
return div;
}
function computeBaseFactorFromFeeBps(binStep, feeBps) {
const U16_MAX = 65535;
const computedBaseFactor = feeBps.toNumber() * BASIS_POINT_MAX / binStep.toNumber();
if (computedBaseFactor > U16_MAX) {
let truncatedBaseFactor = computedBaseFactor;
let base_power_factor = 0;
while (truncatedBaseFactor > U16_MAX) {
const remainder = truncatedBaseFactor % 10;
if (remainder == 0) {
base_power_factor += 1;
truncatedBaseFactor /= 10;
} else {
throw "have decimals";
}
}
return [new (0, _anchor.BN)(truncatedBaseFactor), new (0, _anchor.BN)(base_power_factor)];
} else {
const computedBaseFactorFloor = Math.floor(computedBaseFactor);
if (computedBaseFactor != computedBaseFactorFloor) {
if (computedBaseFactorFloor >= U16_MAX) {
throw "base factor for the give fee bps overflow u16";
}
if (computedBaseFactorFloor == 0) {
throw "base factor for the give fee bps underflow";
}
if (computedBaseFactor % 1 != 0) {
throw "couldn't compute base factor for the exact fee bps";
}
}
return [new (0, _anchor.BN)(computedBaseFactor), new (0, _anchor.BN)(0)];
}
}
function getQPriceFromId(binId, binStep) {
return pow(getQPriceBaseFactor(binStep), binId);
}
function getQPriceBaseFactor(binStep) {
const bps = binStep.shln(SCALE_OFFSET).div(new (0, _anchor.BN)(BASIS_POINT_MAX));
const base = ONE.add(bps);
return base;
}
function getC(amount, binStep, binId, baseTokenDecimal, quoteTokenDecimal, minPrice, maxPrice, k) {
const currentPricePerLamport = new (0, _decimaljs2.default)(1 + binStep / 1e4).pow(
binId.toNumber()
);
const currentPricePerToken = currentPricePerLamport.mul(
new (0, _decimaljs2.default)(10 ** (baseTokenDecimal - quoteTokenDecimal))
);
const priceRange = maxPrice.sub(minPrice);
const currentPriceDeltaFromMin = currentPricePerToken.sub(
new (0, _decimaljs2.default)(minPrice)
);
const c = new (0, _decimaljs2.default)(amount.toString()).mul(
currentPriceDeltaFromMin.div(priceRange).pow(k)
);
return c.floor();
}
function distributeAmountToCompressedBinsByRatio(compressedBinAmount, uncompressedAmount, multiplier, binCapAmount) {
const newCompressedBinAmount = /* @__PURE__ */ new Map();
let totalCompressedAmount = new (0, _anchor.BN)(0);
for (const compressedAmount of compressedBinAmount.values()) {
totalCompressedAmount = totalCompressedAmount.add(compressedAmount);
}
let totalDepositedAmount = new (0, _anchor.BN)(0);
for (const [binId, compressedAmount] of compressedBinAmount.entries()) {
const depositAmount = compressedAmount.mul(uncompressedAmount).div(totalCompressedAmount);
let compressedDepositAmount = depositAmount.div(multiplier);
let newCompressedAmount = compressedAmount.add(compressedDepositAmount);
if (newCompressedAmount.gt(binCapAmount)) {
compressedDepositAmount = compressedDepositAmount.sub(
newCompressedAmount.sub(binCapAmount)
);
newCompressedAmount = binCapAmount;
}
newCompressedBinAmount.set(binId, newCompressedAmount);
totalDepositedAmount = totalDepositedAmount.add(
compressedDepositAmount.mul(multiplier)
);
}
const loss = uncompressedAmount.sub(totalDepositedAmount);
return {
newCompressedBinAmount,
loss
};
}
function getPositionCount(minBinId, maxBinId) {
const binDelta = maxBinId.sub(minBinId);
const positionCount = binDelta.div(DEFAULT_BIN_PER_POSITION);
return positionCount.add(new (0, _anchor.BN)(1));
}
function findOptimumDecompressMultiplier(binAmount, tokenDecimal) {
let multiplier = new (0, _anchor.BN)(10).pow(tokenDecimal);
while (!multiplier.isZero()) {
let found = true;
for (const [_binId, amount] of binAmount) {
const compressedAmount = amount.div(multiplier);
if (compressedAmount.isZero()) {
multiplier = multiplier.div(new (0, _anchor.BN)(10));
found = false;
break;
}
}
if (found) {
return multiplier;
}
}
throw "Couldn't find optimum multiplier";
}
function compressBinAmount(binAmount, multiplier) {
const compressedBinAmount = /* @__PURE__ */ new Map();
let totalAmount = new (0, _anchor.BN)(0);
let compressionLoss = new (0, _anchor.BN)(0);
for (const [binId, amount] of binAmount) {
totalAmount = totalAmount.add(amount);
const compressedAmount = amount.div(multiplier);
compressedBinAmount.set(binId, compressedAmount);
let loss = amount.sub(compressedAmount.mul(multiplier));
compressionLoss = compressionLoss.add(loss);
}
return {
compressedBinAmount,
compressionLoss
};
}
function generateAmountForBinRange(amount, binStep, tokenXDecimal, tokenYDecimal, minBinId, maxBinId, k) {
const toTokenMultiplier = new (0, _decimaljs2.default)(10 ** (tokenXDecimal - tokenYDecimal));
const minPrice = getPriceOfBinByBinId(minBinId.toNumber(), binStep).mul(
toTokenMultiplier
);
const maxPrice = getPriceOfBinByBinId(maxBinId.toNumber(), binStep).mul(
toTokenMultiplier
);
const binAmounts = /* @__PURE__ */ new Map();
for (let i = minBinId.toNumber(); i < maxBinId.toNumber(); i++) {
const binAmount = generateBinAmount(
amount,
binStep,
new (0, _anchor.BN)(i),
tokenXDecimal,
tokenYDecimal,
minPrice,
maxPrice,
k
);
if (binAmount.isZero()) {
throw "bin amount is zero";
}
binAmounts.set(i, binAmount);
}
return binAmounts;
}
function generateBinAmount(amount, binStep, binId, tokenXDecimal, tokenYDecimal, minPrice, maxPrice, k) {
const c1 = getC(
amount,
binStep,
binId.add(new (0, _anchor.BN)(1)),
tokenXDecimal,
tokenYDecimal,
minPrice,
maxPrice,
k
);
const c0 = getC(
amount,
binStep,
binId,
tokenXDecimal,
tokenYDecimal,
minPrice,
maxPrice,
k
);
return new (0, _anchor.BN)(c1.sub(c0).floor().toString());
}
// src/dlmm/helpers/positions/index.ts
// src/dlmm/helpers/positions/wrapper.ts
function combineBaseAndExtendedPositionBinData(base, extended) {
const combinedLiquidityShares = base.liquidityShares;
const combinedRewardInfos = base.rewardInfos;
const combinedFeeInfos = base.feeInfos;
for (const binData of extended) {
combinedLiquidityShares.push(binData.liquidityShare);
combinedRewardInfos.push(binData.rewardInfo);
combinedFeeInfos.push(binData.feeInfo);
}
return {
liquidityShares: combinedLiquidityShares,
rewardInfos: combinedRewardInfos,
feeInfos: combinedFeeInfos
};
}
function wrapPosition(program, key, account) {
const disc = account.data.subarray(0, 8);
if (disc.equals(Buffer.from(getAccountDiscriminator("positionV2")))) {
const state = decodeAccount(
program,
"positionV2",
account.data
);
const extended = decodeExtendedPosition(
state,
program,
account.data.subarray(8 + POSITION_MIN_SIZE)
);
const combinedPositionBinData = combineBaseAndExtendedPositionBinData(
state,
extended
);
return new PositionV2Wrapper(key, state, extended, combinedPositionBinData);
} else {
throw new Error("Unknown position account");
}
}
var PositionV2Wrapper = class {
constructor(positionAddress, inner, extended, combinedPositionBinData) {
this.positionAddress = positionAddress;
this.inner = inner;
this.extended = extended;
this.combinedPositionBinData = combinedPositionBinData;
}
address() {
return this.positionAddress;
}
totalClaimedRewards() {
return this.inner.totalClaimedRewards;
}
feeOwner() {
return this.inner.feeOwner;
}
lockReleasePoint() {
return this.inner.lockReleasePoint;
}
operator() {
return this.inner.operator;
}
totalClaimedFeeYAmount() {
return this.inner.totalClaimedFeeYAmount;
}
totalClaimedFeeXAmount() {
return this.inner.totalClaimedFeeXAmount;
}
lbPair() {
return this.inner.lbPair;
}
lowerBinId() {
return new (0, _bnjs2.default)(this.inner.lowerBinId);
}
upperBinId() {
return new (0, _bnjs2.default)(this.inner.upperBinId);
}
liquidityShares() {
return this.combinedPositionBinData.liquidityShares;
}
rewardInfos() {
return this.combinedPositionBinData.rewardInfos;
}
feeInfos() {
return this.combinedPositionBinData.feeInfos;
}
lastUpdatedAt() {
return this.inner.lastUpdatedAt;
}
getBinArrayIndexesCoverage() {
const isExtended = this.extended.length > 0;
if (isExtended) {
return getBinArrayIndexesCoverage(this.lowerBinId(), this.upperBinId());
} else {
const lowerBinArrayIndex = binIdToBinArrayIndex(this.lowerBinId());
const upperBinArrayIndex = lowerBinArrayIndex.add(new (0, _bnjs2.default)(1));
return [lowerBinArrayIndex, upperBinArrayIndex];
}
}
getBinArrayKeysCoverage(programId) {
return this.getBinArrayIndexesCoverage().map(
(index) => deriveBinArray(this.lbPair(), index, programId)[0]
);
}
version() {
return 1 /* V2 */;
}
owner() {
return this.inner.owner;
}
width() {
return this.upperBinId().sub(this.lowerBinId()).add(new (0, _bnjs2.default)(1));
}
};
// src/dlmm/helpers/positions/index.ts
function getBinArrayIndexesCoverage(lowerBinId, upperBinId) {
const lowerBinArrayIndex = binIdToBinArrayIndex(lowerBinId);
const upperBinArrayIndex = binIdToBinArrayIndex(upperBinId);
const binArrayIndexes = [];
for (let i = lowerBinArrayIndex.toNumber(); i <= upperBinArrayIndex.toNumber(); i++) {
binArrayIndexes.push(new (0, _bnjs2.default)(i));
}
return binArrayIndexes;
}
function getBinArrayKeysCoverage(lowerBinId, upperBinId, lbPair, programId) {
const binArrayIndexes = getBinArrayIndexesCoverage(lowerBinId, upperBinId);
return binArrayIndexes.map((index) => {
return deriveBinArray(lbPair, index, programId)[0];
});
}
function getBinArrayAccountMetasCoverage(lowerBinId, upperBinId, lbPair, programId) {
return getBinArrayKeysCoverage(lowerBinId, upperBinId, lbPair, programId).map(
(key) => {
return {
pubkey: key,
isSigner: false,
isWritable: true
};
}
);
}
function getPositionLowerUpperBinIdWithLiquidity(position) {
const binWithLiquidity = position.positionBinData.filter(
(b) => !new (0, _bnjs2.default)(b.binLiquidity).isZero() || !new (0, _bnjs2.default)(b.positionFeeXAmount.toString()).isZero() || !new (0, _bnjs2.default)(b.positionFeeYAmount.toString()).isZero() || !new (0, _bnjs2.default)(b.positionRewardAmount[0].toString()).isZero() || !new (0, _bnjs2.default)(b.positionRewardAmount[1].toString()).isZero()
);
return binWithLiquidity.length > 0 ? {
lowerBinId: new (0, _bnjs2.default)(binWithLiquidity[0].binId),
upperBinId: new (0, _bnjs2.default)(binWithLiquidity[binWithLiquidity.length - 1].binId)
} : null;
}
function isPositionNoFee(position) {
return position.feeX.isZero() && position.feeY.isZero();
}
function isPositionNoReward(position) {
return position.rewardOne.isZero() && position.rewardTwo.isZero();
}
function chunkBinRangeIntoExtendedPositions(minBinId, maxBinId) {
const chunkedBinRange = [];
for (let currentMinBinId = minBinId; currentMinBinId <= maxBinId; currentMinBinId += POSITION_MAX_LENGTH.toNumber()) {
const currentMaxBinId = Math.min(
currentMinBinId + POSITION_MAX_LENGTH.toNumber() - 1,
maxBinId
);
chunkedBinRange.push({
lowerBinId: currentMinBinId,
upperBinId: currentMaxBinId
});
}
return chunkedBinRange;
}
function chunkBinRange(minBinId, maxBinId, binPerChunk) {
const chunkedBinRange = [];
let startBinId = minBinId;
binPerChunk = _nullishCoalesce(binPerChunk, () => ( DEFAULT_BIN_PER_POSITION.toNumber()));
while (startBinId <= maxBinId) {
const endBinId = Math.min(startBinId + binPerChunk - 1, maxBinId);
chunkedBinRange.push({
lowerBinId: startBinId,
upperBinId: endBinId
});
startBinId += binPerChunk;
}
return chunkedBinRange;
}
function chunkPositionBinRange(position, minBinId, maxBinId) {
const chunkedFeesAndRewards = [];
let totalAmountX = new (0, _bnjs2.default)(0);
let totalAmountY = new (0, _bnjs2.default)(0);
let totalFeeXAmount = new (0, _bnjs2.default)(0);
let totalFeeYAmount = new (0, _bnjs2.default)(0);
let totalRewardAmounts = [new (0, _bnjs2.default)(0), new (0, _bnjs2.default)(0)];
let count = 0;
for (let i = 0; i < position.positionData.positionBinData.length; i++) {
const positionBinData = position.positionData.positionBinData[i];
if (positionBinData.binId >= minBinId && positionBinData.binId <= maxBinId) {
totalFeeXAmount = totalFeeXAmount.add(
new (0, _bnjs2.default)(positionBinData.positionFeeXAmount)
);
totalFeeYAmount = totalFeeYAmount.add(
new (0, _bnjs2.default)(positionBinData.positionFeeYAmount)
);
totalAmountX = totalAmountX.add(new (0, _bnjs2.default)(positionBinData.positionXAmount));
totalAmountY = totalAmountY.add(new (0, _bnjs2.default)(positionBinData.positionYAmount));
for (const [
index,
reward
] of positionBinData.positionRewardAmount.entries()) {
totalRewardAmounts[index] = totalRewardAmounts[index].add(
new (0, _bnjs2.default)(reward)
);
}
count++;
}
if (count === DEFAULT_BIN_PER_POSITION.toNumber() || positionBinData.binId == maxBinId) {
chunkedFeesAndRewards.push({
minBinId: positionBinData.binId - count + 1,
maxBinId: positionBinData.binId,
feeXAmount: totalFeeXAmount,
feeYAmount: totalFeeYAmount,
rewardAmounts: totalRewardAmounts,
amountX: totalAmountX,
amountY: totalAmountY
});
totalFeeXAmount = new (0, _bnjs2.default)(0);
totalFeeYAmount = new (0, _bnjs2.default)(0);
totalAmountX = new (0, _bnjs2.default)(0);
totalAmountY = new (0, _bnjs2.default)(0);
totalRewardAmounts = [new (0, _bnjs2.default)(0), new (0, _bnjs2.default)(0)];
count = 0;
}
}
return chunkedFeesAndRewards;
}
function calculatePositionSize(binCount) {
const extraBinCount = binCount.gt(DEFAULT_BIN_PER_POSITION) ? binCount.sub(DEFAULT_BIN_PER_POSITION) : new (0, _bnjs2.default)(0);
return new (0, _bnjs2.default)(POSITION_MIN_SIZE).add(
extraBinCount.mul(new (0, _bnjs2.default)(POSITION_BIN_DATA_SIZE))
);
}
function getPositionRentExemption(connection, binCount) {
const size = calculatePositionSize(binCount);
return connection.getMinimumBalanceForRentExemption(size.toNumber());
}
async function getPositionExpandRentExemption(currentMinBinId, currentMaxBinId, connection, binCountToExpand) {
const currentPositionWidth = currentMaxBinId.sub(currentMinBinId).addn(1);
const positionWidthAfterExpand = currentPositionWidth.add(binCountToExpand);
if (positionWidthAfterExpand.lte(DEFAULT_BIN_PER_POSITION)) {
return 0;
} else {
const binCountInExpandedBytes = positionWidthAfterExpand.sub(
DEFAULT_BIN_PER_POSITION
);
const expandSize = binCountInExpandedBytes.toNumber() * POSITION_BIN_DATA_SIZE;
const [minimumLamports, rentExemptionLamports] = await Promise.all([
connection.getMinimumBalanceForRentExemption(0),
connection.getMinimumBalanceForRentExemption(expandSize)
]);
return rentExemptionLamports - minimumLamports;
}
}
function getExtendedPositionBinCount(minBinId, maxBinId) {
const width = maxBinId.sub(minBinId).addn(1);
const extended = width.sub(DEFAULT_BIN_PER_POSITION);
return extended.lte(new (0, _bnjs2.default)(0)) ? new (0, _bnjs2.default)(0) : extended;
}
function decodeExtendedPosition(base, program, bytes) {
const width = base.upperBinId - base.lowerBinId + 1;
const extendedWidth = width - DEFAULT_BIN_PER_POSITION.toNumber();
const extendedPosition = [];
for (let i = 0; i < extendedWidth; i++) {
const offset = i * POSITION_BIN_DATA_SIZE;
const data = bytes.subarray(offset, offset + POSITION_BIN_DATA_SIZE);
const decodedPositionBinData = program.coder.types.decode(
// TODO: Find a type safe way
"positionBinData",
data
);
extendedPosition.push(decodedPositionBinData);
}
return extendedPosition;
}
// src/dlmm/helpers/binArray.ts
function internalBitmapRange() {
const lowerBinArrayIndex = BIN_ARRAY_BITMAP_SIZE.neg();
const upperBinArrayIndex = BIN_ARRAY_BITMAP_SIZE.sub(new (0, _anchor.BN)(1));
return [lowerBinArrayIndex, upperBinArrayIndex];
}
function buildBitmapFromU64Arrays(u64Arrays, type) {
const buffer = Buffer.concat(
u64Arrays.map((b) => {
return b.toArrayLike(Buffer, "le", 8);
})
);
return new (0, _anchor.BN)(buffer, "le");
}
function bitmapTypeDetail(type) {
if (type == 0 /* U1024 */) {
return {
bits: 1024,
bytes: 1024 / 8
};
} else {
return {
bits: 512,
bytes: 512 / 8
};
}
}
function mostSignificantBit(number, bitLength) {
const highestIndex = bitLength - 1;
if (number.isZero()) {
return null;
}
for (let i = highestIndex; i >= 0; i--) {
if (number.testn(i)) {
return highestIndex - i;
}
}
return null;
}
function leastSignificantBit(number, bitLength) {
if (number.isZero()) {
return null;
}
for (let i = 0; i < bitLength; i++) {
if (number.testn(i)) {
return i;
}
}
return null;
}
function extensionBitmapRange() {
return [
BIN_ARRAY_BITMAP_SIZE.neg().mul(
EXTENSION_BINARRAY_BITMAP_SIZE.add(new (0, _anchor.BN)(1))
),
BIN_ARRAY_BITMAP_SIZE.mul(
EXTENSION_BINARRAY_BITMAP_SIZE.add(new (0, _anchor.BN)(1))
).sub(new (0, _anchor.BN)(1))
];
}
function findSetBit(startIndex, endIndex, binArrayBitmapExtension) {
const getBinArrayOffset = (binArrayIndex) => {
return binArrayIndex.gt(new (0, _anchor.BN)(0)) ? binArrayIndex.mod(BIN_ARRAY_BITMAP_SIZE) : binArrayIndex.add(new (0, _anchor.BN)(1)).neg().mod(BIN_ARRAY_BITMAP_SIZE);
};
const getBitmapOffset = (binArrayIndex) => {
return binArrayIndex.gt(new (0, _anchor.BN)(0)) ? binArrayIndex.div(BIN_ARRAY_BITMAP_SIZE).sub(new (0, _anchor.BN)(1)) : binArrayIndex.add(new (0, _anchor.BN)(1)).neg().div(BIN_ARRAY_BITMAP_SIZE).sub(new (0, _anchor.BN)(1));
};
if (startIndex <= endIndex) {
for (let i = startIndex; i <= endIndex; i++) {
const binArrayOffset = getBinArrayOffset(new (0, _anchor.BN)(i)).toNumber();
const bitmapOffset = getBitmapOffset(new (0, _anchor.BN)(i)).toNumber();
const bitmapChunks = i > 0 ? binArrayBitmapExtension.positiveBinArrayBitmap[bitmapOffset] : binArrayBitmapExtension.negativeBinArrayBitmap[bitmapOffset];
const bitmap = buildBitmapFromU64Arrays(bitmapChunks, 1 /* U512 */);
if (bitmap.testn(binArrayOffset)) {
return i;
}
}
} else {
for (let i = startIndex; i >= endIndex; i--) {
const binArrayOffset = getBinArrayOffset(new (0, _anchor.BN)(i)).toNumber();
const bitmapOffset = getBitmapOffset(new (0, _anchor.BN)(i)).toNumber();
const bitmapChunks = i > 0 ? binArrayBitmapExtension.positiveBinArrayBitmap[bitmapOffset] : binArrayBitmapExtension.negativeBinArrayBitmap[bitmapOffset];
const bitmap = buildBitmapFromU64Arrays(bitmapChunks, 1 /* U512 */);
if (bitmap.testn(binArrayOffset)) {
return i;
}
}
}
return null;
}
function isOverflowDefaultBinArrayBitmap(binArrayIndex) {
const [minBinArrayIndex, maxBinArrayIndex] = internalBitmapRange();
return binArrayIndex.gt(maxBinArrayIndex) || binArrayIndex.lt(minBinArrayIndex);
}
function deriveBinArrayBitmapExtension(lbPair, programId) {
return _web3js.PublicKey.findProgramAddressSync(
[Buffer.from("bitmap"), lbPair.toBytes()],
programId
);
}
function binIdToBinArrayIndex(binId) {
const { div: idx, mod } = binId.divmod(MAX_BIN_ARRAY_SIZE);
return binId.isNeg() && !mod.isZero() ? idx.sub(new (0, _anchor.BN)(1)) : idx;
}
function getBinArrayLowerUpperBinId(binArrayIndex) {
const lowerBinId = binArrayIndex.mul(MAX_BIN_ARRAY_SIZE);
const upperBinId = lowerBinId.add(MAX_BIN_ARRAY_SIZE).sub(new (0, _anchor.BN)(1));
return [lowerBinId, upperBinId];
}
function isBinIdWithinBinArray(activeId, binArrayIndex) {
const [lowerBinId, upperBinId] = getBinArrayLowerUpperBinId(binArrayIndex);
return activeId.gte(lowerBinId) && activeId.lte(upperBinId);
}
function getBinFromBinArray(binId, binArray) {
const [lowerBinId, upperBinId] = getBinArrayLowerUpperBinId(binArray.index);
let index = 0;
if (binId > 0) {
index = binId - lowerBinId.toNumber();
} else {
const delta = upperBinId.toNumber() - binId;
index = MAX_BIN_ARRAY_SIZE.toNumber() - delta - 1;
}
return binArray.bins[index];
}
function findNextBinArrayIndexWithLiquidity(swapForY, activeId, lbPairState, binArrayBitmapExtension) {
const [lowerBinArrayIndex, upperBinArrayIndex] = internalBitmapRange();
let startBinArrayIndex = binIdToBinArrayIndex(activeId);
while (true) {
if (isOverflowDefaultBinArrayBitmap(startBinArrayIndex)) {
if (binArrayBitmapExtension === null) {
return null;
}
const [minBinArrayIndex, maxBinArrayIndex] = extensionBitmapRange();
if (startBinArrayIndex.isNeg()) {
if (swapForY) {
const binArrayIndex = findSetBit(
startBinArrayIndex.toNumber(),
minBinArrayIndex.toNumber(),
binArrayBitmapExtension
);
if (binArrayIndex !== null) {
return new (0, _anchor.BN)(binArrayIndex);
} else {
return null;
}
} else {
const binArrayIndex = findSetBit(
startBinArrayIndex.toNumber(),
BIN_ARRAY_BITMAP_SIZE.neg().sub(new (0, _anchor.BN)(1)).toNumber(),
binArrayBitmapExtension
);
if (binArrayIndex !== null) {
return new (0, _anchor.BN)(binArrayIndex);
} else {
startBinArrayIndex = BIN_ARRAY_BITMAP_SIZE.neg();
}
}
} else {
if (swapForY) {
const binArrayIndex = findSetBit(
startBinArrayIndex.toNumber(),
BIN_ARRAY_BITMAP_SIZE.toNumber(),
binArrayBitmapExtension
);
if (binArrayIndex !== null) {
return new (0, _anchor.BN)(binArrayIndex);
} else {
startBinArrayIndex = BIN_ARRAY_BITMAP_SIZE.sub(new (0, _anchor.BN)(1));
}
} else {
const binArrayIndex = findSetBit(
startBinArrayIndex.toNumber(),
maxBinArrayIndex.toNumber(),
binArrayBitmapExtension
);
if (binArrayIndex !== null) {
return new (0, _anchor.BN)(binArrayIndex);
} else {
return null;
}
}
}
} else {
const bitmapType = 0 /* U1024 */;
const bitmapDetail = bitmapTypeDetail(bitmapType);
const offset = startBinArrayIndex.add(BIN_ARRAY_BITMAP_SIZE);
const bitmap = buildBitmapFromU64Arrays(
lbPairState.binArrayBitmap,
bitmapType
);
if (swapForY) {
const upperBitRange = new (0, _anchor.BN)(bitmapDetail.bits - 1).sub(offset);
const croppedBitmap = bitmap.shln(upperBitRange.toNumber());
const msb = mostSignificantBit(croppedBitmap, bitmapDetail.bits);
if (msb !== null) {
return startBinArrayIndex.sub(new (0, _anchor.BN)(msb));
} else {
startBinArrayIndex = lowerBinArrayIndex.sub(new (0, _anchor.BN)(1));
}
} else {
const lowerBitRange = offset;
const croppedBitmap = bitmap.shrn(lowerBitRange.toNumber());
const lsb = leastSignificantBit(croppedBitmap, bitmapDetail.bits);
if (lsb !== null) {
return startBinArrayIndex.add(new (0, _anchor.BN)(lsb));
} else {
startBinArrayIndex = upperBinArrayIndex.add(new (0, _anchor.BN)(1));
}
}
}
}
}
function findNextBinArrayWithLiquidity(swapForY, activeBinId, lbPairState, binArrayBitmapExtension, binArrays) {
const nearestBinArrayIndexWithLiquidity = findNextBinArrayIndexWithLiquidity(
swapForY,
activeBinId,
lbPairState,
binArrayBitmapExtension
);
if (nearestBinArrayIndexWithLiquidity == null) {
return null;
}
const binArrayAccount = binArrays.find(
(ba) => ba.account.index.eq(nearestBinArrayIndexWithLiquidity)
);
if (!binArrayAccount) {
return null;
}
return binArrayAccount;
}
function getBinArraysRequiredByPositionRange(pair, fromBinId, toBinId, programId) {
const [minBinId, maxBinId] = fromBinId.lt(toBinId) ? [fromBinId, toBinId] : [toBinId, fromBinId];
const positionCount = getPositionCount(minBinId, maxBinId);
const binArrays = /* @__PURE__ */ new Map();
for (let i = 0; i < positionCount.toNumber(); i++) {
const lowerBinId = minBinId.add(DEFAULT_BIN_PER_POSITION.mul(new (0, _anchor.BN)(i)));
const lowerBinArrayIndex = binIdToBinArrayIndex(lowerBinId);
const upperBinArrayIndex = lowerBinArrayIndex.add(new (0, _anchor.BN)(1));
const [lowerBinArray] = deriveBinArray(pair, lowerBinArrayIndex, programId);
const [upperBinArray] = deriveBinArray(pair, upperBinArrayIndex, programId);
binArrays.set(lowerBinArray.toBase58(), lowerBinArrayIndex);
binArrays.set(upperBinArray.toBase58(), upperBinArrayIndex);
}
return Array.from(binArrays, ([key, index]) => ({
key: new (0, _web3js.PublicKey)(key),
index
}));
}
function getBinArraysRequiredByPositionRange2(pair, fromBinId, toBinId, programId) {
const [minBinId, maxBinId] = fromBinId.lt(toBinId) ? [fromBinId, toBinId] : [toBinId, fromBinId];
const binArrayIndexes = getBinArrayIndexesCoverage(minBinId, maxBinId);
return Array.from(binArrayIndexes, (index) => {
const [binArrayPubkey] = deriveBinArray(pair, index, programId);
return {
key: binArrayPubkey,
index
};
});
}
function* enumerateBins(binsById, lowerBinId, upperBinId, binStep, baseTokenDecimal, quoteTokenDecimal, version, lbPair) {
for (let currentBinId = lowerBinId; currentBinId <= upperBinId; currentBinId++) {
const bin = binsById.get(currentBinId);
if (bin != null) {
yield BinLiquidity.fromBin(
bin,
currentBinId,
binStep,
baseTokenDecimal,
quoteTokenDecimal,
version,
lbPair
);
} else {
yield BinLiquidity.empty(
currentBinId,
binStep,
baseTokenDecimal,
quoteTokenDecimal,
version
);
}
}
}
function getBinIdIndexInBinArray(binId, lowerBinId, upperBinId) {
if (binId.lt(lowerBinId) || binId.gt(upperBinId)) {
return null;
}
return binId.sub(lowerBinId);
}
function binDeltaToMinMaxBinId(binDelta, activeBinId) {
const minBinId = activeBinId - binDelta;
const maxBinId = minBinId + binDelta * 2;
return {
minBinId,
maxBinId
};
}
function decodeRewardPerTokenStored(bin) {
const rewardPerTokenStored0Buf0 = bin.fulfilledOrderAmountX.toArrayLike(
Buffer,
"le",
8
);
const rewardPerTokenStored0Buf1 = bin.fulfilledOrderAmountY.toArrayLike(
Buffer,
"le",
8
);
const rewardPerTokenStored0 = new (0, _anchor.BN)(
Buffer.concat([rewardPerTokenStored0Buf0, rewardPerTokenStored0Buf1]),
"le"
);
const rewardPerTokenStored1Buf0 = bin.limitOrderFeeAskSide.toArrayLike(
Buffer,
"le",
8
);
const rewardPerTokenStored1Buf1 = bin.limitOrderFeeBidSide.toArrayLike(
Buffer,
"le",
8
);
const rewardPerTokenStored1 = new (0, _anchor.BN)(
Buffer.concat([rewardPerTokenStored1Buf0, rewardPerTokenStored1Buf1]),
"le"
);
return [rewardPerTokenStored0, rewardPerTokenStored1];
}
function getBinArrayInfoForNonContiguousBinIds(binIds, programId, lbPair) {
let binArrayBitmapExtension = programId;
const binArrayIndexes = /* @__PURE__ */ new Set();
for (const binId of binIds) {
const binArrayIndex = binIdToBinArrayIndex(new (0, _anchor.BN)(binId));
if (isOverflowDefaultBinArrayBitmap(binArrayIndex) && binArrayBitmapExtension.equals(programId)) {
binArrayBitmapExtension = deriveBinArrayBitmapExtension(
lbPair,
programId
)[0];
}
binArrayIndexes.add(binArrayIndex.toNumber());
}
const binArrayPubkeys = [...binArrayIndexes].map(
(idx) => deriveBinArray(lbPair, new (0, _anchor.BN)(idx), programId)[0]
);
const binArrayAccountMetas = binArrayPubkeys.map((pubkey) => {
return {
pubkey,
isSigner: false,
isWritable: true
};
});
return {
binArrayAccountMetas,
binArrayBitmapExtension,
binArrayIndexes: [...binArrayIndexes].map((idx) => new (0, _anchor.BN)(idx))
};
}
// src/dlmm/helpers/computeUnit.ts
var DEFAULT_ADD_LIQUIDITY_CU = 1e6;
var DEFAULT_EXTEND_POSITION_HIGH_CU = 1e6;
var DEFAULT_EXTEND_POSITION_LOW_CU = 3e4;
var DEFAULT_INIT_POSITION_CU = 3e4;
var DEFAULT_INIT_BIN_ARRAY_CU = 35e4;
var MIN_CU_BUFFER = 5e4;
var MAX_CU_BUFFER = 2e5;
var MAX_CU = 14e5;
var getDefaultExtendPositionCU = (side) => {
switch (side) {
case 0 /* Lower */:
return DEFAULT_EXTEND_POSITION_HIGH_CU;
case 1 /* Upper */:
return DEFAULT_EXTEND_POSITION_LOW_CU;
}
};
var getSimulationComputeUnits = async (connection, instructions, payer, lookupTables, commitment = "confirmed") => {
const testInstructions = [
// Set an arbitrarily high number in simulation
// so we can be sure the transaction will succeed
// and get the real compute units used
_web3js.ComputeBudgetProgram.setComputeUnitLimit({ units: 14e5 }),
...instructions
];
const testTransaction = new (0, _web3js.VersionedTransaction)(
new (0, _web3js.TransactionMessage)({
instructions: testInstructions,
payerKey: payer,
// RecentBlockhash can by any public key during simulation
// since 'replaceRecentBlockhash' is set to 'true' below
recentBlockhash: _web3js.PublicKey.default.toString()
}).compileToV0Message(lookupTables)
);
const rpcResponse = await connection.simulateTransaction(testTransaction, {
replaceRecentBlockhash: true,
sigVerify: false,
commitment
});
if (_optionalChain([rpcResponse, 'optionalAccess', _45 => _45.value, 'optionalAccess', _46 => _46.err])) {
const logs = _optionalChain([rpcResponse, 'access', _47 => _47.value, 'access', _48 => _48.logs, 'optionalAccess', _49 => _49.join, 'call', _50 => _50("\n \u2022 ")]) || "No logs available";
throw new Error(
`Transaction simulation failed:
\u2022${logs}` + JSON.stringify(_optionalChain([rpcResponse, 'optionalAccess', _51 => _51.value, 'optionalAccess', _52 => _52.err]))
);
}
return rpcResponse.value.unitsConsumed || null;
};
// src/dlmm/helpers/rebalance/rebalancePosition.ts
// src/dlmm/helpers/fee.ts
function getBaseFee(binStep, sParameter) {
return new (0, _anchor.BN)(sParameter.baseFactor).mul(new (0, _anchor.BN)(binStep)).mul(new (0, _anchor.BN)(10)).mul(new (0, _anchor.BN)(10).pow(new (0, _anchor.BN)(sParameter.baseFeePowerFactor)));
}
function getVariableFee(binStep, sParameter, vParameter) {
if (sParameter.variableFeeControl > 0) {
const square_vfa_bin = new (0, _anchor.BN)(vParameter.volatilityAccumulator).mul(new (0, _anchor.BN)(binStep)).pow(new (0, _anchor.BN)(2));
const v_fee = new (0, _anchor.BN)(sParameter.variableFeeControl).mul(square_vfa_bin);
return v_fee.add(new (0, _anchor.BN)(99999999999)).div(new (0, _anchor.BN)(1e11));
}
return new (0, _anchor.BN)(0);
}
function getTotalFee(binStep, sParameter, vParameter) {
const totalFee = getBaseFee(binStep, sParameter).add(
getVariableFee(binStep, sParameter, vParameter)
);
return totalFee.gt(MAX_FEE_RATE) ? MAX_FEE_RATE : totalFee;
}
function computeFee(binStep, sParameter, vParameter, inAmount) {
const totalFee = getTotalFee(binStep, sParameter, vParameter);
const denominator = FEE_PRECISION.sub(totalFee);
return inAmount.mul(totalFee).add(denominator).sub(new (0, _anchor.BN)(1)).div(denominator);
}
function computeFeeFromAmount(binStep, sParameter, vParameter, inAmountWithFees) {
const totalFee = getTotalFee(binStep, sParameter, vParameter);
return inAmountWithFees.mul(totalFee).add(FEE_PRECISION.sub(new (0, _anchor.BN)(1))).div(FEE_PRECISION);
}
function computeProtocolFee(feeAmount, sParameter) {
return feeAmount.mul(new (0, _anchor.BN)(sParameter.protocolShare)).div(new (0, _anchor.BN)(BASIS_POINT_MAX));
}
function getExcludedFeeAmount(includedFeeAmount, tradeFeeNumerator) {
const tradingFee = includedFeeAmount.mul(tradeFeeNumerator).add(FEE_PRECISION.sub(new (0, _anchor.BN)(1))).div(FEE_PRECISION);
const excludedFeeAmount = includedFeeAmount.sub(tradingFee);
return {
excludedFeeAmount,
fee: tradingFee
};
}
function getIncludedFeeAmount(excludedFeeAmount, tradeFeeNumerator) {
const denominator = FEE_PRECISION.sub(tradeFeeNumerator);
const includedFeeAmount = excludedFeeAmount.mul(FEE_PRECISION).add(denominator.sub(new (0, _anchor.BN)(1))).div(denominator);
const fee = includedFeeAmount.sub(excludedFeeAmount);
return {
includedFeeAmount,
fee
};
}
function splitFee(tradingFee, protocolShare, mmAmountIn, totalAmountIn) {
if (totalAmountIn.isZero()) {
return {
fee: new (0, _anchor.BN)(0),
protocolFee: new (0, _anchor.BN)(0)
};
}
const mmFee = tradingFee.mul(mmAmountIn).add(totalAmountIn.sub(new (0, _anchor.BN)(1))).div(totalAmountIn);
const totalLoFee = tradingFee.sub(mmFee);
const loFee = totalLoFee.mul(LIMIT_ORDER_FEE_SHARE).div(new (0, _anchor.BN)(BASIS_POINT_MAX));
const loProtocolFee = totalLoFee.sub(loFee);
const mmProtocolFee = mmFee.mul(protocolShare).div(new (0, _anchor.BN)(BASIS_POINT_MAX));
const totalProtocolFee = loProtocolFee.add(mmProtocolFee);
const totalUserFee = tradingFee.sub(totalProtocolFee);
return {
fee: totalUserFee,
protocolFee: totalProtocolFee
};
}
// src/dlmm/helpers/rebalance/rebalancePosition.ts
function buildBitFlagAndNegateStrategyParameters(x0, y0, deltaX, deltaY) {
let bitFlag = 0;
if (x0.isNeg()) {
bitFlag |= 1;
x0 = x0.neg();
}
if (y0.isNeg()) {
bitFlag |= 2;
y0 = y0.neg();
}
if (deltaX.isNeg()) {
bitFlag |= 4;
deltaX = deltaX.neg();
}
if (deltaY.isNeg()) {
bitFlag |= 8;
deltaY = deltaY.neg();
}
return {
bitFlag,
x0,
y0,
deltaX,
deltaY
};
}
function toRebalancePositionBinData(positionData) {
return positionData.positionBinData.map(
({
binId,
price,
pricePerToken,
positionXAmount,
positionYAmount,
positionFeeXAmount,
positionFeeYAmount,
positionRewardAmount
}) => {
return {
binId,
price,
pricePerToken,
amountX: new (0, _bnjs2.default)(positionXAmount),
amountY: new (0, _bnjs2.default)(positionYAmount),
claimableRewardAmount: positionRewardAmount.map(
(amount) => new (0, _bnjs2.default)(amount)
),
claimableFeeXAmount: new (0, _bnjs2.default)(positionFeeXAmount),
claimableFeeYAmount: new (0, _bnjs2.default)(positionFeeYAmount)
};
}
);
}
function getDepositBinIds(activeId, deposits) {
const uniqueBinId = /* @__PURE__ */ new Set();
for (const { minDeltaId, maxDeltaId } of deposits) {
const minBinId = activeId.add(minDeltaId);
const maxBinId = activeId.add(maxDeltaId);
for (let binId = minBinId.toNumber(); binId <= maxBinId.toNumber(); binId++) {
uniqueBinId.add(binId);
}
}
const binIds = Array.from(uniqueBinId);
binIds.sort((a, b) => a - b);
return binIds;
}
function findMinMaxBinIdWithLiquidity(rebalancePositionBinData) {
let minBinId = null;
let maxBinId = null;
for (const binData of rebalancePositionBinData) {
if (binData.amountX.isZero() && binData.amountY.isZero() && binData.claimableFeeXAmount.isZero() && binData.claimableFeeYAmount.isZero() && binData.claimableRewardAmount.every((amount) => amount.isZero())) {
continue;
}
if (minBinId == null || binData.binId < minBinId) {
minBinId = binData.binId;
}
if (maxBinId == null || binData.binId > maxBinId) {
maxBinId = binData.binId;
}
}
return [minBinId, maxBinId];
}
function onlyDepositToBidSide(maxDeltaId, favorXInActiveBin) {
if (favorXInActiveBin) {
return maxDeltaId.lt(new (0, _bnjs2.default)(0));
}
return maxDeltaId.lte(new (0, _bnjs2.default)(0));
}
function onlyDepositToAskSide(minDeltaId, favorXInActiveBin) {
if (favorXInActiveBin) {
return minDeltaId.gte(new (0, _bnjs2.default)(0));
}
return minDeltaId.gt(new (0, _bnjs2.default)(0));
}
function getAmountInBinsBidSide(activeId, minDeltaId, maxDeltaId, deltaY, y0) {
const amountInBins = [];
const minBinId = activeId.add(minDeltaId);
const maxBinId = activeId.add(maxDeltaId);
for (let binId = minBinId.toNumber(); binId <= maxBinId.toNumber(); binId++) {
const deltaBin = activeId.toNumber() - binId;
const totalDeltaY = deltaY.mul(new (0, _bnjs2.default)(deltaBin));
const amountY = y0.add(totalDeltaY);
amountInBins.push({
binId: new (0, _bnjs2.default)(binId),
amountX: new (0, _bnjs2.default)(0),
amountY
});
}
return amountInBins;
}
function getAmountInBinsAskSide(activeId, binStep, minDeltaId, maxDeltaId, deltaX, x0) {
const binCount = maxDeltaId.sub(minDeltaId).add(new (0, _bnjs2.default)(1));
const minBinId = activeId.add(minDeltaId);
const maxBinId = activeId.add(maxDeltaId);
const amountInBins = new Array(binCount.toNumber());
const base = getQPriceBaseFactor(binStep);
let inverseBasePrice = pow(base, maxBinId.neg());
for (let binId = maxBinId.toNumber(); binId >= minBinId.toNumber(); binId--) {
const delta = binId - activeId.toNumber();
const totalDeltaX = deltaX.mul(new (0, _bnjs2.default)(delta));
const amountX = x0.add(totalDeltaX).mul(inverseBasePrice).shrn(SCALE_OFFSET);
const idx = binId - minBinId.toNumber();
amountInBins[idx] = {
binId: new (0, _bnjs2.default)(binId),
amountX,
amountY: new (0, _bnjs2.default)(0)
};
inverseBasePrice = inverseBasePrice.mul(base).shrn(SCALE_OFFSET);
}
return amountInBins;
}
function toAmountIntoBins(activeId, minDeltaId, maxDeltaId, deltaX, deltaY, x0, y0, binStep, favorXInActiveBin) {
if (onlyDepositToBidSide(maxDeltaId, favorXInActiveBin)) {
return getAmountInBinsBidSide(activeId, minDeltaId, maxDeltaId, deltaY, y0);
}
if (onlyDepositToAskSide(minDeltaId, favorXInActiveBin)) {
return getAmountInBinsAskSide(
activeId,
binStep,
minDeltaId,
maxDeltaId,
deltaX,
x0
);
}
const [bidSideEndDeltaId, askSideStartDeltaId] = favorXInActiveBin ? [-1, 0] : [0, 1];
const amountInBinsBidSide = getAmountInBinsBidSide(
activeId,
minDeltaId,
new (0, _bnjs2.default)(bidSideEndDeltaId),
deltaY,
y0
);
const amountInBinsAskSide = getAmountInBinsAskSide(
activeId,
binStep,
new (0, _bnjs2.default)(askSideStartDeltaId),
maxDeltaId,
deltaX,
x0
);
return amountInBinsBidSide.concat(amountInBinsAskSide);
}
function getLiquidity(x, y, price) {
const px = price.mul(x);
const shly = y.shln(SCALE_OFFSET);
return px.add(shly);
}
function computeCompositionFee(binStep, sParameters3, vParameters3, outAmountX, inAmountX, outAmountY, inAmountY) {
if (outAmountX.gt(inAmountX)) {
const delta = inAmountY.sub(outAmountY);
const totalFeeRate = getTotalFee(
binStep.toNumber(),
sParameters3,
vParameters3
);
const feeAmount = delta.mul(totalFeeRate);
return feeAmount.mul(FEE_PRECISION.add(totalFeeRate)).div(FEE_PRECISION.pow(new (0, _bnjs2.default)(2)));
}
return new (0, _bnjs2.default)(0);
}
function simulateDepositBin(binId, binStep, amountX, amountY, bin) {
if (!bin) {
return {
amountXIntoBin: amountX,
amountYIntoBin: amountY
};
}
const price = getQPriceFromId(binId, binStep);
const inLiquidity = getLiquidity(amountX, amountY, price);
const binLiquidity = getLiquidity(bin.amountX, bin.amountY, price);
if (bin.liquiditySupply.isZero()) {
return {
amountXIntoBin: amountX,
amountYIntoBin: amountY
};
}
const liquidityShare = inLiquidity.mul(bin.liquiditySupply).div(binLiquidity);
const updatedBinXAmount = bin.amountX.add(amountX);
const updatedBinYAmount = bin.amountY.add(amountY);
const updatedBinSupply = bin.liquiditySupply.add(liquidityShare);
let amountXIntoBin = liquidityShare.mul(
updatedBinXAmount.div(updatedBinSupply)
);
let amountYIntoBin = liquidityShare.mul(
updatedBinYAmount.div(updatedBinSupply)
);
if (amountXIntoBin.gt(amountX)) {
}
return {
amountXIntoBin,
amountYIntoBin
};
}
var RebalancePosition = class {
constructor(positionAddress, positionData, lbPair, activeBin, shouldClaimFee, shouldClaimReward, currentTimestamp) {
this.address = positionAddress;
this.rebalancePositionBinData = toRebalancePositionBinData(positionData);
this.lowerBinId = new (0, _bnjs2.default)(positionData.lowerBinId);
this.upperBinId = new (0, _bnjs2.default)(positionData.upperBinId);
this.lbPair = lbPair;
this.shouldClaimFee = shouldClaimFee;
this.shouldClaimReward = shouldClaimReward;
this.owner = positionData.owner;
this.activeBin = activeBin;
this.currentTimestamp = currentTimestamp;
}
static async create(params) {
const {
program,
positionAddress,
pairAddress,
positionData,
shouldClaimFee,
shouldClaimReward
} = params;
const [lbPairAccount, clockAccount] = await program.provider.connection.getMultipleAccountsInfo([
pairAddress,
_web3js.SYSVAR_CLOCK_PUBKEY
]);
const lbPair = decodeAccount(program, "lbPair", lbPairAccount.data);
const clock = ClockLayout.decode(clockAccount.data);
const activeBinArrayIdx = binIdToBinArrayIndex(new (0, _bnjs2.default)(lbPair.activeId));
const [activeBinArrayPubkey] = deriveBinArray(
pairAddress,
activeBinArrayIdx,
program.programId
);
const [lowerBinId, upperBinId] = getBinArrayLowerUpperBinId(activeBinArrayIdx);
const idx = getBinIdIndexInBinArray(
new (0, _bnjs2.default)(lbPair.activeId),
lowerBinId,
upperBinId
);
let activeBin = null;
try {
const activeBinArrayState = await program.account.binArray.fetch(activeBinArrayPubkey);
activeBin = activeBinArrayState[idx.toNumber()];
} catch (error) {
}
return new RebalancePosition(
positionAddress,
positionData,
lbPair,
activeBin,
shouldClaimFee,
shouldClaimReward,
clock.unixTimestamp
);
}
_simulateDeposit(binStep, tokenXDecimal, tokenYDecimal, deposits, simulatedWithdrawResult) {
const { liquidityAndFeeXWithdrawn, liquidityAndFeeYWithdrawn } = simulatedWithdrawResult;
const activeId = new (0, _bnjs2.default)(this.lbPair.activeId);
const depositBinIds = getDepositBinIds(activeId, deposits);
if (depositBinIds.length > 0) {
const depositMinBinId = depositBinIds[0];
const depositMaxBinId = depositBinIds[depositBinIds.length - 1];
this._simulateResize(
new (0, _bnjs2.default)(depositMinBinId),
new (0, _bnjs2.default)(depositMaxBinId),
binStep,
tokenXDecimal,
tokenYDecimal
);
}
let totalAmountXDeposited = new (0, _bnjs2.default)(0);
let totalAmountYDeposited = new (0, _bnjs2.default)(0);
const addLiquidityParam = [];
for (const {
x0,
y0,
favorXInActiveBin,
deltaX,
deltaY,
minDeltaId,
maxDeltaId
} of deposits) {
const params = buildBitFlagAndNegateStrategyParameters(
x0,
y0,
deltaX,
deltaY
);
addLiquidityParam.push({
minDeltaId: minDeltaId.toNumber(),
maxDeltaId: maxDeltaId.toNumber(),
x0: params.x0,
y0: params.y0,
deltaX: params.deltaX,
deltaY: params.deltaY,
bitFlag: params.bitFlag,
padding: Array(16).fill(0),
favorXInActiveId: favorXInActiveBin
});
const amountIntoBins = toAmountIntoBins(
activeId,
minDeltaId,
maxDeltaId,
deltaX,
deltaY,
x0,
y0,
binStep,
favorXInActiveBin
);
for (const { binId, amountX, amountY } of amountIntoBins) {
totalAmountXDeposited = totalAmountXDeposited.add(amountX);
totalAmountYDeposited = totalAmountYDeposited.add(amountY);
const idx = this.rebalancePositionBinData.findIndex(
(data) => data.binId == binId.toNumber()
);
if (binId.eq(activeId)) {
const vParameters3 = Object.assign({}, this.lbPair.vParameters);
const sParameters3 = Object.assign({}, this.lbPair.parameters);
DLMM.updateReference(
activeId.toNumber(),
vParameters3,
sParameters3,
this.currentTimestamp.toNumber()
);
DLMM.updateVolatilityAccumulator(
vParameters3,
sParameters3,
activeId.toNumber()
);
const { amountXIntoBin, amountYIntoBin } = simulateDepositBin(
binId,
binStep,
amountX,
amountY,
this.activeBin
);
const feeY = computeCompositionFee(
binStep,
sParameters3,
vParameters3,
amountXIntoBin,
amountX,
amountYIntoBin,
amountY
);
const feeX = computeCompositionFee(
binStep,
sParameters3,
vParameters3,
amountYIntoBin,
amountY,
amountXIntoBin,
amountX
);
const amountXIntoBinExcludeFee = amountXIntoBin.sub(feeX);
const amountYIntoBinExcludeFee = amountYIntoBin.sub(feeY);
this.rebalancePositionBinData[idx].amountX = this.rebalancePositionBinData[idx].amountX.add(
amountXIntoBinExcludeFee
);
this.rebalancePositionBinData[idx].amountY = this.rebalancePositionBinData[idx].amountY.add(
amountYIntoBinExcludeFee
);
} else {
this.rebalancePositionBinData[idx].amountX = this.rebalancePositionBinData[idx].amountX.add(amountX);
this.rebalancePositionBinData[idx].amountY = this.rebalancePositionBinData[idx].amountY.add(amountY);
}
}
}
let actualTotalAmountXDeposited = totalAmountXDeposited;
let actualTotalAmountYDeposited = totalAmountYDeposited;
let actualLiquidityAndFeeXWithdrawn = liquidityAndFeeXWithdrawn;
let actualLiquidityAndFeeYWithdrawn = liquidityAndFeeYWithdrawn;
if (actualTotalAmountXDeposited.gt(actualLiquidityAndFeeXWithdrawn)) {
actualTotalAmountXDeposited = actualTotalAmountXDeposited.sub(
actualLiquidityAndFeeXWithdrawn
);
actualLiquidityAndFeeXWithdrawn = new (0, _bnjs2.default)(0);
} else {
actualLiquidityAndFeeXWithdrawn = actualLiquidityAndFeeXWithdrawn.sub(
actualTotalAmountXDeposited
);
actualTotalAmountXDeposited = new (0, _bnjs2.default)(0);
}
if (actualTotalAmountYDeposited.gt(actualLiquidityAndFeeYWithdrawn)) {
actualTotalAmountYDeposited = actualTotalAmountYDeposited.sub(
actualLiquidityAndFeeYWithdrawn
);
actualLiquidityAndFeeYWithdrawn = new (0, _bnjs2.default)(0);
} else {
actualLiquidityAndFeeYWithdrawn = actualLiquidityAndFeeYWithdrawn.sub(
actualTotalAmountYDeposited
);
actualTotalAmountYDeposited = new (0, _bnjs2.default)(0);
}
return {
result: {
totalAmountXDeposited,
totalAmountYDeposited,
actualLiquidityAndFeeXWithdrawn,
actualLiquidityAndFeeYWithdrawn,
actualTotalAmountXDeposited,
actualTotalAmountYDeposited
},
depositParams: addLiquidityParam
};
}
_simulateResize(depositMinBinId, depositMaxBinId, binStep, tokenXDecimal, tokenYDecimal) {
const tokenXMultiplier = new (0, _decimaljs2.default)(10 ** tokenXDecimal.toNumber());
const tokenYMultiplier = new (0, _decimaljs2.default)(10 ** tokenYDecimal.toNumber());
const [minBinId, maxBinId] = findMinMaxBinIdWithLiquidity(
this.rebalancePositionBinData
);
const newMinBinId = new (0, _bnjs2.default)(
Math.min(depositMinBinId.toNumber(), _nullishCoalesce(minBinId, () => ( Number.MAX_SAFE_INTEGER)))
);
const newMaxBinId = new (0, _bnjs2.default)(
Math.max(depositMaxBinId.toNumber(), _nullishCoalesce(maxBinId, () => ( Number.MIN_SAFE_INTEGER)))
);
if (newMinBinId.lt(this.lowerBinId)) {
const binCountToExpand = this.lowerBinId.sub(depositMinBinId);
for (let i = 1; i <= binCountToExpand.toNumber(); i++) {
const binId = this.lowerBinId.subn(i);
const price = getPriceOfBinByBinId(
binId.toNumber(),
binStep.toNumber()
);
const adjustedPrice = price.mul(tokenXMultiplier).div(tokenYMultiplier);
this.rebalancePositionBinData.unshift({
binId: binId.toNumber(),
price: adjustedPrice.toString(),
pricePerToken: adjustedPrice.toString(),
amountX: new (0, _bnjs2.default)(0),
amountY: new (0, _bnjs2.default)(0),
claimableRewardAmount: [new (0, _bnjs2.default)(0), new (0, _bnjs2.default)(0)],
claimableFeeXAmount: new (0, _bnjs2.default)(0),
claimableFeeYAmount: new (0, _bnjs2.default)(0)
});
}
} else {
const binCountToShrink = newMinBinId.sub(this.lowerBinId);
for (let i = 1; i <= binCountToShrink.toNumber(); i++) {
this.rebalancePositionBinData.shift();
}
}
if (newMaxBinId.gt(this.upperBinId)) {
const binCountToExpand = newMaxBinId.sub(this.upperBinId);
for (let i = 1; i <= binCountToExpand.toNumber(); i++) {
const binId = this.upperBinId.addn(i);
const price = getPriceOfBinByBinId(
binId.toNumber(),
binStep.toNumber()
);
const adjustedPrice = price.mul(tokenXMultiplier).div(tokenYMultiplier);
this.rebalancePositionBinData.push({
binId: binId.toNumber(),
price: adjustedPrice.toString(),
pricePerToken: adjustedPrice.toString(),
amountX: new (0, _bnjs2.default)(0),
amountY: new (0, _bnjs2.default)(0),
claimableRewardAmount: [new (0, _bnjs2.default)(0), new (0, _bnjs2.default)(0)],
claimableFeeXAmount: new (0, _bnjs2.default)(0),
claimableFeeYAmount: new (0, _bnjs2.default)(0)
});
}
} else {
const binCountToShrink = this.upperBinId.sub(newMaxBinId);
for (let i = 1; i <= binCountToShrink.toNumber(); i++) {
this.rebalancePositionBinData.pop();
}
}
this.lowerBinId = newMinBinId;
this.upperBinId = newMaxBinId;
}
_simulateWithdraw(withdraws) {
let liquidityAndFeeXWithdrawn = new (0, _bnjs2.default)(0);
let liquidityAndFeeYWithdrawn = new (0, _bnjs2.default)(0);
let rewardsAmountClaimed = [new (0, _bnjs2.default)(0), new (0, _bnjs2.default)(0)];
const activeId = new (0, _bnjs2.default)(this.lbPair.activeId);
for (const { minBinId, maxBinId, bps } of withdraws) {
const fromBinId = _nullishCoalesce(minBinId, () => ( activeId));
const toBinId = _nullishCoalesce(maxBinId, () => ( activeId));
const binIds = binRangeToBinIdArray(fromBinId, toBinId).filter(
(binId) => binId.gte(this.lowerBinId) && binId.lte(this.upperBinId)
);
for (const binId of binIds) {
const idx = this.rebalancePositionBinData.findIndex(
(b) => b.binId === binId.toNumber()
);
const binData = this.rebalancePositionBinData[idx];
const amountXWithdrawn = binData.amountX.mul(bps).divn(BASIS_POINT_MAX);
const amountYWithdrawn = binData.amountY.mul(bps).divn(BASIS_POINT_MAX);
liquidityAndFeeXWithdrawn = liquidityAndFeeXWithdrawn.add(amountXWithdrawn);
liquidityAndFeeYWithdrawn = liquidityAndFeeYWithdrawn.add(amountYWithdrawn);
binData.amountX = binData.amountX.sub(amountXWithdrawn);
binData.amountY = binData.amountY.sub(amountYWithdrawn);
if (this.shouldClaimFee) {
liquidityAndFeeXWithdrawn = liquidityAndFeeXWithdrawn.add(
binData.claimableFeeXAmount
);
liquidityAndFeeYWithdrawn = liquidityAndFeeYWithdrawn.add(
binData.claimableFeeYAmount
);
binData.claimableFeeXAmount = new (0, _bnjs2.default)(0);
binData.claimableFeeYAmount = new (0, _bnjs2.default)(0);
}
if (this.shouldClaimReward) {
for (const [idx2, amount] of binData.claimableRewardAmount.entries()) {
rewardsAmountClaimed[idx2] = rewardsAmountClaimed[idx2].add(amount);
binData.claimableRewardAmount[idx2] = new (0, _bnjs2.default)(0);
}
}
this.rebalancePositionBinData[idx] = binData;
}
}
const withdrawParams = withdraws.map(
({ minBinId, maxBinId, bps }) => {
return {
minBinId: minBinId ? minBinId.toNumber() : null,
maxBinId: maxBinId ? maxBinId.toNumber() : null,
bps: bps.toNumber(),
padding: Array(16).fill(0)
};
}
);
return {
result: {
liquidityAndFeeXWithdrawn,
liquidityAndFeeYWithdrawn,
rewardsAmountClaimed
},
withdrawParams
};
}
async simulateRebalance(connection, binStep, tokenXDecimal, tokenYDecimal, withdraws, deposits) {
if (withdraws.length == 0 && deposits.length == 0) {
throw "No rebalance action";
}
const activeId = new (0, _bnjs2.default)(this.lbPair.activeId);
withdraws = validateAndSortRebalanceWithdraw(withdraws, activeId);
deposits = validateAndSortRebalanceDeposit(deposits);
const beforeWidth = getPositionWidthWithMinWidth(
this.lowerBinId.toNumber(),
this.upperBinId.toNumber()
);
const { withdrawParams, result: withdrawResult } = this._simulateWithdraw(withdraws);
const { depositParams, result: depositResult } = this._simulateDeposit(
binStep,
tokenXDecimal,
tokenYDecimal,
deposits,
withdrawResult
);
const afterWidth = getPositionWidthWithMinWidth(
this.lowerBinId.toNumber(),
this.upperBinId.toNumber()
);
const widthDelta = afterWidth - beforeWidth;
let rentalCostLamports = new (0, _bnjs2.default)(0);
if (widthDelta != 0) {
const sizeChanges = Math.abs(widthDelta) * POSITION_BIN_DATA_SIZE;
const [minimumLamports, rentExemptionLamports] = await Promise.all([
connection.getMinimumBalanceForRentExemption(0),
connection.getMinimumBalanceForRentExemption(sizeChanges)
]);
const lamportChanges = new (0, _bnjs2.default)(rentExemptionLamports).sub(
new (0, _bnjs2.default)(minimumLamports)
);
if (widthDelta > 0) {
rentalCostLamports = rentalCostLamports.add(lamportChanges);
} else {
rentalCostLamports = rentalCostLamports.sub(lamportChanges);
}
}
return {
amountXDeposited: depositResult.totalAmountXDeposited,
amountYDeposited: depositResult.totalAmountYDeposited,
actualAmountXDeposited: depositResult.actualTotalAmountXDeposited,
actualAmountYDeposited: depositResult.actualTotalAmountYDeposited,
actualAmountXWithdrawn: depositResult.actualLiquidityAndFeeXWithdrawn,
actualAmountYWithdrawn: depositResult.actualLiquidityAndFeeYWithdrawn,
rewardAmountsClaimed: withdrawResult.rewardsAmountClaimed,
withdrawParams,
depositParams,
rentalCostLamports
};
}
totalAmounts() {
let totalAmountX = new (0, _bnjs2.default)(0);
let totalAmountY = new (0, _bnjs2.default)(0);
for (const binData of this.rebalancePositionBinData) {
totalAmountX = totalAmountX.add(binData.amountX);
totalAmountY = totalAmountY.add(binData.amountY);
}
return [totalAmountX, totalAmountY];
}
totalFeeAmounts() {
let totalFeeXAmount = new (0, _bnjs2.default)(0);
let totalFeeYAmount = new (0, _bnjs2.default)(0);
for (const binData of this.rebalancePositionBinData) {
totalFeeXAmount = totalFeeXAmount.add(binData.claimableFeeXAmount);
totalFeeYAmount = totalFeeYAmount.add(binData.claimableFeeYAmount);
}
return [totalFeeXAmount, totalFeeYAmount];
}
totalRewardAmounts() {
let totalRewardAmounts = [new (0, _bnjs2.default)(0), new (0, _bnjs2.default)(0)];
for (const binData of this.rebalancePositionBinData) {
totalRewardAmounts[0] = totalRewardAmounts[0].add(
binData.claimableRewardAmount[0]
);
totalRewardAmounts[1] = totalRewardAmounts[1].add(
binData.claimableRewardAmount[1]
);
}
return totalRewardAmounts;
}
};
function getPositionWidthWithMinWidth(lowerBinId, upperBinId) {
const width = upperBinId - lowerBinId + 1;
return Math.max(width, DEFAULT_BIN_PER_POSITION.toNumber());
}
function validateAndSortRebalanceDeposit(deposits) {
const sortedDeposits = deposits.sort(
(a, b) => a.minDeltaId.sub(b.minDeltaId).toNumber()
);
for (const deposit of deposits) {
if (deposit.minDeltaId.gt(deposit.maxDeltaId)) {
throw "Invalid minDeltaId or maxDeltaId";
}
}
for (let i = 1; i < sortedDeposits.length; i++) {
const prevDeposit = sortedDeposits[i - 1];
const currDeposit = sortedDeposits[i];
if (prevDeposit.maxDeltaId.gte(currDeposit.minDeltaId)) {
throw "Overlap deposit bin range";
}
}
return sortedDeposits;
}
function validateAndSortRebalanceWithdraw(withdraws, activeId) {
const filledWithdraws = [];
for (const { minBinId, maxBinId, bps } of withdraws) {
if (bps.toNumber() < 0 || bps.toNumber() > BASIS_POINT_MAX) {
throw "Invalid bps";
}
const filledMinBinId = _nullishCoalesce(minBinId, () => ( activeId));
const filledMaxBinId = _nullishCoalesce(maxBinId, () => ( activeId));
if (filledMinBinId.gt(filledMaxBinId)) {
throw "Invalid minBinId or maxBinId";
}
filledWithdraws.push({
minBinId: filledMinBinId,
maxBinId: filledMaxBinId,
bps
});
}
filledWithdraws.sort((a, b) => {
return a.minBinId.sub(b.minBinId).toNumber();
});
for (let i = 1; i < filledWithdraws.length; i++) {
const prev = filledWithdraws[i - 1];
const curr = filledWithdraws[i];
if (curr.minBinId.lte(prev.maxBinId)) {
throw "Overlap withdraw bin range";
}
}
return filledWithdraws;
}
function binRangeToBinIdArray(minBinId, maxBinId) {
const binIdArray = [];
const fromBinId = minBinId.toNumber();
const toBinId = maxBinId.toNumber();
for (let binId = fromBinId; binId <= toBinId; binId++) {
binIdArray.push(new (0, _bnjs2.default)(binId));
}
return binIdArray;
}
function getRebalanceBinArrayIndexesAndBitmapCoverage(adds, removes, activeId, pairAddress, programId) {
let indexMap = /* @__PURE__ */ new Map();
removes.forEach((value) => {
let minBinId = value.minBinId;
if (minBinId == null) {
minBinId = activeId;
}
let maxBinId = value.maxBinId;
if (maxBinId == null) {
maxBinId = activeId;
}
let binArrayIndex = binIdToBinArrayIndex(new (0, _bnjs2.default)(minBinId));
const upperBinId = new (0, _bnjs2.default)(maxBinId);
while (true) {
indexMap.set(binArrayIndex.toNumber(), true);
const [binArrayLowerBinId, binArrayUpperBinId] = getBinArrayLowerUpperBinId(binArrayIndex);
if (upperBinId.gte(binArrayLowerBinId) && upperBinId.lte(binArrayUpperBinId)) {
break;
} else {
binArrayIndex = binArrayIndex.add(new (0, _bnjs2.default)(1));
}
}
});
adds.forEach((value) => {
const minBinId = activeId + value.minDeltaId;
const maxBinId = activeId + value.maxDeltaId;
let binArrayIndex = binIdToBinArrayIndex(new (0, _bnjs2.default)(minBinId));
const upperBinId = new (0, _bnjs2.default)(maxBinId);
while (true) {
indexMap.set(binArrayIndex.toNumber(), true);
const [binArrayLowerBinId, binArrayUpperBinId] = getBinArrayLowerUpperBinId(binArrayIndex);
if (upperBinId.gte(binArrayLowerBinId) && upperBinId.lte(binArrayUpperBinId)) {
break;
} else {
binArrayIndex = binArrayIndex.add(new (0, _bnjs2.default)(1));
}
}
});
const binArrayIndexes = Array.from(indexMap.keys()).map((idx) => new (0, _bnjs2.default)(idx));
const requireBitmapExtension = binArrayIndexes.some(
(index) => isOverflowDefaultBinArrayBitmap(new (0, _bnjs2.default)(index))
);
return {
binArrayIndexes,
binArrayBitmap: requireBitmapExtension ? deriveBinArrayBitmapExtension(pairAddress, programId)[0] : programId
};
}
// src/dlmm/helpers/rebalance/liquidity_strategy/index.ts
// src/dlmm/helpers/rebalance/liquidity_strategy/bidAsk.ts
function findBaseDeltaY(amountY, minDeltaId, maxDeltaId) {
if (minDeltaId.gt(maxDeltaId) || amountY.lte(new (0, _bnjs2.default)(0))) {
return new (0, _bnjs2.default)(0);
}
if (minDeltaId.eq(maxDeltaId)) {
return amountY;
}
const m1 = minDeltaId.neg();
const m2 = maxDeltaId.neg();
const b = m2.neg().addn(1).mul(m1.sub(m2).addn(1));
const c = m1.mul(m1.addn(1)).divn(2);
const d = m2.mul(m2.subn(1)).divn(2);
const a = b.add(c.sub(d));
return amountY.div(a);
}
function findY0AndDeltaY(amountY, minDeltaId, maxDeltaId, activeId) {
if (minDeltaId.gt(maxDeltaId) || amountY.isZero()) {
return {
base: new (0, _bnjs2.default)(0),
delta: new (0, _bnjs2.default)(0)
};
}
let baseDeltaY = findBaseDeltaY(amountY, minDeltaId, maxDeltaId);
const y0 = baseDeltaY.neg().mul(maxDeltaId.neg().subn(1));
while (true) {
const amountInBins = getAmountInBinsBidSide(
activeId,
minDeltaId,
maxDeltaId,
baseDeltaY,
y0
);
const totalAmountY = amountInBins.reduce((acc, { amountY: amountY2 }) => {
return acc.add(amountY2);
}, new (0, _bnjs2.default)(0));
if (totalAmountY.gt(amountY)) {
baseDeltaY = baseDeltaY.sub(new (0, _bnjs2.default)(1));
} else {
return {
base: y0,
delta: baseDeltaY
};
}
}
}
function findBaseDeltaX(amountX, minDeltaId, maxDeltaId, binStep, activeId) {
if (minDeltaId.gt(maxDeltaId) || amountX.lte(new (0, _bnjs2.default)(0))) {
return new (0, _bnjs2.default)(0);
}
const m1 = minDeltaId;
const m2 = maxDeltaId;
let b = new (0, _bnjs2.default)(0);
let c = new (0, _bnjs2.default)(0);
let s = new (0, _bnjs2.default)(0);
const base = getQPriceBaseFactor(binStep);
const maxBinId = activeId.add(maxDeltaId);
let inverseBasePrice = pow(base, maxBinId.neg());
for (let m = m2.toNumber(); m >= m1.toNumber(); m--) {
const pm = inverseBasePrice;
b = b.add(m1.mul(pm));
c = c.add(new (0, _bnjs2.default)(m).mul(pm));
s = s.add(pm);
inverseBasePrice = inverseBasePrice.mul(base).shrn(SCALE_OFFSET);
}
return amountX.shln(SCALE_OFFSET).div(c.sub(b).add(s));
}
function findX0AndDeltaX(amountX, minDeltaId, maxDeltaId, binStep, activeId) {
if (minDeltaId.gt(maxDeltaId) || amountX.lte(new (0, _bnjs2.default)(0)) || amountX.isZero()) {
return {
base: new (0, _bnjs2.default)(0),
delta: new (0, _bnjs2.default)(0)
};
}
let baseDeltaX = findBaseDeltaX(
amountX,
minDeltaId,
maxDeltaId,
binStep,
activeId
);
let maxProbe = 100;
while (true) {
if (maxProbe < 0) {
throw new Error(
"Something wrong: Unable to find suitable x0 and delta_x within probe limit"
);
}
const x0 = minDeltaId.neg().addn(1).mul(baseDeltaX);
const amountInBins = getAmountInBinsAskSide(
activeId,
binStep,
minDeltaId,
maxDeltaId,
baseDeltaX,
x0
);
const totalAmountX = amountInBins.reduce((acc, { amountX: amountX2 }) => {
return acc.add(amountX2);
}, new (0, _bnjs2.default)(0));
if (totalAmountX.gt(amountX)) {
baseDeltaX = baseDeltaX.subn(1);
maxProbe--;
} else {
return {
base: x0,
delta: baseDeltaX
};
}
}
}
var BidAskStrategyParameterBuilder = class {
findXParameters(amountX, minDeltaId, maxDeltaId, binStep, activeId) {
return findX0AndDeltaX(amountX, minDeltaId, maxDeltaId, binStep, activeId);
}
findYParameters(amountY, minDeltaId, maxDeltaId, activeId) {
return findY0AndDeltaY(amountY, minDeltaId, maxDeltaId, activeId);
}
suggestBalancedXParametersFromY(activeId, binStep, favorXInActiveBin, minDeltaId, maxDeltaId, amountY) {
const deltaX = amountY.div(
maxDeltaId.addn(1).mul(maxDeltaId.addn(2)).divn(2)
);
const x0 = minDeltaId.neg().mul(deltaX).add(deltaX);
const totalAmountX = toAmountIntoBins(
activeId,
minDeltaId,
maxDeltaId,
deltaX,
new (0, _bnjs2.default)(0),
x0,
new (0, _bnjs2.default)(0),
binStep,
favorXInActiveBin
).reduce((acc, bin) => {
return acc.add(bin.amountX);
}, new (0, _bnjs2.default)(0));
return {
base: x0,
delta: deltaX,
amountX: totalAmountX
};
}
suggestBalancedYParametersFromX(activeId, binStep, favorXInActiveBin, minDeltaId, maxDeltaId, amountXInQuoteValue) {
const m1 = minDeltaId.neg().subn(1);
const m2 = maxDeltaId.neg();
const a1 = m2.neg().mul(m1.sub(m2).addn(1));
const a2 = m1.mul(m1.addn(1)).divn(2);
const a3 = m2.mul(m2.subn(1)).divn(2);
const a = a1.add(a2.sub(a3));
const deltaY = amountXInQuoteValue.div(a);
const y0 = deltaY.neg().mul(m2).add(deltaY);
const amountY = toAmountIntoBins(
activeId,
minDeltaId,
maxDeltaId,
new (0, _bnjs2.default)(0),
deltaY,
new (0, _bnjs2.default)(0),
y0,
binStep,
favorXInActiveBin
).reduce((acc, bin) => {
return acc.add(bin.amountY);
}, new (0, _bnjs2.default)(0));
return {
base: y0,
delta: deltaY,
amountY
};
}
};
// src/dlmm/helpers/rebalance/liquidity_strategy/curve.ts
function findBaseY0(amountY, minDeltaId, maxDeltaId) {
if (minDeltaId.gt(maxDeltaId) || amountY.lte(new (0, _bnjs2.default)(0))) {
return new (0, _bnjs2.default)(0);
}
if (minDeltaId.eq(maxDeltaId)) {
return amountY;
}
const m1 = minDeltaId.neg();
const m2 = maxDeltaId.neg();
const b = m1.sub(m2).addn(1);
const c = m1.mul(m1.addn(1)).divn(2);
const d = m2.mul(m2.subn(1)).divn(2);
const a = b.sub(c.sub(d).div(m1.addn(1)));
return amountY.div(a);
}
function findY0AndDeltaY2(amountY, minDeltaId, maxDeltaId, activeId) {
if (minDeltaId.gt(maxDeltaId) || amountY.isZero()) {
return {
base: new (0, _bnjs2.default)(0),
delta: new (0, _bnjs2.default)(0)
};
}
let baseY0 = findBaseY0(amountY, minDeltaId, maxDeltaId);
while (true) {
const deltaY = baseY0.neg().div(minDeltaId.neg().addn(1));
const amountInBins = getAmountInBinsBidSide(
activeId,
minDeltaId,
maxDeltaId,
deltaY,
baseY0
);
const totalAmountY = amountInBins.reduce((acc, { amountY: amountY2 }) => {
return acc.add(amountY2);
}, new (0, _bnjs2.default)(0));
if (totalAmountY.gt(amountY)) {
baseY0 = baseY0.sub(new (0, _bnjs2.default)(1));
} else {
return {
base: baseY0,
delta: deltaY
};
}
}
}
function findBaseX0(amountX, minDeltaId, maxDeltaId, binStep, activeId) {
if (minDeltaId.gt(maxDeltaId) || amountX.lte(new (0, _bnjs2.default)(0))) {
return new (0, _bnjs2.default)(0);
}
let b = new (0, _bnjs2.default)(0);
let c = new (0, _bnjs2.default)(0);
let m1 = minDeltaId;
let m2 = maxDeltaId;
for (let m = m1.toNumber(); m <= m2.toNumber(); m++) {
const binId = activeId.addn(m);
const pm = getQPriceFromId(binId.neg(), binStep);
b = b.add(pm);
const cDelta = new (0, _bnjs2.default)(m).mul(pm).div(m2);
c = c.add(cDelta);
}
return amountX.shln(SCALE_OFFSET).div(b.sub(c));
}
function findX0AndDeltaX2(amountX, minDeltaId, maxDeltaId, binStep, activeId) {
if (minDeltaId.gt(maxDeltaId) || amountX.lte(new (0, _bnjs2.default)(0)) || amountX.isZero()) {
return {
base: new (0, _bnjs2.default)(0),
delta: new (0, _bnjs2.default)(0)
};
}
let baseX0 = findBaseX0(amountX, minDeltaId, maxDeltaId, binStep, activeId);
const deltaX = baseX0.neg().div(maxDeltaId);
while (true) {
const amountInBins = getAmountInBinsAskSide(
activeId,
binStep,
minDeltaId,
maxDeltaId,
deltaX,
baseX0
);
const totalAmountX = amountInBins.reduce((acc, { amountX: amountX2 }) => {
return acc.add(amountX2);
}, new (0, _bnjs2.default)(0));
if (totalAmountX.gt(amountX)) {
baseX0 = baseX0.sub(new (0, _bnjs2.default)(1));
} else {
return {
base: baseX0,
delta: deltaX
};
}
}
}
var CurveStrategyParameterBuilder = class {
findXParameters(amountX, minDeltaId, maxDeltaId, binStep, activeId) {
return findX0AndDeltaX2(amountX, minDeltaId, maxDeltaId, binStep, activeId);
}
findYParameters(amountY, minDeltaId, maxDeltaId, activeId) {
return findY0AndDeltaY2(amountY, minDeltaId, maxDeltaId, activeId);
}
suggestBalancedXParametersFromY(activeId, binStep, favorXInActiveBin, minDeltaId, maxDeltaId, amountY) {
const x0 = amountY.muln(2).div(maxDeltaId.addn(1));
const deltaX = x0.neg().div(maxDeltaId);
const totalAmountX = toAmountIntoBins(
activeId,
minDeltaId,
maxDeltaId,
deltaX,
new (0, _bnjs2.default)(0),
x0,
new (0, _bnjs2.default)(0),
binStep,
favorXInActiveBin
).reduce((acc, bin) => {
return acc.add(bin.amountX);
}, new (0, _bnjs2.default)(0));
return {
base: x0,
delta: deltaX,
amountX: totalAmountX
};
}
suggestBalancedYParametersFromX(activeId, binStep, favorXInActiveBin, minDeltaId, maxDeltaId, amountXInQuoteValue) {
const m1 = minDeltaId.neg();
const m2 = maxDeltaId.neg();
const a1 = m1.sub(m2).addn(1);
const a2 = m1.mul(m1.addn(1)).divn(2);
const a3 = m2.mul(m2.subn(1)).divn(2);
const a = m1.sub(a3.sub(a2)).div(m1);
const y0 = amountXInQuoteValue.div(a);
const deltaY = y0.neg().div(m1);
const amountY = toAmountIntoBins(
activeId,
minDeltaId,
maxDeltaId,
new (0, _bnjs2.default)(0),
deltaY,
new (0, _bnjs2.default)(0),
y0,
binStep,
favorXInActiveBin
).reduce((acc, bin) => {
return acc.add(bin.amountY);
}, new (0, _bnjs2.default)(0));
return {
base: y0,
delta: deltaY,
amountY
};
}
};
// src/dlmm/helpers/rebalance/liquidity_strategy/spot.ts
function findY0(amountY, minDeltaId, maxDeltaId) {
if (minDeltaId.gt(maxDeltaId) || amountY.lte(new (0, _bnjs2.default)(0)) || amountY.isZero()) {
return new (0, _bnjs2.default)(0);
}
const m1 = minDeltaId.neg();
const m2 = maxDeltaId.neg();
const delta = m1.sub(m2).addn(1);
return amountY.div(delta);
}
function findBaseX02(amountX, minDeltaId, maxDeltaId, binStep, activeId) {
let totalWeight = new (0, _bnjs2.default)(0);
const minBinId = activeId.add(minDeltaId);
const maxBinId = activeId.add(maxDeltaId);
let baseFactor = getQPriceBaseFactor(binStep);
let basePrice = getQPriceFromId(maxBinId.neg(), binStep);
for (let binId = minBinId.toNumber(); binId <= maxBinId.toNumber(); binId++) {
totalWeight = totalWeight.add(basePrice);
basePrice = basePrice.mul(baseFactor).shrn(SCALE_OFFSET);
}
return amountX.shln(SCALE_OFFSET).div(totalWeight);
}
function findX0(amountX, minDeltaId, maxDeltaId, binStep, activeId) {
if (minDeltaId.gt(maxDeltaId) || amountX.lte(new (0, _bnjs2.default)(0)) || amountX.isZero()) {
return new (0, _bnjs2.default)(0);
}
let x0 = findBaseX02(amountX, minDeltaId, maxDeltaId, binStep, activeId);
while (true) {
const amountInBins = getAmountInBinsAskSide(
activeId,
binStep,
minDeltaId,
maxDeltaId,
new (0, _bnjs2.default)(0),
x0
);
const totalAmountX = amountInBins.reduce((acc, bin) => {
return acc.add(bin.amountX);
}, new (0, _bnjs2.default)(0));
if (totalAmountX.lt(amountX)) {
x0 = x0.add(new (0, _bnjs2.default)(1));
} else {
x0 = x0.sub(new (0, _bnjs2.default)(1));
return x0;
}
}
}
var SpotStrategyParameterBuilder = class {
findXParameters(amountX, minDeltaId, maxDeltaId, binStep, activeId) {
return {
base: findX0(amountX, minDeltaId, maxDeltaId, binStep, activeId),
delta: new (0, _bnjs2.default)(0)
};
}
findYParameters(amountY, minDeltaId, maxDeltaId, _activeId) {
return {
base: findY0(amountY, minDeltaId, maxDeltaId),
delta: new (0, _bnjs2.default)(0)
};
}
suggestBalancedXParametersFromY(activeId, binStep, favorXInActiveBin, minDeltaId, maxDeltaId, amountY) {
const x0 = amountY.div(maxDeltaId.addn(1));
const totalAmountX = toAmountIntoBins(
activeId,
minDeltaId,
maxDeltaId,
new (0, _bnjs2.default)(0),
new (0, _bnjs2.default)(0),
x0,
new (0, _bnjs2.default)(0),
binStep,
favorXInActiveBin
).reduce((acc, bin) => {
return acc.add(bin.amountX);
}, new (0, _bnjs2.default)(0));
return {
base: new (0, _bnjs2.default)(x0.toString()),
delta: new (0, _bnjs2.default)(0),
amountX: totalAmountX
};
}
suggestBalancedYParametersFromX(activeId, binStep, favorXInActiveBin, minDeltaId, maxDeltaId, amountXInQuoteValue) {
const y0 = amountXInQuoteValue.div(maxDeltaId.sub(minDeltaId).addn(1));
const amountY = toAmountIntoBins(
activeId,
minDeltaId,
maxDeltaId,
new (0, _bnjs2.default)(0),
new (0, _bnjs2.default)(0),
new (0, _bnjs2.default)(0),
y0,
binStep,
favorXInActiveBin
).reduce((acc, bin) => {
return acc.add(bin.amountY);
}, new (0, _bnjs2.default)(0));
return {
base: y0,
delta: new (0, _bnjs2.default)(0),
amountY
};
}
};
// src/dlmm/helpers/rebalance/liquidity_strategy/index.ts
function getLiquidityStrategyParameterBuilder(strategyType) {
switch (strategyType) {
case 0 /* Spot */:
return new SpotStrategyParameterBuilder();
case 1 /* Curve */:
return new CurveStrategyParameterBuilder();
case 2 /* BidAsk */:
return new BidAskStrategyParameterBuilder();
default:
throw new Error("Strategy not supported");
}
}
function suggestBalancedXParametersFromY(y0, deltaY, minDeltaId, maxDeltaId, activeId, binStep, favorXInActiveBin, builder) {
const endDeltaIdBidSide = favorXInActiveBin ? new (0, _bnjs2.default)(-1) : new (0, _bnjs2.default)(0);
if (maxDeltaId.lte(endDeltaIdBidSide)) {
return {
base: new (0, _bnjs2.default)(0),
delta: new (0, _bnjs2.default)(0),
amountX: new (0, _bnjs2.default)(0)
};
}
const minYDeltaId = minDeltaId;
const maxYDeltaId = endDeltaIdBidSide;
const totalAmountY = toAmountIntoBins(
activeId,
minYDeltaId,
maxYDeltaId,
new (0, _bnjs2.default)(0),
deltaY,
new (0, _bnjs2.default)(0),
y0,
binStep,
favorXInActiveBin
).reduce((acc, bin) => {
return acc.add(bin.amountY);
}, new (0, _bnjs2.default)(0));
const minXDeltaId = maxYDeltaId.addn(1);
const maxXDeltaId = maxDeltaId;
return builder.suggestBalancedXParametersFromY(
activeId,
binStep,
favorXInActiveBin,
minXDeltaId,
maxXDeltaId,
totalAmountY
);
}
function getAutoFillAmountByRebalancedPosition(rebalancePosition, strategyType) {
let liquidityInBidSide = new (0, _bnjs2.default)(0);
let liquidityInAskSide = new (0, _bnjs2.default)(0);
const builder = getLiquidityStrategyParameterBuilder(strategyType);
const { lbPair } = rebalancePosition;
let favorXInActiveBin = false;
let activeIdIndex = -1;
for (const [
idx,
binData
] of rebalancePosition.rebalancePositionBinData.entries()) {
const liquidityBid = binData.amountY;
const liquidityAsk = new (0, _decimaljs2.default)(binData.price).mul(new (0, _decimaljs2.default)(binData.amountX.toString())).floor().toString();
liquidityInBidSide = liquidityInBidSide.add(liquidityBid);
liquidityInAskSide = liquidityInAskSide.add(new (0, _bnjs2.default)(liquidityAsk));
if (binData.binId == lbPair.activeId) {
favorXInActiveBin = binData.amountX.gt(binData.amountY);
activeIdIndex = idx;
}
}
if (liquidityInAskSide.gt(liquidityInBidSide)) {
const minBinId = rebalancePosition.rebalancePositionBinData[0].binId;
let maxBinId;
if (activeIdIndex == -1) {
maxBinId = rebalancePosition.rebalancePositionBinData[rebalancePosition.rebalancePositionBinData.length - 1].binId;
} else {
maxBinId = rebalancePosition.rebalancePositionBinData[favorXInActiveBin ? activeIdIndex - 1 : activeIdIndex].binId;
}
const minDeltaId = minBinId - lbPair.activeId;
const maxDeltaId = maxBinId - lbPair.activeId;
const { amountY } = builder.suggestBalancedYParametersFromX(
new (0, _bnjs2.default)(lbPair.activeId),
new (0, _bnjs2.default)(lbPair.binStep),
favorXInActiveBin,
new (0, _bnjs2.default)(minDeltaId),
new (0, _bnjs2.default)(maxDeltaId),
liquidityInAskSide
);
const [_, positionAmountY] = rebalancePosition.totalAmounts();
return {
amount: _bnjs2.default.max(amountY.sub(positionAmountY), new (0, _bnjs2.default)(0)),
isBidSide: true
};
} else if (liquidityInAskSide.lt(liquidityInBidSide)) {
const maxBinId = rebalancePosition.rebalancePositionBinData[rebalancePosition.rebalancePositionBinData.length - 1].binId;
let minBinId;
if (activeIdIndex == -1) {
minBinId = rebalancePosition.rebalancePositionBinData[0].binId;
} else {
minBinId = rebalancePosition.rebalancePositionBinData[favorXInActiveBin ? activeIdIndex - 1 : activeIdIndex].binId;
}
const minDeltaId = minBinId - lbPair.activeId;
const maxDeltaId = maxBinId - lbPair.activeId;
const { amountX } = builder.suggestBalancedXParametersFromY(
new (0, _bnjs2.default)(lbPair.activeId),
new (0, _bnjs2.default)(lbPair.binStep),
favorXInActiveBin,
new (0, _bnjs2.default)(minDeltaId),
new (0, _bnjs2.default)(maxDeltaId),
liquidityInBidSide
);
const [positionAmountX] = rebalancePosition.totalAmounts();
return {
amount: _bnjs2.default.max(amountX.sub(positionAmountX), new (0, _bnjs2.default)(0)),
isBidSide: false
};
} else {
return {
amount: new (0, _bnjs2.default)(0),
isBidSide: false
};
}
}
function suggestBalancedYParametersFromX(x0, deltaX, minDeltaId, maxDeltaId, activeId, binStep, favorXInActiveBin, builder) {
const startDeltaIdAskSide = favorXInActiveBin ? new (0, _bnjs2.default)(0) : new (0, _bnjs2.default)(1);
if (minDeltaId.gte(startDeltaIdAskSide)) {
return {
base: new (0, _bnjs2.default)(0),
delta: new (0, _bnjs2.default)(0),
amountY: new (0, _bnjs2.default)(0)
};
}
const minXDeltaId = startDeltaIdAskSide;
const maxXDeltaId = maxDeltaId;
const amountXInBins = toAmountIntoBins(
activeId,
minXDeltaId,
maxXDeltaId,
deltaX,
new (0, _bnjs2.default)(0),
x0,
new (0, _bnjs2.default)(0),
binStep,
favorXInActiveBin
);
const totalAmountXInQuote = amountXInBins.reduce((acc, bin) => {
const price = getPriceOfBinByBinId(
bin.binId.toNumber(),
binStep.toNumber()
);
return acc.add(price.mul(new (0, _decimaljs2.default)(bin.amountX.toString())));
}, new (0, _decimaljs2.default)(0));
const totalAmountXInQuoteBN = new (0, _bnjs2.default)(totalAmountXInQuote.floor().toString());
const minYDeltaId = minDeltaId;
const maxYDeltaId = startDeltaIdAskSide.subn(1);
return builder.suggestBalancedYParametersFromX(
activeId,
binStep,
favorXInActiveBin,
minYDeltaId,
maxYDeltaId,
totalAmountXInQuoteBN
);
}
function buildLiquidityStrategyParameters(amountX, amountY, minDeltaId, maxDeltaId, binStep, favorXInActiveId, activeId, strategyParameterBuilder) {
if (minDeltaId.gt(maxDeltaId)) {
return {
x0: new (0, _bnjs2.default)(0),
y0: new (0, _bnjs2.default)(0),
deltaX: new (0, _bnjs2.default)(0),
deltaY: new (0, _bnjs2.default)(0)
};
}
const depositOnlyY = maxDeltaId.lt(new (0, _bnjs2.default)(0)) || maxDeltaId.isZero() && !favorXInActiveId;
const depositOnlyX = minDeltaId.gt(new (0, _bnjs2.default)(0)) || minDeltaId.isZero() && favorXInActiveId;
if (depositOnlyY) {
const { base, delta } = strategyParameterBuilder.findYParameters(
amountY,
minDeltaId,
maxDeltaId,
activeId
);
return {
x0: new (0, _bnjs2.default)(0),
deltaX: new (0, _bnjs2.default)(0),
y0: base,
deltaY: delta
};
}
if (depositOnlyX) {
const { base, delta } = strategyParameterBuilder.findXParameters(
amountX,
minDeltaId,
maxDeltaId,
binStep,
activeId
);
return {
x0: base,
deltaX: delta,
y0: new (0, _bnjs2.default)(0),
deltaY: new (0, _bnjs2.default)(0)
};
}
const maxDeltaIdBidSide = favorXInActiveId ? new (0, _bnjs2.default)(-1) : new (0, _bnjs2.default)(0);
const minDeltaIdAskSide = favorXInActiveId ? new (0, _bnjs2.default)(0) : new (0, _bnjs2.default)(1);
const { base: y0, delta: deltaY } = strategyParameterBuilder.findYParameters(
amountY,
minDeltaId,
maxDeltaIdBidSide,
activeId
);
const { base: x0, delta: deltaX } = strategyParameterBuilder.findXParameters(
amountX,
minDeltaIdAskSide,
maxDeltaId,
binStep,
activeId
);
return {
x0,
deltaX,
y0,
deltaY
};
}
// src/dlmm/helpers/index.ts
// src/dlmm/helpers/lbPair.ts
async function getTokensMintFromPoolAddress(connection, poolAddress, opt) {
const program = createProgram(connection, opt);
const poolAccount = await program.account.lbPair.fetchNullable(
new (0, _web3js.PublicKey)(poolAddress)
);
if (!poolAccount)
throw new Error("Pool account not found");
return {
tokenXMint: poolAccount.tokenXMint,
tokenYMint: poolAccount.tokenYMint
};
}
function getTokenProgramId(lbPairState) {
const getTokenProgramIdByFlag = (flag) => {
return flag == 0 ? _spltoken.TOKEN_PROGRAM_ID : _spltoken.TOKEN_2022_PROGRAM_ID;
};
return {
tokenXProgram: getTokenProgramIdByFlag(lbPairState.tokenMintXProgramFlag),
tokenYProgram: getTokenProgramIdByFlag(lbPairState.tokenMintYProgramFlag)
};
}
function isSupportLimitOrder(lbPairState) {
const functionType = lbPairState.parameters.functionType;
switch (functionType) {
case 2 /* LimitOrder */:
return true;
case 1 /* LiquidityMining */:
return false;
case 0 /* Undetermined */:
return lbPairState.rewardInfos.every(
(rewardInfo) => rewardInfo.mint.equals(_web3js.PublicKey.default)
);
default:
throw new Error("Invalid function type");
}
}
function getFeeMode(lbPairState, swapForY) {
const collectFeeMode = lbPairState.parameters.collectFeeMode;
let feeOnInput;
let feeOnTokenX;
switch (collectFeeMode) {
case 0 /* InputOnly */:
feeOnInput = true;
feeOnTokenX = swapForY;
break;
case 1 /* OnlyY */:
feeOnInput = !swapForY;
feeOnTokenX = false;
break;
default:
throw new Error("Invalid collect fee mode");
}
return {
feeOnInput,
feeOnTokenX
};
}
// src/dlmm/helpers/strategy.ts
var DEFAULT_MAX_WEIGHT = 2e3;
var DEFAULT_MIN_WEIGHT = 200;
function toWeightSpotBalanced(minBinId, maxBinId) {
let distributions = [];
for (let i = minBinId; i <= maxBinId; i++) {
distributions.push({
binId: i,
weight: 1
});
}
return distributions;
}
function toWeightDescendingOrder(minBinId, maxBinId) {
let distributions = [];
for (let i = minBinId; i <= maxBinId; i++) {
distributions.push({
binId: i,
weight: maxBinId - i + 1
});
}
return distributions;
}
function toWeightAscendingOrder(minBinId, maxBinId) {
let distributions = [];
for (let i = minBinId; i <= maxBinId; i++) {
distributions.push({
binId: i,
weight: i - minBinId + 1
});
}
return distributions;
}
function toWeightCurve(minBinId, maxBinId, activeId) {
if (activeId < minBinId || activeId > maxBinId) {
throw "Invalid strategy params";
}
let maxWeight = DEFAULT_MAX_WEIGHT;
let minWeight = DEFAULT_MIN_WEIGHT;
let diffWeight = maxWeight - minWeight;
let diffMinWeight = activeId > minBinId ? Math.floor(diffWeight / (activeId - minBinId)) : 0;
let diffMaxWeight = maxBinId > activeId ? Math.floor(diffWeight / (maxBinId - activeId)) : 0;
let distributions = [];
for (let i = minBinId; i <= maxBinId; i++) {
if (i < activeId) {
distributions.push({
binId: i,
weight: maxWeight - (activeId - i) * diffMinWeight
});
} else if (i > activeId) {
distributions.push({
binId: i,
weight: maxWeight - (i - activeId) * diffMaxWeight
});
} else {
distributions.push({
binId: i,
weight: maxWeight
});
}
}
return distributions;
}
function toWeightBidAsk(minBinId, maxBinId, activeId) {
if (activeId < minBinId || activeId > maxBinId) {
throw "Invalid strategy params";
}
let maxWeight = DEFAULT_MAX_WEIGHT;
let minWeight = DEFAULT_MIN_WEIGHT;
let diffWeight = maxWeight - minWeight;
let diffMinWeight = activeId > minBinId ? Math.floor(diffWeight / (activeId - minBinId)) : 0;
let diffMaxWeight = maxBinId > activeId ? Math.floor(diffWeight / (maxBinId - activeId)) : 0;
let distributions = [];
for (let i = minBinId; i <= maxBinId; i++) {
if (i < activeId) {
distributions.push({
binId: i,
weight: minWeight + (activeId - i) * diffMinWeight
});
} else if (i > activeId) {
distributions.push({
binId: i,
weight: minWeight + (i - activeId) * diffMaxWeight
});
} else {
distributions.push({
binId: i,
weight: minWeight
});
}
}
return distributions;
}
function toAmountsBothSideByStrategy(activeId, binStep, minBinId, maxBinId, amountX, amountY, amountXInActiveBin, amountYInActiveBin, strategyType, mintX, mintY, clock) {
const isSingleSideX = amountY.isZero();
switch (strategyType) {
case 0 /* Spot */: {
if (activeId < minBinId || activeId > maxBinId) {
const weights = toWeightSpotBalanced(minBinId, maxBinId);
return toAmountBothSide(
activeId,
binStep,
amountX,
amountY,
amountXInActiveBin,
amountYInActiveBin,
weights,
mintX,
mintY,
clock
);
}
const amountsInBin = [];
if (!isSingleSideX) {
if (minBinId <= activeId) {
const weights = toWeightSpotBalanced(minBinId, activeId);
const amounts = toAmountBidSide(
activeId,
amountY,
weights,
mintY,
clock
);
for (let bin of amounts) {
amountsInBin.push({
binId: bin.binId,
amountX: new (0, _anchor.BN)(0),
amountY: bin.amount
});
}
}
if (activeId < maxBinId) {
const weights = toWeightSpotBalanced(activeId + 1, maxBinId);
const amounts = toAmountAskSide(
activeId,
binStep,
amountX,
weights,
mintX,
clock
);
for (let bin of amounts) {
amountsInBin.push({
binId: bin.binId,
amountX: bin.amount,
amountY: new (0, _anchor.BN)(0)
});
}
}
} else {
if (minBinId < activeId) {
const weights = toWeightSpotBalanced(minBinId, activeId - 1);
const amountsIntoBidSide = toAmountBidSide(
activeId,
amountY,
weights,
mintY,
clock
);
for (let bin of amountsIntoBidSide) {
amountsInBin.push({
binId: bin.binId,
amountX: new (0, _anchor.BN)(0),
amountY: bin.amount
});
}
}
if (activeId <= maxBinId) {
const weights = toWeightSpotBalanced(activeId, maxBinId);
const amountsIntoAskSide = toAmountAskSide(
activeId,
binStep,
amountX,
weights,
mintX,
clock
);
for (let bin of amountsIntoAskSide) {
amountsInBin.push({
binId: bin.binId,
amountX: bin.amount,
amountY: new (0, _anchor.BN)(0)
});
}
}
}
return amountsInBin;
}
case 1 /* Curve */: {
if (activeId < minBinId) {
let weights = toWeightDescendingOrder(minBinId, maxBinId);
return toAmountBothSide(
activeId,
binStep,
amountX,
amountY,
amountXInActiveBin,
amountYInActiveBin,
weights,
mintX,
mintY,
clock
);
}
if (activeId > maxBinId) {
const weights = toWeightAscendingOrder(minBinId, maxBinId);
return toAmountBothSide(
activeId,
binStep,
amountX,
amountY,
amountXInActiveBin,
amountYInActiveBin,
weights,
mintX,
mintY,
clock
);
}
const amountsInBin = [];
if (!isSingleSideX) {
if (minBinId <= activeId) {
const weights = toWeightAscendingOrder(minBinId, activeId);
const amounts = toAmountBidSide(
activeId,
amountY,
weights,
mintY,
clock
);
for (let bin of amounts) {
amountsInBin.push({
binId: bin.binId,
amountX: new (0, _anchor.BN)(0),
amountY: bin.amount
});
}
}
if (activeId < maxBinId) {
const weights = toWeightDescendingOrder(activeId + 1, maxBinId);
const amounts = toAmountAskSide(
activeId,
binStep,
amountX,
weights,
mintX,
clock
);
for (let bin of amounts) {
amountsInBin.push({
binId: bin.binId,
amountX: bin.amount,
amountY: new (0, _anchor.BN)(0)
});
}
}
} else {
if (minBinId < activeId) {
const weights = toWeightAscendingOrder(minBinId, activeId - 1);
const amountsIntoBidSide = toAmountBidSide(
activeId,
amountY,
weights,
mintY,
clock
);
for (let bin of amountsIntoBidSide) {
amountsInBin.push({
binId: bin.binId,
amountX: new (0, _anchor.BN)(0),
amountY: bin.amount
});
}
}
if (activeId <= maxBinId) {
const weights = toWeightDescendingOrder(activeId, maxBinId);
const amountsIntoAskSide = toAmountAskSide(
activeId,
binStep,
amountX,
weights,
mintX,
clock
);
for (let bin of amountsIntoAskSide) {
amountsInBin.push({
binId: bin.binId,
amountX: bin.amount,
amountY: new (0, _anchor.BN)(0)
});
}
}
}
return amountsInBin;
}
case 2 /* BidAsk */: {
if (activeId < minBinId) {
const weights = toWeightAscendingOrder(minBinId, maxBinId);
return toAmountBothSide(
activeId,
binStep,
amountX,
amountY,
amountXInActiveBin,
amountYInActiveBin,
weights,
mintX,
mintY,
clock
);
}
if (activeId > maxBinId) {
const weights = toWeightDescendingOrder(minBinId, maxBinId);
return toAmountBothSide(
activeId,
binStep,
amountX,
amountY,
amountXInActiveBin,
amountYInActiveBin,
weights,
mintX,
mintY,
clock
);
}
const amountsInBin = [];
if (!isSingleSideX) {
if (minBinId <= activeId) {
const weights = toWeightDescendingOrder(minBinId, activeId);
const amounts = toAmountBidSide(
activeId,
amountY,
weights,
mintY,
clock
);
for (let bin of amounts) {
amountsInBin.push({
binId: bin.binId,
amountX: new (0, _anchor.BN)(0),
amountY: bin.amount
});
}
}
if (activeId < maxBinId) {
const weights = toWeightAscendingOrder(activeId + 1, maxBinId);
const amounts = toAmountAskSide(
activeId,
binStep,
amountX,
weights,
mintX,
clock
);
for (let bin of amounts) {
amountsInBin.push({
binId: bin.binId,
amountX: bin.amount,
amountY: new (0, _anchor.BN)(0)
});
}
}
} else {
if (minBinId < activeId) {
const weights = toWeightDescendingOrder(minBinId, activeId - 1);
const amountsIntoBidSide = toAmountBidSide(
activeId,
amountY,
weights,
mintY,
clock
);
for (let bin of amountsIntoBidSide) {
amountsInBin.push({
binId: bin.binId,
amountX: new (0, _anchor.BN)(0),
amountY: bin.amount
});
}
}
if (activeId <= maxBinId) {
const weights = toWeightAscendingOrder(activeId, maxBinId);
const amountsIntoAskSide = toAmountAskSide(
activeId,
binStep,
amountX,
weights,
mintX,
clock
);
for (let bin of amountsIntoAskSide) {
amountsInBin.push({
binId: bin.binId,
amountX: bin.amount,
amountY: new (0, _anchor.BN)(0)
});
}
}
}
return amountsInBin;
}
}
}
function autoFillYByStrategy(activeId, binStep, amountX, amountXInActiveBin, amountYInActiveBin, minBinId, maxBinId, strategyType) {
switch (strategyType) {
case 0 /* Spot */: {
let weights = toWeightSpotBalanced(minBinId, maxBinId);
return autoFillYByWeight(
activeId,
binStep,
amountX,
amountXInActiveBin,
amountYInActiveBin,
weights
);
}
case 1 /* Curve */: {
let weights = toWeightCurve(minBinId, maxBinId, activeId);
return autoFillYByWeight(
activeId,
binStep,
amountX,
amountXInActiveBin,
amountYInActiveBin,
weights
);
}
case 2 /* BidAsk */: {
let weights = toWeightBidAsk(minBinId, maxBinId, activeId);
return autoFillYByWeight(
activeId,
binStep,
amountX,
amountXInActiveBin,
amountYInActiveBin,
weights
);
}
}
}
function autoFillXByStrategy(activeId, binStep, amountY, amountXInActiveBin, amountYInActiveBin, minBinId, maxBinId, strategyType) {
switch (strategyType) {
case 0 /* Spot */: {
let weights = toWeightSpotBalanced(minBinId, maxBinId);
return autoFillXByWeight(
activeId,
binStep,
amountY,
amountXInActiveBin,
amountYInActiveBin,
weights
);
}
case 1 /* Curve */: {
let weights = toWeightCurve(minBinId, maxBinId, activeId);
return autoFillXByWeight(
activeId,
binStep,
amountY,
amountXInActiveBin,
amountYInActiveBin,
weights
);
}
case 2 /* BidAsk */: {
let weights = toWeightBidAsk(minBinId, maxBinId, activeId);
return autoFillXByWeight(
activeId,
binStep,
amountY,
amountXInActiveBin,
amountYInActiveBin,
weights
);
}
}
}
function toStrategyParameters({
maxBinId,
minBinId,
strategyType,
singleSidedX
}) {
const parameteres = new Array(64).fill(0);
const favorSide = singleSidedX ? 1 : 0;
parameteres[0] = favorSide;
switch (strategyType) {
case 0 /* Spot */: {
return {
minBinId,
maxBinId,
strategyType: { spotImBalanced: {} },
parameteres
};
}
case 1 /* Curve */: {
return {
minBinId,
maxBinId,
strategyType: { curveImBalanced: {} },
parameteres
};
}
case 2 /* BidAsk */: {
return {
minBinId,
maxBinId,
strategyType: { bidAskImBalanced: {} },
parameteres
};
}
}
}
// src/dlmm/helpers/bin.ts
function getAmountIn(amountOut, price, swapForY, rounding) {
if (swapForY) {
return shlDiv(amountOut, price, SCALE_OFFSET, rounding);
} else {
return mulShr(amountOut, price, SCALE_OFFSET, rounding);
}
}
function getAmountOut(bin, inAmount, swapForY) {
return swapForY ? mulShr(inAmount, bin.price, SCALE_OFFSET, 1 /* Down */) : shlDiv(inAmount, bin.price, SCALE_OFFSET, 1 /* Down */);
}
function getExcludedFeeAmountIn(bin, includedFeeOutAmount, swapForY) {
const mmAmount = swapForY ? bin.amountY : bin.amountX;
const { openOrderAmount, processedOrderRemainingAmount } = getLimitOrderAmountsBySwapDirection(bin, swapForY);
let remainingOutAmount = includedFeeOutAmount;
let totalAmountIn = new (0, _bnjs2.default)(0);
let exactOutAmount = _bnjs2.default.min(remainingOutAmount, mmAmount);
let amountIn = getAmountIn(exactOutAmount, bin.price, swapForY, 0 /* Up */);
remainingOutAmount = remainingOutAmount.sub(exactOutAmount);
totalAmountIn = totalAmountIn.add(amountIn);
if (remainingOutAmount.gt(new (0, _bnjs2.default)(0))) {
exactOutAmount = _bnjs2.default.min(remainingOutAmount, processedOrderRemainingAmount);
amountIn = getAmountIn(exactOutAmount, bin.price, swapForY, 0 /* Up */);
remainingOutAmount = remainingOutAmount.sub(exactOutAmount);
totalAmountIn = totalAmountIn.add(amountIn);
if (remainingOutAmount.gt(new (0, _bnjs2.default)(0))) {
exactOutAmount = _bnjs2.default.min(remainingOutAmount, openOrderAmount);
amountIn = getAmountIn(exactOutAmount, bin.price, swapForY, 0 /* Up */);
totalAmountIn = totalAmountIn.add(amountIn);
}
}
return totalAmountIn;
}
function swapExactOutQuoteAtBin(bin, binStep, sParameter, vParameter, outAmount, swapForY, supportLimitOrder, feeOnInput) {
const tradeFeeNumerator = getTotalFee(binStep, sParameter, vParameter);
let includedFeeAmountOut = outAmount;
if (!feeOnInput) {
const { includedFeeAmount } = getIncludedFeeAmount(
outAmount,
tradeFeeNumerator
);
includedFeeAmountOut = includedFeeAmount;
}
const maxAmountOut = getBinMaxAmountOut(bin, swapForY, supportLimitOrder);
if (includedFeeAmountOut.gte(maxAmountOut)) {
return swapExactInQuoteAtBin(
bin,
binStep,
sParameter,
vParameter,
U64_MAX,
swapForY,
supportLimitOrder,
feeOnInput
);
} else {
const excludedFeeAmountIn = getExcludedFeeAmountIn(
bin,
includedFeeAmountOut,
swapForY
);
let includedFeeAmountIn = excludedFeeAmountIn;
if (feeOnInput) {
const { includedFeeAmount } = getIncludedFeeAmount(
excludedFeeAmountIn,
tradeFeeNumerator
);
includedFeeAmountIn = includedFeeAmount;
}
let {
amountIn,
amountOut: quotedAmountOut,
fee,
protocolFee
} = swapExactInQuoteAtBin(
bin,
binStep,
sParameter,
vParameter,
includedFeeAmountIn,
swapForY,
supportLimitOrder,
feeOnInput
);
const delta = quotedAmountOut.sub(outAmount);
if (delta.gt(new (0, _bnjs2.default)(1))) {
protocolFee = protocolFee.add(delta);
}
return {
amountIn,
amountOut: outAmount,
fee,
protocolFee
};
}
}
function calculateExactInFillAmount(bin, amount, maxAmountOut, swapForY) {
const maxAmountIn = getAmountIn(
maxAmountOut,
bin.price,
swapForY,
0 /* Up */
);
if (amount.gte(maxAmountIn)) {
return {
amountIn: maxAmountIn,
amountLeft: amount.sub(maxAmountIn),
outAmount: maxAmountOut
};
} else {
const outAmount = getAmountOut(bin, amount, swapForY);
return {
amountIn: amount,
amountLeft: new (0, _bnjs2.default)(0),
outAmount
};
}
}
function getLimitOrderAmountsBySwapDirection(bin, swapForY) {
const isAskSide = Boolean(bin.limitOrderAskSide);
if (swapForY && !isAskSide || !swapForY && isAskSide) {
return {
openOrderAmount: bin.openOrderAmount,
processedOrderRemainingAmount: bin.processedOrderRemainingAmount
};
}
return {
openOrderAmount: new (0, _bnjs2.default)(0),
processedOrderRemainingAmount: new (0, _bnjs2.default)(0)
};
}
function getExactInFillAmountResult(bin, amountIn, swapForY, supportLimitOrder) {
const mmAmount = swapForY ? bin.amountY : bin.amountX;
const mmFillInResult = calculateExactInFillAmount(
bin,
amountIn,
mmAmount,
swapForY
);
if (!supportLimitOrder) {
return {
amountIn: mmFillInResult.amountIn,
amountLeft: mmFillInResult.amountLeft,
outAmount: mmFillInResult.outAmount,
mmAmountIn: mmFillInResult.amountIn,
mmAmountOut: mmFillInResult.outAmount
};
}
const amountLeftAfterMM = mmFillInResult.amountLeft;
let processedOrderAmountIn = new (0, _bnjs2.default)(0);
let processedOrderAmountOut = new (0, _bnjs2.default)(0);
let openOrderAmountIn = new (0, _bnjs2.default)(0);
let openOrderAmountOut = new (0, _bnjs2.default)(0);
if (!amountLeftAfterMM.isZero()) {
const { openOrderAmount, processedOrderRemainingAmount } = getLimitOrderAmountsBySwapDirection(bin, swapForY);
const remainingOrderFillInResult = calculateExactInFillAmount(
bin,
amountLeftAfterMM,
processedOrderRemainingAmount,
swapForY
);
processedOrderAmountIn = remainingOrderFillInResult.amountIn;
processedOrderAmountOut = remainingOrderFillInResult.outAmount;
if (!remainingOrderFillInResult.amountLeft.isZero()) {
const openOrderFillInResult = calculateExactInFillAmount(
bin,
remainingOrderFillInResult.amountLeft,
openOrderAmount,
swapForY
);
openOrderAmountIn = openOrderFillInResult.amountIn;
openOrderAmountOut = openOrderFillInResult.outAmount;
}
}
const totalAmountIn = mmFillInResult.amountIn.add(processedOrderAmountIn).add(openOrderAmountIn);
const totalAmountOut = mmFillInResult.outAmount.add(processedOrderAmountOut).add(openOrderAmountOut);
return {
amountIn: totalAmountIn,
amountLeft: amountIn.sub(totalAmountIn),
outAmount: totalAmountOut,
mmAmountIn: mmFillInResult.amountIn,
mmAmountOut: mmFillInResult.outAmount
};
}
function swapExactInQuoteAtBin(bin, binStep, sParameter, vParameter, inAmount, swapForY, supportLimitOrder, feeOnInput) {
let tradingFee = new (0, _bnjs2.default)(0);
let excludedFeeAmountIn = inAmount;
const tradeFeeNumerator = getTotalFee(binStep, sParameter, vParameter);
if (feeOnInput) {
const { excludedFeeAmount: amount, fee: fee2 } = getExcludedFeeAmount(
inAmount,
tradeFeeNumerator
);
tradingFee = fee2;
excludedFeeAmountIn = amount;
}
const fillAmountResult = getExactInFillAmountResult(
bin,
excludedFeeAmountIn,
swapForY,
supportLimitOrder
);
const amountLeft = fillAmountResult.amountLeft;
const outAmount = fillAmountResult.outAmount;
let includedFeeAmountIn = inAmount;
if (!amountLeft.isZero()) {
excludedFeeAmountIn = excludedFeeAmountIn.sub(amountLeft);
if (feeOnInput) {
const { includedFeeAmount: amount, fee: fee2 } = getIncludedFeeAmount(
excludedFeeAmountIn,
tradeFeeNumerator
);
tradingFee = fee2;
includedFeeAmountIn = amount;
} else {
includedFeeAmountIn = excludedFeeAmountIn;
}
}
let excludedFeeAmountOut = outAmount;
if (!feeOnInput) {
const { excludedFeeAmount: amount, fee: fee2 } = getExcludedFeeAmount(
outAmount,
tradeFeeNumerator
);
tradingFee = fee2;
excludedFeeAmountOut = amount;
}
const { fee, protocolFee } = splitFee(
tradingFee,
new (0, _bnjs2.default)(sParameter.protocolShare),
fillAmountResult.mmAmountIn,
fillAmountResult.amountIn
);
return {
amountIn: includedFeeAmountIn,
amountOut: excludedFeeAmountOut,
fee,
protocolFee
};
}
function getLimitOrderLiquidity(bin, supportLimitOrder) {
if (!supportLimitOrder) {
return {
orderAmountX: new (0, _bnjs2.default)(0),
orderAmountY: new (0, _bnjs2.default)(0)
};
}
const totalOrderAmount = bin.openOrderAmount.add(
bin.processedOrderRemainingAmount
);
const isAskSide = Boolean(bin.limitOrderAskSide);
if (isAskSide) {
return {
orderAmountX: totalOrderAmount,
orderAmountY: new (0, _bnjs2.default)(0)
};
} else {
return {
orderAmountX: new (0, _bnjs2.default)(0),
orderAmountY: totalOrderAmount
};
}
}
function getBinMaxAmountOut(bin, swapForY, supportLimitOrder) {
const { orderAmountX, orderAmountY } = getLimitOrderLiquidity(
bin,
supportLimitOrder
);
const totalAmount = swapForY ? bin.amountY.add(orderAmountY) : bin.amountX.add(orderAmountX);
return totalAmount;
}
// src/dlmm/helpers/oracle/wrapper.ts
var ORACLE_METADATA_SIZE = 8 + 24;
var OBSERVATION_SIZE = 32;
var Observation = class {
constructor(cumulativeActiveBinId, createdAt, lastUpdatedAt) {
this.cumulativeActiveBinId = cumulativeActiveBinId;
this.createdAt = createdAt;
this.lastUpdatedAt = lastUpdatedAt;
}
isInitialized() {
return !this.createdAt.isZero() && !this.lastUpdatedAt.isZero();
}
};
function wrapOracle(oracleAddress, data, binStep, currentActiveBinId, baseTokenDecimals, quoteTokenDecimals, program) {
const oracleBaseData = data.subarray(0, ORACLE_METADATA_SIZE);
const oracleState = decodeAccount(program, "oracle", oracleBaseData);
const observationSlice = data.subarray(ORACLE_METADATA_SIZE);
let observations = [];
for (let i = 0; i < oracleState.length.toNumber(); i++) {
let offset = i * OBSERVATION_SIZE;
const cumulativeActiveBinIdSlice = observationSlice.subarray(
offset,
offset + 16
);
const cumulativeActiveBinId = new (0, _bnjs2.default)(
cumulativeActiveBinIdSlice,
"le"
).fromTwos(128);
offset += 16;
const createdAtSlice = observationSlice.subarray(offset, offset + 8);
const createdAt = new (0, _bnjs2.default)(createdAtSlice, "le");
offset += 8;
const lastUpdatedAtSlice = observationSlice.subarray(offset, offset + 8);
const lastUpdatedAt = new (0, _bnjs2.default)(lastUpdatedAtSlice, "le");
observations.push(
new Observation(cumulativeActiveBinId, createdAt, lastUpdatedAt)
);
}
return new DynamicOracle(
oracleAddress,
oracleState,
observations,
binStep,
currentActiveBinId,
baseTokenDecimals,
quoteTokenDecimals
);
}
var DynamicOracle = class {
constructor(oracleAddress, metadata, observations, binStep, currentActiveBinId, baseTokenDecimals, quoteTokenDecimals) {
this.oracleAddress = oracleAddress;
this.metadata = metadata;
this.observations = observations;
this.binStep = binStep;
this.currentActiveBinId = currentActiveBinId;
this.baseTokenDecimals = baseTokenDecimals;
this.quoteTokenDecimals = quoteTokenDecimals;
}
nextIndex() {
const currentIndex = this.metadata.idx.toNumber();
const nextIndex = currentIndex + 1;
return nextIndex >= this.metadata.activeSize.toNumber() ? 0 : nextIndex;
}
getEarliestSample() {
const earliestIndex = this.nextIndex();
return this.observations[earliestIndex];
}
getLatestSample() {
return this.observations[this.metadata.idx.toNumber()];
}
findCumulativeActiveIdByTimestamp(activeId, timestamp) {
const latestSample = this.getLatestSample();
if (!latestSample.isInitialized()) {
return null;
}
if (timestamp.gte(latestSample.lastUpdatedAt)) {
const deltaSeconds = timestamp.sub(latestSample.lastUpdatedAt);
const accumulatedActiveId = activeId.mul(deltaSeconds);
return latestSample.cumulativeActiveBinId.add(accumulatedActiveId);
}
const earliestSample = this.getEarliestSample();
if (!earliestSample.isInitialized() || timestamp.lt(earliestSample.lastUpdatedAt)) {
return null;
}
let currentIndex = this.metadata.idx.toNumber();
while (true) {
let previousIndex = currentIndex == 0 ? this.metadata.activeSize.toNumber() - 1 : currentIndex - 1;
if (previousIndex == this.metadata.idx.toNumber()) {
return null;
}
const currentSample = this.observations[currentIndex];
const previousSample = this.observations[previousIndex];
if (timestamp.gte(previousSample.lastUpdatedAt)) {
const totalWeight = currentSample.lastUpdatedAt.sub(
previousSample.lastUpdatedAt
);
if (totalWeight.isZero()) {
return previousSample.cumulativeActiveBinId;
}
const prevWeight = currentSample.lastUpdatedAt.sub(timestamp);
const nextWeight = timestamp.sub(previousSample.lastUpdatedAt);
return previousSample.cumulativeActiveBinId.mul(prevWeight).add(currentSample.cumulativeActiveBinId.mul(nextWeight)).div(totalWeight);
}
currentIndex = previousIndex;
}
}
getActiveIdByTime(timePoint0, timePoint1) {
const t0 = _bnjs2.default.min(timePoint0, timePoint1);
const t1 = _bnjs2.default.max(timePoint0, timePoint1);
const duration = t1.sub(t0);
if (duration.isZero()) {
return null;
}
const cumulativeActiveBinId0 = this.findCumulativeActiveIdByTimestamp(
this.currentActiveBinId,
t0
);
if (cumulativeActiveBinId0 === null) {
return null;
}
const cumulativeActiveBinId1 = this.findCumulativeActiveIdByTimestamp(
this.currentActiveBinId,
t1
);
if (cumulativeActiveBinId1 === null) {
return null;
}
return {
value: cumulativeActiveBinId1.sub(cumulativeActiveBinId0).div(duration),
duration
};
}
getActiveId(currentTimestamp) {
const timePoint0 = this.getEarliestTimestamp();
if (timePoint0 === null) {
return null;
}
const timePoint1 = currentTimestamp;
return this.getActiveIdByTime(timePoint0, timePoint1);
}
getEarliestTimestamp() {
const earliestSample = this.getEarliestSample();
return earliestSample.isInitialized() ? earliestSample.lastUpdatedAt : null;
}
getPriceByTime(timePoint0, timePoint1) {
const result = this.getActiveIdByTime(timePoint0, timePoint1);
if (result === null) {
return null;
}
return {
value: getPriceOfBinByBinId(result.value.toNumber(), this.binStep),
duration: result.duration
};
}
getUiPriceByTime(timePoint0, timePoint1) {
const result = this.getPriceByTime(timePoint0, timePoint1);
if (result === null) {
return null;
}
const uiMultiplier = new (0, _decimaljs2.default)(10).pow(
this.baseTokenDecimals - this.quoteTokenDecimals
);
const quoteAdjustment = new (0, _decimaljs2.default)(10).pow(this.quoteTokenDecimals);
return {
value: result.value.mul(uiMultiplier).mul(quoteAdjustment).floor().div(quoteAdjustment),
duration: result.duration
};
}
getMaxDuration(currentTimestamp) {
const earliestTimestamp = this.getEarliestTimestamp();
if (earliestTimestamp === null) {
return new (0, _bnjs2.default)(0);
}
if (currentTimestamp.lte(earliestTimestamp)) {
return new (0, _bnjs2.default)(0);
}
return currentTimestamp.sub(earliestTimestamp);
}
};
// src/dlmm/helpers/index.ts
function chunks(array, size) {
return Array.apply(0, new Array(Math.ceil(array.length / size))).map(
(_, index) => array.slice(index * size, (index + 1) * size)
);
}
function range(min, max, mapfn) {
const length = max - min + 1;
return Array.from({ length }, (_, i) => mapfn(min + i));
}
async function chunkedFetchMultiplePoolAccount(program, pks, chunkSize = 100) {
const accounts = (await Promise.all(
chunks(pks, chunkSize).map(
(chunk) => program.account.lbPair.fetchMultiple(chunk)
)
)).flat();
return accounts.filter(Boolean);
}
async function chunkedFetchMultipleBinArrayBitmapExtensionAccount(program, pks, chunkSize = 100) {
const accounts = (await Promise.all(
chunks(pks, chunkSize).map(
(chunk) => program.account.binArrayBitmapExtension.fetchMultiple(chunk)
)
)).flat();
return accounts;
}
async function getTokenDecimals(conn, mint) {
const token = await _spltoken.getMint.call(void 0, conn, mint);
return await token.decimals;
}
var getOrCreateATAInstruction = async (connection, tokenMint, owner, programId, payer = owner, allowOwnerOffCurve = true) => {
programId = _nullishCoalesce(programId, () => ( _spltoken.TOKEN_PROGRAM_ID));
const toAccount = _spltoken.getAssociatedTokenAddressSync.call(void 0,
tokenMint,
owner,
allowOwnerOffCurve,
programId,
_spltoken.ASSOCIATED_TOKEN_PROGRAM_ID
);
try {
await _spltoken.getAccount.call(void 0, connection, toAccount, connection.commitment, programId);
return { ataPubKey: toAccount, ix: void 0 };
} catch (e) {
if (e instanceof _spltoken.TokenAccountNotFoundError || e instanceof _spltoken.TokenInvalidAccountOwnerError) {
const ix = _spltoken.createAssociatedTokenAccountIdempotentInstruction.call(void 0,
payer,
toAccount,
owner,
tokenMint,
programId,
_spltoken.ASSOCIATED_TOKEN_PROGRAM_ID
);
return { ataPubKey: toAccount, ix };
} else {
console.error("Error::getOrCreateATAInstruction", e);
throw e;
}
}
};
async function getTokenBalance(conn, tokenAccount) {
const acc = await _spltoken.getAccount.call(void 0, conn, tokenAccount);
return acc.amount;
}
var parseLogs = (eventParser, logs) => {
if (!logs.length)
throw new Error("No logs found");
for (const event of _optionalChain([eventParser, 'optionalAccess', _53 => _53.parseLogs, 'call', _54 => _54(logs)])) {
return event.data;
}
throw new Error("No events found");
};
var wrapSOLInstruction = (from, to, amount) => {
return [
_web3js.SystemProgram.transfer({
fromPubkey: from,
toPubkey: to,
lamports: amount
}),
new (0, _web3js.TransactionInstruction)({
keys: [
{
pubkey: to,
isSigner: false,
isWritable: true
}
],
data: Buffer.from(new Uint8Array([17])),
programId: _spltoken.TOKEN_PROGRAM_ID
})
];
};
var unwrapSOLInstruction = (owner, allowOwnerOffCurve = true) => {
const wSolATAAccount = _spltoken.getAssociatedTokenAddressSync.call(void 0,
_spltoken.NATIVE_MINT,
owner,
allowOwnerOffCurve
);
if (wSolATAAccount) {
const closedWrappedSolInstruction = _spltoken.createCloseAccountInstruction.call(void 0,
wSolATAAccount,
owner,
owner,
[],
_spltoken.TOKEN_PROGRAM_ID
);
return closedWrappedSolInstruction;
}
return null;
};
async function chunkedGetMultipleAccountInfos(connection, pks, chunkSize = 100) {
const accountInfos = (await Promise.all(
chunks(pks, chunkSize).map(
(chunk) => connection.getMultipleAccountsInfo(chunk)
)
)).flat();
return accountInfos;
}
async function chunkedGetProgramAccounts(connection, programId, filters, chunkSize = 100, onChunkFetched, isParallelExecution = false) {
const accountsWithoutData = await connection.getProgramAccounts(programId, {
filters,
dataSlice: { offset: 0, length: 0 }
});
if (accountsWithoutData.length === 0) {
return [];
}
const pubkeys = accountsWithoutData.map((account) => account.pubkey);
const totalAccounts = pubkeys.length;
const chunkedPks = chunks(pubkeys, chunkSize);
const totalChunks = chunkedPks.length;
let chunksLoaded = 0;
let accountsLoaded = 0;
const chunkResults = new Array(totalChunks);
const processChunk = async (chunk, chunkIndex) => {
const chunkAccountInfos = await connection.getMultipleAccountsInfo(chunk);
chunkResults[chunkIndex] = chunkAccountInfos;
if (onChunkFetched) {
const chunkAccounts = [];
const startIdx = chunkIndex * chunkSize;
for (let i = 0; i < chunkAccountInfos.length; i++) {
const accountInfo = chunkAccountInfos[i];
if (accountInfo) {
chunkAccounts.push({
pubkey: pubkeys[startIdx + i],
account: accountInfo
});
}
}
chunksLoaded++;
accountsLoaded += chunkAccounts.length;
onChunkFetched(chunkAccounts, {
chunksLoaded,
totalChunks,
accountsLoaded,
totalAccounts
});
}
};
if (isParallelExecution) {
await Promise.all(
chunkedPks.map((chunk, chunkIndex) => processChunk(chunk, chunkIndex))
);
} else {
for (let chunkIndex = 0; chunkIndex < chunkedPks.length; chunkIndex++) {
await processChunk(chunkedPks[chunkIndex], chunkIndex);
}
}
const result = [];
for (let chunkIndex = 0; chunkIndex < chunkResults.length; chunkIndex++) {
const chunkAccountInfos = chunkResults[chunkIndex];
const startIdx = chunkIndex * chunkSize;
for (let i = 0; i < chunkAccountInfos.length; i++) {
const accountInfo = chunkAccountInfos[i];
if (accountInfo) {
result.push({
pubkey: pubkeys[startIdx + i],
account: accountInfo
});
}
}
}
return result;
}
var getEstimatedComputeUnitUsageWithBuffer = async (connection, instructions, feePayer, buffer, altAddress) => {
if (!buffer) {
buffer = 0.1;
}
buffer = Math.max(0, buffer);
buffer = Math.min(1, buffer);
const altAccounts = [];
if (altAddress) {
const altAccountInfo = await connection.getAddressLookupTable(altAddress);
altAccounts.push(altAccountInfo.value);
}
const estimatedComputeUnitUsage = await getSimulationComputeUnits(
connection,
instructions,
feePayer,
altAccounts
);
let extraComputeUnitBuffer = estimatedComputeUnitUsage * buffer;
if (extraComputeUnitBuffer > MAX_CU_BUFFER) {
extraComputeUnitBuffer = MAX_CU_BUFFER;
} else if (extraComputeUnitBuffer < MIN_CU_BUFFER) {
extraComputeUnitBuffer = MIN_CU_BUFFER;
}
return estimatedComputeUnitUsage + extraComputeUnitBuffer;
};
var getEstimatedComputeUnitIxWithBuffer = async (connection, instructions, feePayer, buffer, altAddress) => {
const units = await getEstimatedComputeUnitUsageWithBuffer(
connection,
instructions,
feePayer,
buffer,
altAddress
).catch((error) => {
console.error("Error::getEstimatedComputeUnitUsageWithBuffer", error);
return 14e5;
});
return _web3js.ComputeBudgetProgram.setComputeUnitLimit({ units });
};
function createProgram(connection, opt) {
const cluster = _optionalChain([opt, 'optionalAccess', _55 => _55.cluster]) || "mainnet-beta";
const provider = new (0, _anchor.AnchorProvider)(
connection,
{},
_anchor.AnchorProvider.defaultOptions()
);
return new (0, _anchor.Program)(
{ ...idl_default, address: _nullishCoalesce(_optionalChain([opt, 'optionalAccess', _56 => _56.programId]), () => ( LBCLMM_PROGRAM_IDS[cluster])) },
provider
);
}
function decodeAccount(program, accountName, buffer) {
return program.coder.accounts.decode(accountName, buffer);
}
function getAccountDiscriminator(accountName) {
return _optionalChain([idl_default, 'access', _57 => _57.accounts, 'access', _58 => _58.find, 'call', _59 => _59(
(acc) => acc.name.toLowerCase() === accountName.toLowerCase()
), 'optionalAccess', _60 => _60.discriminator]);
}
function capSlippagePercentage(slippage) {
if (slippage > 100) {
slippage = 100;
}
if (slippage < 0) {
slippage = 0;
}
return slippage;
}
function getAndCapMaxActiveBinSlippage(slippagePercentage, binStep, maxActiveBinSlippage) {
return slippagePercentage ? Math.ceil(slippagePercentage / (binStep / 100)) : maxActiveBinSlippage;
}
function getBinCount(minBinId, maxBinId) {
return maxBinId - minBinId + 1;
}
function getSlippageMaxAmount(amount, slippage) {
if (slippage == 100) {
return U64_MAX;
}
const amountDecimal = new (0, _decimaljs2.default)(amount.toString());
const slippageAppliedAmount = new (0, _anchor.BN)(
amountDecimal.mul(new (0, _decimaljs2.default)(100 + slippage)).div(new (0, _decimaljs2.default)(100)).floor().toString()
);
return slippageAppliedAmount;
}
function getSlippageMinAmount(amount, slippage) {
const amountDecimal = new (0, _decimaljs2.default)(amount.toString());
return new (0, _anchor.BN)(
amountDecimal.mul(new (0, _decimaljs2.default)(100 - slippage)).div(new (0, _decimaljs2.default)(100)).ceil().toString()
);
}
function getPositionCountByBinCount(binCount) {
return Math.ceil(binCount / MAX_BINS_PER_POSITION.toNumber());
}
function resetUninvolvedLiquidityParams(minDeltaId, maxDeltaId, favorXInActiveId, params) {
const endBidSideDeltaId = favorXInActiveId ? new (0, _anchor.BN)(-1) : new (0, _anchor.BN)(0);
const startAskSideDeltaId = endBidSideDeltaId.addn(1);
let x0 = params.x0;
let y0 = params.y0;
let deltaX = params.deltaX;
let deltaY = params.deltaY;
if (maxDeltaId.lte(endBidSideDeltaId)) {
deltaX = new (0, _anchor.BN)(0);
x0 = new (0, _anchor.BN)(0);
}
if (minDeltaId.gte(startAskSideDeltaId)) {
deltaY = new (0, _anchor.BN)(0);
y0 = new (0, _anchor.BN)(0);
}
return {
x0,
y0,
deltaX,
deltaY
};
}
async function chunkDepositWithRebalanceEndpoint(dlmm, strategy, slippagePercentage, maxActiveBinSlippage, position, positionMinBinId, positionMaxBinId, liquidityStrategyParameters, owner, payer, isParallel, skipSolWrappingOperation = false) {
const { slices, accounts: transferHookAccounts } = dlmm.getPotentialToken2022IxDataAndAccounts(0 /* Liquidity */);
const userTokenX = _spltoken.getAssociatedTokenAddressSync.call(void 0,
dlmm.lbPair.tokenXMint,
owner,
true,
dlmm.tokenX.owner
);
const userTokenY = _spltoken.getAssociatedTokenAddressSync.call(void 0,
dlmm.lbPair.tokenYMint,
owner,
true,
dlmm.tokenY.owner
);
const createUserTokenXIx = _spltoken.createAssociatedTokenAccountIdempotentInstruction.call(void 0,
payer,
userTokenX,
owner,
dlmm.lbPair.tokenXMint,
dlmm.tokenX.owner
);
const createUserTokenYIx = _spltoken.createAssociatedTokenAccountIdempotentInstruction.call(void 0,
payer,
userTokenY,
owner,
dlmm.lbPair.tokenYMint,
dlmm.tokenY.owner
);
const bitmapPubkey = deriveBinArrayBitmapExtension(
dlmm.pubkey,
dlmm.program.programId
)[0];
let calculatedAddLiquidityCU = 0;
const chunkedAddLiquidityIx = [];
const chunkedBinRange = chunkBinRange(positionMinBinId, positionMaxBinId);
const binArrayOrBitmapInitTracking = /* @__PURE__ */ new Set();
for (let i = 0; i < chunkedBinRange.length; i++) {
const chunkMinBinId = chunkedBinRange[i].lowerBinId;
const chunkMaxBinId = chunkedBinRange[i].upperBinId;
const initBinArrayIxs = [];
const initBitmapIxs = [];
const binArrayIndexes = getBinArrayIndexesCoverage(
new (0, _anchor.BN)(chunkMinBinId),
new (0, _anchor.BN)(chunkMaxBinId)
);
const overflowDefaultBinArrayBitmap = binArrayIndexes.reduce(
(acc, binArrayIndex) => acc || isOverflowDefaultBinArrayBitmap(binArrayIndex),
false
);
if (overflowDefaultBinArrayBitmap) {
const initBitmapIx = await dlmm.program.methods.initializeBinArrayBitmapExtension().accountsPartial({
binArrayBitmapExtension: bitmapPubkey,
lbPair: dlmm.pubkey,
funder: payer,
rent: _web3js.SYSVAR_RENT_PUBKEY
}).instruction();
initBitmapIxs.push(initBitmapIx);
binArrayOrBitmapInitTracking.add(bitmapPubkey.toBase58());
}
const binArrayPubkeys = binArrayIndexes.map(
(index) => deriveBinArray(dlmm.pubkey, index, dlmm.program.programId)[0]
);
for (const [idx, binArrayPubkey] of binArrayPubkeys.entries()) {
const initBinArrayIx = await dlmm.program.methods.initializeBinArray(binArrayIndexes[idx]).accountsPartial({
binArray: binArrayPubkey,
funder: payer,
lbPair: dlmm.pubkey
}).instruction();
if (isParallel) {
initBinArrayIxs.push(initBinArrayIx);
} else if (!binArrayOrBitmapInitTracking.has(binArrayPubkey.toBase58())) {
binArrayOrBitmapInitTracking.add(binArrayPubkey.toBase58());
initBinArrayIxs.push(initBinArrayIx);
calculatedAddLiquidityCU += DEFAULT_INIT_BIN_ARRAY_CU;
}
}
const minDeltaId = new (0, _anchor.BN)(chunkMinBinId - dlmm.lbPair.activeId);
const maxDeltaId = new (0, _anchor.BN)(chunkMaxBinId - dlmm.lbPair.activeId);
const { deltaX, deltaY, x0, y0 } = resetUninvolvedLiquidityParams(
minDeltaId,
maxDeltaId,
strategy.singleSidedX,
{
...liquidityStrategyParameters
}
);
const { bitFlag, ...baseAndDelta } = buildBitFlagAndNegateStrategyParameters(x0, y0, deltaX, deltaY);
const addParam = {
minDeltaId: minDeltaId.toNumber(),
maxDeltaId: maxDeltaId.toNumber(),
x0: baseAndDelta.x0,
y0: baseAndDelta.y0,
deltaX: baseAndDelta.deltaX,
deltaY: baseAndDelta.deltaY,
bitFlag,
favorXInActiveId: strategy.singleSidedX,
padding: Array(36).fill(0)
};
const { totalXAmount, totalYAmount } = toAmountIntoBins(
new (0, _anchor.BN)(dlmm.lbPair.activeId),
minDeltaId,
maxDeltaId,
deltaX,
deltaY,
x0,
y0,
new (0, _anchor.BN)(dlmm.lbPair.binStep),
strategy.singleSidedX
).reduce(
(acc, bin) => {
return {
totalXAmount: acc.totalXAmount.add(bin.amountX),
totalYAmount: acc.totalYAmount.add(bin.amountY)
};
},
{
totalXAmount: new (0, _anchor.BN)(0),
totalYAmount: new (0, _anchor.BN)(0)
}
);
const totalXAmountIncludeTransferFee = calculateTransferFeeIncludedAmount(
totalXAmount,
dlmm.tokenX.mint,
dlmm.clock.epoch.toNumber()
).amount;
const totalYAmountIncludeTransferFee = calculateTransferFeeIncludedAmount(
totalYAmount,
dlmm.tokenY.mint,
dlmm.clock.epoch.toNumber()
).amount;
const maxDepositXAmount = getSlippageMaxAmount(
totalXAmountIncludeTransferFee,
slippagePercentage
);
const maxDepositYAmount = getSlippageMaxAmount(
totalYAmountIncludeTransferFee,
slippagePercentage
);
let shrinkMode;
if (isParallel) {
if (i == 0) {
shrinkMode = 2 /* NoShrinkRight */;
} else if (i == chunkBinRange.length - 1) {
shrinkMode = 1 /* NoShrinkLeft */;
} else {
shrinkMode = 3 /* NoShrinkBoth */;
}
} else {
shrinkMode = 0 /* ShrinkBoth */;
}
const rebalanceIx = await dlmm.program.methods.rebalanceLiquidity(
{
activeId: dlmm.lbPair.activeId,
maxActiveBinSlippage,
shouldClaimFee: false,
shouldClaimReward: false,
minWithdrawXAmount: new (0, _anchor.BN)(0),
minWithdrawYAmount: new (0, _anchor.BN)(0),
maxDepositXAmount,
maxDepositYAmount,
removes: [],
adds: [addParam],
shrinkMode,
padding: REBALANCE_POSITION_PADDING
},
{
slices
}
).accountsPartial({
binArrayBitmapExtension: initBitmapIxs.length > 0 ? bitmapPubkey : dlmm.program.programId,
lbPair: dlmm.pubkey,
position,
owner,
tokenXMint: dlmm.lbPair.tokenXMint,
tokenYMint: dlmm.lbPair.tokenYMint,
userTokenX,
userTokenY,
tokenXProgram: dlmm.tokenX.owner,
tokenYProgram: dlmm.tokenY.owner,
rentPayer: payer
}).remainingAccounts([
...transferHookAccounts,
...binArrayPubkeys.map((baPubkey) => ({
pubkey: baPubkey,
isWritable: true,
isSigner: false
})),
derivePlaceHolderAccountMeta(dlmm.program.programId)
]).instruction();
calculatedAddLiquidityCU += DEFAULT_ADD_LIQUIDITY_CU;
const addLiquidityIxs = [];
addLiquidityIxs.push(...initBitmapIxs, ...initBinArrayIxs);
if (isParallel) {
addLiquidityIxs.push(createUserTokenXIx);
addLiquidityIxs.push(createUserTokenYIx);
}
if (dlmm.tokenX.publicKey.equals(_spltoken.NATIVE_MINT) && !skipSolWrappingOperation) {
const wrapSOLIx = wrapSOLInstruction(
owner,
userTokenX,
BigInt(totalXAmount.toString())
);
if (!isParallel) {
addLiquidityIxs.push(createUserTokenXIx);
}
addLiquidityIxs.push(...wrapSOLIx);
}
if (dlmm.tokenY.publicKey.equals(_spltoken.NATIVE_MINT) && !skipSolWrappingOperation) {
const wrapSOLIx = wrapSOLInstruction(
owner,
userTokenY,
BigInt(totalYAmount.toString())
);
if (!isParallel) {
addLiquidityIxs.push(createUserTokenYIx);
}
addLiquidityIxs.push(...wrapSOLIx);
}
addLiquidityIxs.push(rebalanceIx);
if (dlmm.tokenX.publicKey.equals(_spltoken.NATIVE_MINT) && !totalXAmount.isZero() && !skipSolWrappingOperation) {
addLiquidityIxs.push(
_spltoken.createCloseAccountInstruction.call(void 0,
userTokenX,
owner,
owner,
[],
_spltoken.TOKEN_PROGRAM_ID
)
);
}
if (dlmm.tokenY.publicKey.equals(_spltoken.NATIVE_MINT) && !totalYAmount.isZero() && !skipSolWrappingOperation) {
addLiquidityIxs.push(
_spltoken.createCloseAccountInstruction.call(void 0,
userTokenY,
owner,
owner,
[],
_spltoken.TOKEN_PROGRAM_ID
)
);
}
if (!isParallel) {
addLiquidityIxs.unshift(
_web3js.ComputeBudgetProgram.setComputeUnitLimit({
units: Math.min(calculatedAddLiquidityCU, MAX_CU)
})
);
}
chunkedAddLiquidityIx.push(addLiquidityIxs);
}
return chunkedAddLiquidityIx;
}
function encodePositionPermissions(permissions) {
return permissions.reduce((acc, perm) => {
return acc | 1 << perm;
}, 0);
}
// src/dlmm/helpers/accountFilters.ts
var _bytes = require('@coral-xyz/anchor/dist/cjs/utils/bytes');
var presetParameter2BinStepFilter = (binStep) => {
return {
memcmp: {
bytes: _bytes.bs58.encode(binStep.toArrayLike(Buffer, "le", 2)),
offset: 8
}
};
};
var presetParameter2BaseFactorFilter = (baseFactor) => {
return {
memcmp: {
bytes: _bytes.bs58.encode(baseFactor.toArrayLike(Buffer, "le", 2)),
offset: 8 + 2
}
};
};
var presetParameter2BaseFeePowerFactor = (baseFeePowerFactor) => {
return {
memcmp: {
bytes: _bytes.bs58.encode(baseFeePowerFactor.toArrayLike(Buffer, "le", 1)),
offset: 8 + 22
}
};
};
var binArrayLbPairFilter = (lbPair) => {
return {
memcmp: {
bytes: lbPair.toBase58(),
offset: 8 + 16
}
};
};
var positionOwnerFilter = (owner) => {
return {
memcmp: {
bytes: owner.toBase58(),
offset: 8 + 32
}
};
};
var positionLbPairFilter = (lbPair) => {
return {
memcmp: {
bytes: _bytes.bs58.encode(lbPair.toBuffer()),
offset: 8
}
};
};
var positionV2Filter = () => {
return {
memcmp: {
bytes: _bytes.bs58.encode(Buffer.from(getAccountDiscriminator("positionV2"))),
offset: 0
}
};
};
var limitOrderFilter = () => {
return {
memcmp: {
bytes: _bytes.bs58.encode(Buffer.from(getAccountDiscriminator("limitOrder"))),
offset: 0
}
};
};
var limitOrderOwnerFilter = (owner) => {
return {
memcmp: {
bytes: owner.toBase58(),
offset: 8 + 32
}
};
};
var limitOrderLbPairFilter = (lbPair) => {
return {
memcmp: {
bytes: lbPair.toBase58(),
offset: 8
}
};
};
// src/dlmm/helpers/rebalance/strategy/balanced.ts
// src/dlmm/helpers/rebalance/strategy/index.ts
var MAX_BPS = new (0, _bnjs2.default)(BASIS_POINT_MAX);
function capBps(bps) {
return bps.lt(new (0, _bnjs2.default)(0)) ? new (0, _bnjs2.default)(0) : bps.gt(MAX_BPS) ? new (0, _bnjs2.default)(MAX_BPS) : bps;
}
// src/dlmm/helpers/rebalance/strategy/balanced.ts
var BalancedStrategyBuilder = class {
constructor(activeId, binStep, positionData, topUpAmountX, topUpAmountY, xWithdrawBps, yWithdrawBps, strategy, favorXIfImbalance = false, favorXInActiveBin = false) {
this.activeId = activeId;
this.binStep = binStep;
this.positionData = positionData;
this.topUpAmountX = topUpAmountX;
this.topUpAmountY = topUpAmountY;
this.xWithdrawBps = xWithdrawBps;
this.yWithdrawBps = yWithdrawBps;
this.strategy = strategy;
this.favorXIfImbalance = favorXIfImbalance;
this.favorXInActiveBin = favorXInActiveBin;
}
// Rebalance to active bin by withdrawing all liquidities and redeposit portion of withdrawn liquidity, together with topup amount
buildRebalanceStrategyParameters() {
const xWithdrawBps = capBps(this.xWithdrawBps);
const yWithdrawBps = capBps(this.yWithdrawBps);
let totalXAmountOut = new (0, _bnjs2.default)(this.positionData.totalXAmount);
let totalYAmountOut = new (0, _bnjs2.default)(this.positionData.totalYAmount);
totalXAmountOut = totalXAmountOut.add(new (0, _bnjs2.default)(this.positionData.feeX));
totalYAmountOut = totalYAmountOut.add(new (0, _bnjs2.default)(this.positionData.feeY));
const redepositAmountX = totalXAmountOut.mul(MAX_BPS.sub(xWithdrawBps)).div(MAX_BPS);
const redepositAmountY = totalYAmountOut.mul(MAX_BPS.sub(yWithdrawBps)).div(MAX_BPS);
const depositAmountX = this.topUpAmountX.add(redepositAmountX);
const depositAmountY = this.topUpAmountY.add(redepositAmountY);
const width = this.positionData.upperBinId - this.positionData.lowerBinId + 1;
const binPerSide = Math.floor(width / 2);
const rem = width % 2;
let binPerAsk = binPerSide;
let binPerBid = binPerSide;
if (rem == 0) {
if (this.favorXIfImbalance) {
binPerAsk += 1;
binPerBid -= 1;
} else {
binPerAsk -= 1;
binPerBid += 1;
}
}
const minDeltaId = new (0, _bnjs2.default)(binPerBid).neg();
const maxDeltaId = new (0, _bnjs2.default)(binPerAsk);
const strategyParameters = buildLiquidityStrategyParameters(
depositAmountX,
depositAmountY,
minDeltaId,
maxDeltaId,
this.binStep,
this.favorXInActiveBin,
this.activeId,
getLiquidityStrategyParameterBuilder(this.strategy)
);
const depositParam = {
minDeltaId,
maxDeltaId,
x0: strategyParameters.x0,
y0: strategyParameters.y0,
deltaX: strategyParameters.deltaX,
deltaY: strategyParameters.deltaY,
favorXInActiveBin: this.favorXInActiveBin
};
const withdrawParam = {
minBinId: new (0, _bnjs2.default)(this.positionData.lowerBinId),
maxBinId: new (0, _bnjs2.default)(this.positionData.upperBinId),
bps: MAX_BPS
};
return {
shouldClaimFee: true,
shouldClaimReward: true,
deposits: [depositParam],
withdraws: [withdrawParam]
};
}
};
// src/dlmm/helpers/limitOrders/wrapper.ts
var LimitOrderBinDataWrapper = class {
constructor(inner) {
this.inner = inner;
}
amount() {
return this.inner.amount;
}
age() {
return this.inner.age;
}
binId() {
return this.inner.binId;
}
isAsk() {
return Boolean(this.inner.isAsk);
}
isEmpty() {
return this.inner.age == 0 && this.inner.amount.isZero();
}
};
var LimitOrderV1Wrapper = class {
constructor(limitOrderAddress, inner, limitOrderBinData) {
this.limitOrderAddress = limitOrderAddress;
this.inner = inner;
this.limitOrderBinData = limitOrderBinData;
}
address() {
return this.limitOrderAddress;
}
lbPair() {
return this.inner.lbPair;
}
owner() {
return this.inner.owner;
}
binCount() {
return this.inner.binCount;
}
orders() {
return this.limitOrderBinData;
}
getBinArrayIndexesCoverage() {
const binArrayIndexes = /* @__PURE__ */ new Set();
for (const bin of this.limitOrderBinData) {
const binArrayIndex = binIdToBinArrayIndex(new (0, _bnjs2.default)(bin.binId()));
binArrayIndexes.add(binArrayIndex.toNumber());
}
return [...binArrayIndexes].map((index) => new (0, _bnjs2.default)(index));
}
getBinArrayKeysCoverage(programId) {
return this.getBinArrayIndexesCoverage().map(
(index) => deriveBinArray(this.lbPair(), index, programId)[0]
);
}
parseInfo(programId, lbPair, baseMint, quoteMint, clock, binArrayMap) {
let totalAmountXDeposited = new (0, _bnjs2.default)(0);
let totalAmountYDeposited = new (0, _bnjs2.default)(0);
let totalFilledAmountX = new (0, _bnjs2.default)(0);
let totalFilledAmountY = new (0, _bnjs2.default)(0);
let totalUnfilledAmountX = new (0, _bnjs2.default)(0);
let totalUnfilledAmountY = new (0, _bnjs2.default)(0);
let totalSwappedAmountX = new (0, _bnjs2.default)(0);
let totalSwappedAmountY = new (0, _bnjs2.default)(0);
let totalFeeAmountX = new (0, _bnjs2.default)(0);
let totalFeeAmountY = new (0, _bnjs2.default)(0);
const collectFeeMode = lbPair.parameters.collectFeeMode;
const parsedLimitOrderBinData = [];
const tokenXUiMultiplier = new (0, _decimaljs2.default)(10).pow(
new (0, _decimaljs2.default)(baseMint.decimals)
);
const tokenYUiMultiplier = new (0, _decimaljs2.default)(10).pow(
new (0, _decimaljs2.default)(quoteMint.decimals)
);
for (const loBin of this.limitOrderBinData) {
const binArrayIndex = binIdToBinArrayIndex(new (0, _bnjs2.default)(loBin.binId()));
const binArrayPubkey = deriveBinArray(
this.lbPair(),
binArrayIndex,
programId
)[0];
const binArrayState = binArrayMap.get(binArrayPubkey.toString());
if (!binArrayState) {
throw new Error("Missing bin array for limit order");
}
const bin = getBinFromBinArray(loBin.binId(), binArrayState);
if (!bin) {
throw new Error("Missing bin for limit order");
}
const limitOrderStatus = getLimitOrderStatus(loBin, bin);
const updatedLimitOrderAmount = getUpdatedLimitOrderAmount(
limitOrderStatus,
loBin,
bin,
collectFeeMode
);
let depositAmountX = new (0, _bnjs2.default)(0);
let depositAmountY = new (0, _bnjs2.default)(0);
let swappedAmountX = new (0, _bnjs2.default)(0);
let swappedAmountY = new (0, _bnjs2.default)(0);
let filledAmountX = new (0, _bnjs2.default)(0);
let filledAmountY = new (0, _bnjs2.default)(0);
let unFilledAmountX = new (0, _bnjs2.default)(0);
let unFilledAmountY = new (0, _bnjs2.default)(0);
let feeAmountX = new (0, _bnjs2.default)(0);
let feeAmountY = new (0, _bnjs2.default)(0);
if (loBin.isAsk()) {
depositAmountX = loBin.amount();
filledAmountX = updatedLimitOrderAmount.fulFilledAmount;
unFilledAmountX = updatedLimitOrderAmount.unFilledAmount;
swappedAmountY = updatedLimitOrderAmount.swappedAmount;
} else {
depositAmountY = loBin.amount();
filledAmountY = updatedLimitOrderAmount.fulFilledAmount;
unFilledAmountY = updatedLimitOrderAmount.unFilledAmount;
swappedAmountX = updatedLimitOrderAmount.swappedAmount;
}
feeAmountX = updatedLimitOrderAmount.feeXAmount;
feeAmountY = updatedLimitOrderAmount.feeYAmount;
totalFeeAmountX = totalFeeAmountX.add(feeAmountX);
totalFeeAmountY = totalFeeAmountY.add(feeAmountY);
totalAmountXDeposited = totalAmountXDeposited.add(depositAmountX);
totalAmountYDeposited = totalAmountYDeposited.add(depositAmountY);
totalFilledAmountX = totalFilledAmountX.add(filledAmountX);
totalFilledAmountY = totalFilledAmountY.add(filledAmountY);
totalUnfilledAmountX = totalUnfilledAmountX.add(unFilledAmountX);
totalUnfilledAmountY = totalUnfilledAmountY.add(unFilledAmountY);
totalSwappedAmountX = totalSwappedAmountX.add(swappedAmountX);
totalSwappedAmountY = totalSwappedAmountY.add(swappedAmountY);
parsedLimitOrderBinData.push({
binId: loBin.binId(),
empty: loBin.isEmpty(),
depositAmountX: new (0, _decimaljs2.default)(depositAmountX.toString()).div(tokenXUiMultiplier).toString(),
depositAmountY: new (0, _decimaljs2.default)(depositAmountY.toString()).div(tokenYUiMultiplier).toString(),
unfilledAmountX: new (0, _decimaljs2.default)(unFilledAmountX.toString()).div(tokenXUiMultiplier).toString(),
unfilledAmountY: new (0, _decimaljs2.default)(unFilledAmountY.toString()).div(tokenYUiMultiplier).toString(),
swappedAmountX: new (0, _decimaljs2.default)(swappedAmountX.toString()).div(tokenXUiMultiplier).toString(),
swappedAmountY: new (0, _decimaljs2.default)(swappedAmountY.toString()).div(tokenYUiMultiplier).toString(),
isAskSide: loBin.isAsk(),
filledAmountX: new (0, _decimaljs2.default)(filledAmountX.toString()).div(tokenXUiMultiplier).toString(),
filledAmountY: new (0, _decimaljs2.default)(filledAmountY.toString()).div(tokenYUiMultiplier).toString(),
feeAmountX: new (0, _decimaljs2.default)(feeAmountX.toString()).div(tokenXUiMultiplier).toString(),
feeAmountY: new (0, _decimaljs2.default)(feeAmountY.toString()).div(tokenYUiMultiplier).toString(),
status: limitOrderStatus
});
}
const totalXAmount = totalFeeAmountX.add(totalSwappedAmountX).add(totalUnfilledAmountX);
const totalYAmount = totalFeeAmountY.add(totalSwappedAmountY).add(totalUnfilledAmountY);
const transferFeeExcludedWithdrawableAmountX = calculateTransferFeeExcludedAmount(
totalXAmount,
baseMint,
clock.epoch.toNumber()
).amount;
const transferFeeExcludedWithdrawableAmountY = calculateTransferFeeExcludedAmount(
totalYAmount,
quoteMint,
clock.epoch.toNumber()
).amount;
return {
totalDepositAmountX: new (0, _decimaljs2.default)(totalAmountXDeposited.toString()).div(tokenXUiMultiplier).toString(),
totalDepositAmountY: new (0, _decimaljs2.default)(totalAmountYDeposited.toString()).div(tokenYUiMultiplier).toString(),
limitOrderBinData: parsedLimitOrderBinData,
totalUnfilledAmountX: new (0, _decimaljs2.default)(totalUnfilledAmountX.toString()).div(tokenXUiMultiplier).toString(),
totalUnfilledAmountY: new (0, _decimaljs2.default)(totalUnfilledAmountY.toString()).div(tokenYUiMultiplier).toString(),
totalFilledAmountX: new (0, _decimaljs2.default)(totalFilledAmountX.toString()).div(tokenXUiMultiplier).toString(),
totalFilledAmountY: new (0, _decimaljs2.default)(totalFilledAmountY.toString()).div(tokenYUiMultiplier).toString(),
totalSwappedAmountX: new (0, _decimaljs2.default)(totalSwappedAmountX.toString()).div(tokenXUiMultiplier).toString(),
totalSwappedAmountY: new (0, _decimaljs2.default)(totalSwappedAmountY.toString()).div(tokenYUiMultiplier).toString(),
totalFeeAmountX: new (0, _decimaljs2.default)(totalFeeAmountX.toString()).div(tokenXUiMultiplier).toString(),
totalFeeAmountY: new (0, _decimaljs2.default)(totalFeeAmountY.toString()).div(tokenYUiMultiplier).toString(),
transferFeeExcludedWithdrawableAmountX: new (0, _decimaljs2.default)(
transferFeeExcludedWithdrawableAmountX.toString()
).div(tokenXUiMultiplier).toString(),
transferFeeExcludedWithdrawableAmountY: new (0, _decimaljs2.default)(
transferFeeExcludedWithdrawableAmountY.toString()
).div(tokenYUiMultiplier).toString()
};
}
};
function getUpdatedLimitOrderAmount(limitOrderStatus, limitOrderData, bin, collectFeeMode) {
let fulFilledAmount = new (0, _bnjs2.default)(0);
let unFilledAmount = new (0, _bnjs2.default)(0);
switch (limitOrderStatus) {
case 0 /* NotFilled */:
unFilledAmount = limitOrderData.amount();
break;
case 1 /* PartialFilled */:
unFilledAmount = limitOrderData.amount().mul(bin.processedOrderRemainingAmount).add(bin.totalProcessingOrderAmount.sub(new (0, _bnjs2.default)(1))).div(bin.totalProcessingOrderAmount);
fulFilledAmount = limitOrderData.amount().sub(unFilledAmount);
break;
case 2 /* Fulfilled */:
fulFilledAmount = limitOrderData.amount();
break;
}
const swappedAmount = getAmountIn(
fulFilledAmount,
bin.price,
!limitOrderData.isAsk(),
1 /* Down */
);
const { feeX, feeY } = calculateLimitOrderFee(
fulFilledAmount,
limitOrderData.isAsk(),
collectFeeMode,
bin
);
return {
fulFilledAmount,
unFilledAmount,
swappedAmount,
feeXAmount: feeX,
feeYAmount: feeY
};
}
function calculateLimitOrderFee(fulfilledAmount, isAskSide, collectFeeMode, bin) {
if (fulfilledAmount.isZero() || bin.fulfilledOrderAmountX.isZero() && isAskSide || bin.fulfilledOrderAmountY.isZero() && !isAskSide) {
return {
feeX: new (0, _bnjs2.default)(0),
feeY: new (0, _bnjs2.default)(0)
};
}
let limitOrderFee = new (0, _bnjs2.default)(0);
if (isAskSide) {
limitOrderFee = bin.limitOrderFeeAskSide.mul(fulfilledAmount).div(bin.fulfilledOrderAmountX);
} else {
limitOrderFee = bin.limitOrderFeeBidSide.mul(fulfilledAmount).div(bin.fulfilledOrderAmountY);
}
switch (collectFeeMode) {
case 0 /* InputOnly */:
if (isAskSide) {
return {
feeX: new (0, _bnjs2.default)(0),
feeY: limitOrderFee
};
} else {
return {
feeX: limitOrderFee,
feeY: new (0, _bnjs2.default)(0)
};
}
case 1 /* OnlyY */:
return {
feeX: new (0, _bnjs2.default)(0),
feeY: limitOrderFee
};
}
}
function getLimitOrderStatus(limitOrderBinData, bin) {
if (limitOrderBinData.age() == bin.orderAge) {
return 0 /* NotFilled */;
} else if (limitOrderBinData.age() + 1 == bin.orderAge) {
if (bin.openOrderAmount.isZero() && bin.processedOrderRemainingAmount.isZero()) {
return 2 /* Fulfilled */;
} else {
return 1 /* PartialFilled */;
}
} else if (limitOrderBinData.age() + 2 <= bin.orderAge) {
return 2 /* Fulfilled */;
} else {
throw new Error("Fail to get limit order status");
}
}
function wrapLimitOrder(program, key, account) {
const disc = account.data.subarray(0, 8);
if (disc.equals(Buffer.from(getAccountDiscriminator("limitOrder")))) {
const state = decodeAccount(
program,
"limitOrder",
account.data
);
const limitOrderBinData = decodeLimitOrderBinData(
state,
program,
account.data.subarray(8 + LIMIT_ORDER_MIN_SIZE)
).map((binData) => new LimitOrderBinDataWrapper(binData));
return new LimitOrderV1Wrapper(key, state, limitOrderBinData);
} else {
throw new Error("Unknown position account");
}
}
// src/dlmm/helpers/limitOrders/index.ts
function decodeLimitOrderBinData(limitOrder, program, bytes) {
const limitOrderBinData = [];
for (let i = 0; i < limitOrder.binCount; i++) {
const offset = i * LIMIT_ORDER_BIN_DATA_SIZE;
const data = bytes.subarray(offset, offset + LIMIT_ORDER_BIN_DATA_SIZE);
const decodedLimitOrderBinData = program.coder.types.decode(
// TODO: Find a type safe way
"limitOrderBinData",
data
);
limitOrderBinData.push(decodedLimitOrderBinData);
}
return limitOrderBinData;
}
// src/dlmm/index.ts
var DLMM = class {
constructor(pubkey, program, lbPair, binArrayBitmapExtension, tokenX, tokenY, rewards, clock, opt) {
this.pubkey = pubkey;
this.program = program;
this.lbPair = lbPair;
this.binArrayBitmapExtension = binArrayBitmapExtension;
this.tokenX = tokenX;
this.tokenY = tokenY;
this.rewards = rewards;
this.clock = clock;
this.opt = opt;
}
/** Static public method */
/**
* The function `getLbPairs` retrieves a list of LB pair accounts using a connection and optional
* parameters.
* @param {Connection} connection - The `connection` parameter is an instance of the `Connection`
* class, which represents the connection to the Solana blockchain network.
* @param {Opt} [opt] - The `opt` parameter is an optional object that contains additional options
* for the function. It can have the following properties:
* @returns The function `getLbPairs` returns a Promise that resolves to an array of
* `LbPairAccount` objects.
*/
static async getLbPairs(connection, opt) {
const program = createProgram(connection, opt);
return program.account.lbPair.all();
}
/**
* Retrieves the public key of a LB pair if it exists. This function expect the RPC have getProgramAccounts RPC method enabled.
* @param connection The connection to the Solana cluster.
* @param tokenX The mint address of token X.
* @param tokenY The mint address of token Y.
* @param binStep The bin step of the LB pair.
* @param baseFactor The base factor of the LB pair.
* @param baseFeePowerFactor The base fee power factor of the LB pair. It allow small bin step to have bigger fee rate.
* @param opt Optional parameters.
* @returns The public key of the LB pair if it exists, or null.
*/
static async getPairPubkeyIfExists(connection, tokenX, tokenY, binStep, baseFactor, baseFeePowerFactor, concreteFunctionType, collectFeeMode, opt) {
const program = createProgram(connection, opt);
const [lbPair2Key] = deriveLbPair2(
tokenX,
tokenY,
binStep,
baseFactor,
program.programId
);
const account2 = await program.account.lbPair.fetchNullable(lbPair2Key);
if (account2 && account2.parameters.baseFeePowerFactor == baseFeePowerFactor.toNumber()) {
return lbPair2Key;
}
const [lbPairKey] = deriveLbPair(
tokenX,
tokenY,
binStep,
program.programId
);
const account = await program.account.lbPair.fetchNullable(lbPairKey);
if (account && account.parameters.baseFactor === baseFactor.toNumber() && account.parameters.baseFeePowerFactor === baseFeePowerFactor.toNumber()) {
return lbPairKey;
}
let presetParametersWithIndex = await program.account.presetParameter2.all([
presetParameter2BinStepFilter(binStep),
presetParameter2BaseFactorFilter(baseFactor),
presetParameter2BaseFeePowerFactor(baseFeePowerFactor)
]);
presetParametersWithIndex = presetParametersWithIndex.filter((p) => {
return p.account.concreteFunctionType == (_nullishCoalesce(concreteFunctionType, () => ( 1)) /* LiquidityMining */) && p.account.collectFeeMode == (_nullishCoalesce(collectFeeMode, () => ( 0)) /* InputOnly */);
});
if (presetParametersWithIndex.length > 0) {
const possibleLbPairKeys = presetParametersWithIndex.map((account3) => {
return deriveLbPairWithPresetParamWithIndexKey(
account3.publicKey,
tokenX,
tokenY,
program.programId
)[0];
});
const accounts = await chunkedGetMultipleAccountInfos(
program.provider.connection,
possibleLbPairKeys
);
for (let i = 0; i < possibleLbPairKeys.length; i++) {
const pairKey = possibleLbPairKeys[i];
const account3 = accounts[i];
if (account3) {
return pairKey;
}
}
}
return null;
}
static async getCustomizablePermissionlessLbPairIfExists(connection, tokenX, tokenY, opt) {
const program = createProgram(connection, opt);
try {
const [lpPair] = deriveCustomizablePermissionlessLbPair(
tokenX,
tokenY,
program.programId
);
const account = await program.account.lbPair.fetchNullable(lpPair);
if (account)
return lpPair;
return null;
} catch (error) {
return null;
}
}
/**
* The `create` function is a static method that creates a new instance of the `DLMM` class
* @param {Connection} connection - The `connection` parameter is an instance of the `Connection`
* class, which represents the connection to the Solana blockchain network.
* @param {PublicKey} dlmm - The PublicKey of LB Pair.
* @param {Opt} [opt] - The `opt` parameter is an optional object that can contain additional options
* for the `create` function. It has the following properties:
* @returns The `create` function returns a `Promise` that resolves to a `DLMM` object.
*/
static async create(connection, dlmm, opt) {
const program = createProgram(connection, opt);
const binArrayBitMapExtensionPubkey = deriveBinArrayBitmapExtension(
dlmm,
program.programId
)[0];
let accountsToFetch = [
dlmm,
binArrayBitMapExtensionPubkey,
_web3js.SYSVAR_CLOCK_PUBKEY
];
const accountsInfo = await chunkedGetMultipleAccountInfos(
connection,
accountsToFetch
);
const lbPairAccountInfoBuffer = _optionalChain([accountsInfo, 'access', _61 => _61[0], 'optionalAccess', _62 => _62.data]);
if (!lbPairAccountInfoBuffer)
throw new Error(`LB Pair account ${dlmm.toBase58()} not found`);
const lbPairAccInfo = decodeAccount(
program,
"lbPair",
lbPairAccountInfoBuffer
);
const binArrayBitMapAccountInfoBuffer = _optionalChain([accountsInfo, 'access', _63 => _63[1], 'optionalAccess', _64 => _64.data]);
let binArrayBitMapExtensionAccInfo = null;
if (binArrayBitMapAccountInfoBuffer) {
binArrayBitMapExtensionAccInfo = decodeAccount(
program,
"binArrayBitmapExtension",
binArrayBitMapAccountInfoBuffer
);
}
const clockAccountInfoBuffer = _optionalChain([accountsInfo, 'access', _65 => _65[2], 'optionalAccess', _66 => _66.data]);
if (!clockAccountInfoBuffer)
throw new Error(`Clock account not found`);
const clock = ClockLayout.decode(clockAccountInfoBuffer);
accountsToFetch = [
lbPairAccInfo.reserveX,
lbPairAccInfo.reserveY,
lbPairAccInfo.tokenXMint,
lbPairAccInfo.tokenYMint,
lbPairAccInfo.rewardInfos[0].vault,
lbPairAccInfo.rewardInfos[1].vault,
lbPairAccInfo.rewardInfos[0].mint,
lbPairAccInfo.rewardInfos[1].mint
];
const [
reserveXAccount,
reserveYAccount,
tokenXMintAccount,
tokenYMintAccount,
reward0VaultAccount,
reward1VaultAccount,
reward0MintAccount,
reward1MintAccount
] = await chunkedGetMultipleAccountInfos(
program.provider.connection,
accountsToFetch
);
let binArrayBitmapExtension;
if (binArrayBitMapExtensionAccInfo) {
binArrayBitmapExtension = {
account: binArrayBitMapExtensionAccInfo,
publicKey: binArrayBitMapExtensionPubkey
};
}
const reserveXBalance = _spltoken.AccountLayout.decode(reserveXAccount.data);
const reserveYBalance = _spltoken.AccountLayout.decode(reserveYAccount.data);
const mintX = _spltoken.unpackMint.call(void 0,
lbPairAccInfo.tokenXMint,
tokenXMintAccount,
tokenXMintAccount.owner
);
const mintY = _spltoken.unpackMint.call(void 0,
lbPairAccInfo.tokenYMint,
tokenYMintAccount,
tokenYMintAccount.owner
);
const [
tokenXTransferHook,
tokenYTransferHook,
reward0TransferHook,
reward1TransferHook
] = await Promise.all([
getExtraAccountMetasForTransferHook(
connection,
lbPairAccInfo.tokenXMint,
tokenXMintAccount
),
getExtraAccountMetasForTransferHook(
connection,
lbPairAccInfo.tokenYMint,
tokenYMintAccount
),
reward0MintAccount ? getExtraAccountMetasForTransferHook(
connection,
lbPairAccInfo.rewardInfos[0].mint,
reward0MintAccount
) : [],
reward1MintAccount ? getExtraAccountMetasForTransferHook(
connection,
lbPairAccInfo.rewardInfos[1].mint,
reward1MintAccount
) : []
]);
const tokenX = {
publicKey: lbPairAccInfo.tokenXMint,
reserve: lbPairAccInfo.reserveX,
amount: reserveXBalance.amount,
mint: mintX,
owner: tokenXMintAccount.owner,
transferHookAccountMetas: tokenXTransferHook
};
const tokenY = {
publicKey: lbPairAccInfo.tokenYMint,
reserve: lbPairAccInfo.reserveY,
amount: reserveYBalance.amount,
mint: mintY,
owner: tokenYMintAccount.owner,
transferHookAccountMetas: tokenYTransferHook
};
const reward0 = !lbPairAccInfo.rewardInfos[0].mint.equals(
_web3js.PublicKey.default
) ? {
publicKey: lbPairAccInfo.rewardInfos[0].mint,
reserve: lbPairAccInfo.rewardInfos[0].vault,
amount: _spltoken.AccountLayout.decode(reward0VaultAccount.data).amount,
mint: _spltoken.unpackMint.call(void 0,
lbPairAccInfo.rewardInfos[0].mint,
reward0MintAccount,
reward0MintAccount.owner
),
owner: reward0MintAccount.owner,
transferHookAccountMetas: reward0TransferHook
} : null;
const reward1 = !lbPairAccInfo.rewardInfos[1].mint.equals(
_web3js.PublicKey.default
) ? {
publicKey: lbPairAccInfo.rewardInfos[1].mint,
reserve: lbPairAccInfo.rewardInfos[1].vault,
amount: _spltoken.AccountLayout.decode(reward1VaultAccount.data).amount,
mint: _spltoken.unpackMint.call(void 0,
lbPairAccInfo.rewardInfos[1].mint,
reward1MintAccount,
reward1MintAccount.owner
),
owner: reward1MintAccount.owner,
transferHookAccountMetas: reward1TransferHook
} : null;
return new DLMM(
dlmm,
program,
lbPairAccInfo,
binArrayBitmapExtension,
tokenX,
tokenY,
[reward0, reward1],
clock,
opt
);
}
/**
* Similar to `create` function, but it accept multiple lbPairs to be initialized.
* @param {Connection} connection - The `connection` parameter is an instance of the `Connection`
* class, which represents the connection to the Solana blockchain network.
* @param dlmmList - An Array of PublicKey of LB Pairs.
* @param {Opt} [opt] - An optional parameter of type `Opt`.
* @returns The function `createMultiple` returns a Promise that resolves to an array of `DLMM`
* objects.
*/
static async createMultiple(connection, dlmmList, opt) {
const program = createProgram(connection, opt);
const binArrayBitMapExtensions = dlmmList.map(
(lbPair) => deriveBinArrayBitmapExtension(lbPair, program.programId)[0]
);
const accountsToFetch = [
...dlmmList,
...binArrayBitMapExtensions,
_web3js.SYSVAR_CLOCK_PUBKEY
];
let accountsInfo = await chunkedGetMultipleAccountInfos(
connection,
accountsToFetch
);
const clockAccount = accountsInfo.pop();
const clockAccountInfoBuffer = _optionalChain([clockAccount, 'optionalAccess', _67 => _67.data]);
if (!clockAccountInfoBuffer)
throw new Error(`Clock account not found`);
const clock = ClockLayout.decode(clockAccountInfoBuffer);
const lbPairArraysMap = /* @__PURE__ */ new Map();
for (let i = 0; i < dlmmList.length; i++) {
const lbPairPubKey = dlmmList[i];
const lbPairAccountInfoBuffer = _optionalChain([accountsInfo, 'access', _68 => _68[i], 'optionalAccess', _69 => _69.data]);
if (!lbPairAccountInfoBuffer)
throw new Error(`LB Pair account ${lbPairPubKey.toBase58()} not found`);
const lbPairAccInfo = decodeAccount(
program,
"lbPair",
lbPairAccountInfoBuffer
);
lbPairArraysMap.set(lbPairPubKey.toBase58(), lbPairAccInfo);
}
const binArrayBitMapExtensionsMap = /* @__PURE__ */ new Map();
for (let i = dlmmList.length; i < accountsInfo.length; i++) {
const index = i - dlmmList.length;
const lbPairPubkey = dlmmList[index];
const binArrayBitMapAccountInfoBuffer = _optionalChain([accountsInfo, 'access', _70 => _70[i], 'optionalAccess', _71 => _71.data]);
if (binArrayBitMapAccountInfoBuffer) {
const binArrayBitMapExtensionAccInfo = decodeAccount(
program,
"binArrayBitmapExtension",
binArrayBitMapAccountInfoBuffer
);
binArrayBitMapExtensionsMap.set(
lbPairPubkey.toBase58(),
binArrayBitMapExtensionAccInfo
);
}
}
const reservePublicKeys = Array.from(lbPairArraysMap.values()).map(({ reserveX, reserveY }) => [reserveX, reserveY]).flat();
const tokenMintPublicKeys = Array.from(lbPairArraysMap.values()).map(({ tokenXMint, tokenYMint }) => [tokenXMint, tokenYMint]).flat();
const rewardVaultPublicKeys = Array.from(lbPairArraysMap.values()).map(({ rewardInfos }) => rewardInfos.map(({ vault }) => vault)).flat();
const rewardMintPublicKeys = Array.from(lbPairArraysMap.values()).map(({ rewardInfos }) => rewardInfos.map(({ mint }) => mint)).flat();
accountsInfo = await chunkedGetMultipleAccountInfos(
program.provider.connection,
[
...reservePublicKeys,
...tokenMintPublicKeys,
...rewardVaultPublicKeys,
...rewardMintPublicKeys
]
);
const offsetToTokenMint = reservePublicKeys.length;
const offsetToRewardMint = reservePublicKeys.length + tokenMintPublicKeys.length + rewardVaultPublicKeys.length;
const tokenMintAccounts = accountsInfo.slice(
offsetToTokenMint,
offsetToTokenMint + tokenMintPublicKeys.length
);
const rewardMintAccounts = accountsInfo.slice(
offsetToRewardMint,
offsetToRewardMint + rewardMintPublicKeys.length
);
const tokenMintsWithAccount = tokenMintPublicKeys.map((key, idx) => {
return {
mintAddress: key,
mintAccountInfo: tokenMintAccounts[idx]
};
}).filter(({ mintAddress }) => mintAddress !== _web3js.PublicKey.default);
const rewardMintsWithAccount = rewardMintPublicKeys.map((key, idx) => {
return {
mintAddress: key,
mintAccountInfo: rewardMintAccounts[idx]
};
}).filter(({ mintAddress }) => mintAddress !== _web3js.PublicKey.default);
const uniqueMintWithAccounts = Array.from(
new Set(tokenMintsWithAccount.concat(rewardMintsWithAccount))
);
const mintHookAccountsMap = await getMultipleMintsExtraAccountMetasForTransferHook(
connection,
uniqueMintWithAccounts
);
const lbClmmImpl = dlmmList.map((lbPair, index) => {
const lbPairState = lbPairArraysMap.get(lbPair.toBase58());
if (!lbPairState)
throw new Error(`LB Pair ${lbPair.toBase58()} state not found`);
const binArrayBitmapExtensionState = binArrayBitMapExtensionsMap.get(
lbPair.toBase58()
);
const binArrayBitmapExtensionPubkey = binArrayBitMapExtensions[index];
let binArrayBitmapExtension = null;
if (binArrayBitmapExtensionState) {
binArrayBitmapExtension = {
account: binArrayBitmapExtensionState,
publicKey: binArrayBitmapExtensionPubkey
};
}
const reserveXAccountInfo = accountsInfo[index * 2];
const reserveYAccountInfo = accountsInfo[index * 2 + 1];
let offsetToTokenMint2 = reservePublicKeys.length;
const tokenXMintAccountInfo = accountsInfo[offsetToTokenMint2 + index * 2];
const tokenYMintAccountInfo = accountsInfo[offsetToTokenMint2 + index * 2 + 1];
const offsetToRewardVaultAccountInfos = offsetToTokenMint2 + tokenMintPublicKeys.length;
const reward0VaultAccountInfo = accountsInfo[offsetToRewardVaultAccountInfos + index * 2];
const reward1VaultAccountInfo = accountsInfo[offsetToRewardVaultAccountInfos + index * 2 + 1];
const offsetToRewardMintAccountInfos = offsetToRewardVaultAccountInfos + rewardVaultPublicKeys.length;
const reward0MintAccountInfo = accountsInfo[offsetToRewardMintAccountInfos + index * 2];
const reward1MintAccountInfo = accountsInfo[offsetToRewardMintAccountInfos + index * 2 + 1];
if (!reserveXAccountInfo || !reserveYAccountInfo)
throw new Error(
`Reserve account for LB Pair ${lbPair.toBase58()} not found`
);
const reserveXBalance = _spltoken.AccountLayout.decode(reserveXAccountInfo.data);
const reserveYBalance = _spltoken.AccountLayout.decode(reserveYAccountInfo.data);
const mintX = _spltoken.unpackMint.call(void 0,
lbPairState.tokenXMint,
tokenXMintAccountInfo,
tokenXMintAccountInfo.owner
);
const mintY = _spltoken.unpackMint.call(void 0,
lbPairState.tokenYMint,
tokenYMintAccountInfo,
tokenYMintAccountInfo.owner
);
const tokenX = {
publicKey: lbPairState.tokenXMint,
reserve: lbPairState.reserveX,
mint: mintX,
amount: reserveXBalance.amount,
owner: tokenXMintAccountInfo.owner,
transferHookAccountMetas: _nullishCoalesce(mintHookAccountsMap.get(lbPairState.tokenXMint.toBase58()), () => ( []))
};
const tokenY = {
publicKey: lbPairState.tokenYMint,
reserve: lbPairState.reserveY,
amount: reserveYBalance.amount,
mint: mintY,
owner: tokenYMintAccountInfo.owner,
transferHookAccountMetas: _nullishCoalesce(mintHookAccountsMap.get(lbPairState.tokenYMint.toBase58()), () => ( []))
};
const reward0 = !lbPairState.rewardInfos[0].mint.equals(
_web3js.PublicKey.default
) ? {
publicKey: lbPairState.rewardInfos[0].mint,
reserve: lbPairState.rewardInfos[0].vault,
amount: _spltoken.AccountLayout.decode(reward0VaultAccountInfo.data).amount,
mint: _spltoken.unpackMint.call(void 0,
lbPairState.rewardInfos[0].mint,
reward0MintAccountInfo,
reward0MintAccountInfo.owner
),
owner: reward0MintAccountInfo.owner,
transferHookAccountMetas: _nullishCoalesce(mintHookAccountsMap.get(
lbPairState.rewardInfos[0].mint.toBase58()
), () => ( []))
} : null;
const reward1 = !lbPairState.rewardInfos[1].mint.equals(
_web3js.PublicKey.default
) ? {
publicKey: lbPairState.rewardInfos[1].mint,
reserve: lbPairState.rewardInfos[1].vault,
amount: _spltoken.AccountLayout.decode(reward1VaultAccountInfo.data).amount,
mint: _spltoken.unpackMint.call(void 0,
lbPairState.rewardInfos[1].mint,
reward1MintAccountInfo,
reward1MintAccountInfo.owner
),
owner: reward1MintAccountInfo.owner,
transferHookAccountMetas: _nullishCoalesce(mintHookAccountsMap.get(
lbPairState.rewardInfos[1].mint.toBase58()
), () => ( []))
} : null;
return new DLMM(
lbPair,
program,
lbPairState,
binArrayBitmapExtension,
tokenX,
tokenY,
[reward0, reward1],
clock,
opt
);
});
return lbClmmImpl;
}
/**
* The `getAllPresetParameters` function retrieves all preset parameter accounts
* for the given DLMM program.
*
* @param {Connection} connection - The connection to the Solana cluster.
* @param {Opt} [opt] - The optional parameters for the function.
*
* @returns A promise that resolves to an object containing the preset parameter
* accounts, with the following properties:
* - `presetParameter`: The preset parameter accounts for the original `PresetParameter` struct.
* - `presetParameter2`: The preset parameter accounts for the `PresetParameter2` struct.
*/
static async getAllPresetParameters(connection, opt) {
const program = createProgram(connection, opt);
const [presetParameter, presetParameter2] = await Promise.all([
program.account.presetParameter.all(),
program.account.presetParameter2.all()
]);
return {
presetParameter,
presetParameter2
};
}
/**
* The function `getAllLbPairPositionsByUser` retrieves all liquidity pool pair positions for a given
* user.
* @param {Connection} connection - The `connection` parameter is an instance of the `Connection`
* class, which represents the connection to the Solana blockchain.
* @param {PublicKey} userPubKey - The user's wallet public key.
* @param {Opt} [opt] - An optional object that contains additional options for the function.
* @param {GetPositionsOpt} [getPositionsOpt] - Optional settings for chunked position fetching
* @returns The function `getAllLbPairPositionsByUser` returns a `Promise` that resolves to a `Map`
* object. The `Map` object contains key-value pairs, where the key is a string representing the LB
* Pair account, and the value is an object of PositionInfo
*/
static async getAllLbPairPositionsByUser(connection, userPubKey, opt, getPositionsOpt) {
const program = createProgram(connection, opt);
const positionsV2 = await chunkedGetProgramAccounts(
program.provider.connection,
program.programId,
[positionV2Filter(), positionOwnerFilter(userPubKey)],
_optionalChain([getPositionsOpt, 'optionalAccess', _72 => _72.chunkSize]),
_optionalChain([getPositionsOpt, 'optionalAccess', _73 => _73.onChunkFetched]),
_optionalChain([getPositionsOpt, 'optionalAccess', _74 => _74.isParallelExecution])
);
const positionWrappers = [
...positionsV2.map((p) => wrapPosition(program, p.pubkey, p.account))
];
const binArrayPubkeySetV2 = /* @__PURE__ */ new Set();
const lbPairSetV2 = /* @__PURE__ */ new Set();
positionWrappers.forEach((p) => {
const binArrayKeys = p.getBinArrayKeysCoverage(program.programId);
binArrayKeys.forEach((binArrayKey) => {
binArrayPubkeySetV2.add(binArrayKey.toBase58());
});
lbPairSetV2.add(p.lbPair().toBase58());
});
const binArrayPubkeyArrayV2 = Array.from(binArrayPubkeySetV2).map(
(pubkey) => new (0, _web3js.PublicKey)(pubkey)
);
const lbPairKeys = Array.from(lbPairSetV2).map(
(pubkey) => new (0, _web3js.PublicKey)(pubkey)
);
const [clockAccInfo, ...binArraysAccInfo] = await chunkedGetMultipleAccountInfos(connection, [
_web3js.SYSVAR_CLOCK_PUBKEY,
...binArrayPubkeyArrayV2,
...lbPairKeys
]);
const positionBinArraysMapV2 = /* @__PURE__ */ new Map();
for (let i = 0; i < binArrayPubkeyArrayV2.length; i++) {
const binArrayPubkey = binArrayPubkeyArrayV2[i];
const binArrayAccInfoBufferV2 = binArraysAccInfo[i];
if (binArrayAccInfoBufferV2) {
const binArrayAccInfo = decodeAccount(
program,
"binArray",
binArrayAccInfoBufferV2.data
);
positionBinArraysMapV2.set(binArrayPubkey.toBase58(), binArrayAccInfo);
}
}
const lbPairMap = /* @__PURE__ */ new Map();
for (let i = binArrayPubkeyArrayV2.length; i < binArraysAccInfo.length; i++) {
const lbPairPubkey = lbPairKeys[i - binArrayPubkeyArrayV2.length];
const lbPairAccInfoBufferV2 = binArraysAccInfo[i];
if (!lbPairAccInfoBufferV2)
throw new Error(`LB Pair account ${lbPairPubkey.toBase58()} not found`);
const lbPairAccInfo = decodeAccount(
program,
"lbPair",
lbPairAccInfoBufferV2.data
);
lbPairMap.set(lbPairPubkey.toBase58(), lbPairAccInfo);
}
const accountKeys = Array.from(lbPairMap.values()).map(({ reserveX, reserveY, tokenXMint, tokenYMint, rewardInfos }) => [
reserveX,
reserveY,
tokenXMint,
tokenYMint,
rewardInfos[0].mint,
rewardInfos[1].mint
]).flat();
const accountInfos = await chunkedGetMultipleAccountInfos(
program.provider.connection,
accountKeys
);
const lbPairReserveMap = /* @__PURE__ */ new Map();
const lbPairMintMap = /* @__PURE__ */ new Map();
lbPairKeys.forEach((lbPair, idx) => {
const index = idx * 6;
const reserveXAccount = accountInfos[index];
const reserveYAccount = accountInfos[index + 1];
if (!reserveXAccount || !reserveYAccount)
throw new Error(
`Reserve account for LB Pair ${lbPair.toBase58()} not found`
);
const reserveAccX = _spltoken.AccountLayout.decode(reserveXAccount.data);
const reserveAccY = _spltoken.AccountLayout.decode(reserveYAccount.data);
lbPairReserveMap.set(lbPair.toBase58(), {
reserveX: reserveAccX.amount,
reserveY: reserveAccY.amount
});
const mintXAccount = accountInfos[index + 2];
const mintYAccount = accountInfos[index + 3];
if (!mintXAccount || !mintYAccount)
throw new Error(
`Mint account for LB Pair ${lbPair.toBase58()} not found`
);
const mintX = _spltoken.unpackMint.call(void 0,
reserveAccX.mint,
mintXAccount,
mintXAccount.owner
);
const mintY = _spltoken.unpackMint.call(void 0,
reserveAccY.mint,
mintYAccount,
mintYAccount.owner
);
const rewardMint0Account = accountInfos[index + 4];
const rewardMint1Account = accountInfos[index + 5];
const lbPairState = lbPairMap.get(lbPair.toBase58());
let rewardMint0 = null;
let rewardMint1 = null;
if (!lbPairState.rewardInfos[0].mint.equals(_web3js.PublicKey.default)) {
rewardMint0 = _spltoken.unpackMint.call(void 0,
lbPairState.rewardInfos[0].mint,
rewardMint0Account,
rewardMint0Account.owner
);
}
if (!lbPairState.rewardInfos[1].mint.equals(_web3js.PublicKey.default)) {
rewardMint1 = _spltoken.unpackMint.call(void 0,
lbPairState.rewardInfos[1].mint,
rewardMint1Account,
rewardMint1Account.owner
);
}
lbPairMintMap.set(lbPair.toBase58(), {
mintX,
mintY,
rewardMint0,
rewardMint1
});
});
const clock = ClockLayout.decode(clockAccInfo.data);
const positionsMap = /* @__PURE__ */ new Map();
for (const position of positionWrappers) {
const lbPair = position.lbPair();
const positionPubkey = position.address();
const version = position.version();
const lbPairAcc = lbPairMap.get(lbPair.toBase58());
const { mintX, mintY, rewardMint0, rewardMint1 } = lbPairMintMap.get(
lbPair.toBase58()
);
const reserveXBalance = _nullishCoalesce(_optionalChain([lbPairReserveMap, 'access', _75 => _75.get, 'call', _76 => _76(lbPair.toBase58()), 'optionalAccess', _77 => _77.reserveX]), () => ( BigInt(0)));
const reserveYBalance = _nullishCoalesce(_optionalChain([lbPairReserveMap, 'access', _78 => _78.get, 'call', _79 => _79(lbPair.toBase58()), 'optionalAccess', _80 => _80.reserveY]), () => ( BigInt(0)));
const { tokenXProgram, tokenYProgram } = getTokenProgramId(lbPairAcc);
const tokenX = {
publicKey: lbPairAcc.tokenXMint,
reserve: lbPairAcc.reserveX,
amount: reserveXBalance,
mint: mintX,
owner: tokenXProgram,
transferHookAccountMetas: []
// No need, the TokenReserve created just for processing position info, doesn't require any transaction
};
const tokenY = {
publicKey: lbPairAcc.tokenYMint,
reserve: lbPairAcc.reserveY,
amount: reserveYBalance,
mint: mintY,
owner: tokenYProgram,
transferHookAccountMetas: []
// No need, the TokenReserve created just for processing position info, doesn't require any transaction
};
const positionData = await DLMM.processPosition(
program,
lbPairAcc,
clock,
position,
mintX,
mintY,
rewardMint0,
rewardMint1,
positionBinArraysMapV2
);
if (positionData) {
positionsMap.set(lbPair.toBase58(), {
publicKey: lbPair,
lbPair: lbPairAcc,
tokenX,
tokenY,
lbPairPositionsData: [
..._nullishCoalesce(_optionalChain([positionsMap, 'access', _81 => _81.get, 'call', _82 => _82(lbPair.toBase58()), 'optionalAccess', _83 => _83.lbPairPositionsData]), () => ( [])),
{
publicKey: positionPubkey,
positionData,
version
}
]
});
}
}
return positionsMap;
}
/**
* The function `getPositionsByUserAndTokenAddress` retrieves all of a user's positions across every
* DLMM pool that includes the given token mint as either the X or Y token.
* @param {Connection} connection - The `connection` parameter is an instance of the `Connection`
* class, which represents the connection to the Solana blockchain.
* @param {PublicKey} userPubKey - The user's wallet public key.
* @param {PublicKey} tokenMint - The token mint used to filter pools. Only positions in pools whose
* `tokenXMint` or `tokenYMint` matches this mint are returned.
* @param {Opt} [opt] - An optional object that contains additional options for the function.
* @param {GetPositionsOpt} [getPositionsOpt] - Optional settings for chunked position fetching
* @returns The function `getPositionsByUserAndTokenAddress` returns a `Promise` that resolves to a
* `Map` object. The `Map` object contains key-value pairs, where the key is a string representing the
* LB Pair account, and the value is an object of PositionInfo. Only pools containing `tokenMint` are
* included.
*/
static async getPositionsByUserAndTokenAddress(connection, userPubKey, tokenMint, opt, getPositionsOpt) {
const allPositions = await DLMM.getAllLbPairPositionsByUser(
connection,
userPubKey,
opt,
getPositionsOpt
);
const targetMint = tokenMint.toBase58();
const filteredPositions = /* @__PURE__ */ new Map();
for (const [lbPairKey, positionInfo] of allPositions) {
const tokenXMint = positionInfo.lbPair.tokenXMint.toBase58();
const tokenYMint = positionInfo.lbPair.tokenYMint.toBase58();
if (tokenXMint === targetMint || tokenYMint === targetMint) {
filteredPositions.set(lbPairKey, positionInfo);
}
}
return filteredPositions;
}
/**
* The function `getLimitOrdersByUserAndTokenAddress` retrieves all of a user's limit orders across
* every DLMM pool that includes the given token mint as either the X or Y token.
* @param {Connection} connection - The `connection` parameter is an instance of the `Connection`
* class, which represents the connection to the Solana blockchain.
* @param {PublicKey} userPubKey - The user's wallet public key.
* @param {PublicKey} tokenMint - The token mint used to filter pools. Only limit orders in pools
* whose `tokenXMint` or `tokenYMint` matches this mint are returned.
* @param {Opt} [opt] - An optional object that contains additional options for the function.
* @returns The function `getLimitOrdersByUserAndTokenAddress` returns a `Promise` that resolves to a
* `Map` object keyed by LB Pair account (base58), where each value is a `LimitOrderInfo` containing
* the LB pair state, token reserves, and the parsed limit orders for that pool.
*/
static async getLimitOrdersByUserAndTokenAddress(connection, userPubKey, tokenMint, opt) {
const program = createProgram(connection, opt);
const limitOrderAccounts = await chunkedGetProgramAccounts(
program.provider.connection,
program.programId,
[limitOrderFilter(), limitOrderOwnerFilter(userPubKey)]
);
const limitOrderWrappers = limitOrderAccounts.map(
({ pubkey, account }) => wrapLimitOrder(program, pubkey, account)
);
if (limitOrderWrappers.length === 0) {
return /* @__PURE__ */ new Map();
}
const lbPairKeys = Array.from(
new Set(limitOrderWrappers.map((lo) => lo.lbPair().toBase58()))
).map((key) => new (0, _web3js.PublicKey)(key));
const lbPairAccInfos = await chunkedGetMultipleAccountInfos(
connection,
lbPairKeys
);
const lbPairMap = /* @__PURE__ */ new Map();
lbPairKeys.forEach((lbPairPubkey, i) => {
const accInfo = lbPairAccInfos[i];
if (!accInfo) {
throw new Error(`LB Pair account ${lbPairPubkey.toBase58()} not found`);
}
lbPairMap.set(
lbPairPubkey.toBase58(),
decodeAccount(program, "lbPair", accInfo.data)
);
});
const targetMint = tokenMint.toBase58();
const matchingLbPairKeys = lbPairKeys.filter((lbPairPubkey) => {
const lbPairState = lbPairMap.get(lbPairPubkey.toBase58());
return lbPairState.tokenXMint.toBase58() === targetMint || lbPairState.tokenYMint.toBase58() === targetMint;
});
if (matchingLbPairKeys.length === 0) {
return /* @__PURE__ */ new Map();
}
const matchingLbPairSet = new Set(
matchingLbPairKeys.map((key) => key.toBase58())
);
const matchingLimitOrders = limitOrderWrappers.filter(
(lo) => matchingLbPairSet.has(lo.lbPair().toBase58())
);
const reserveAndMintKeys = matchingLbPairKeys.map((lbPairPubkey) => {
const { reserveX, reserveY, tokenXMint, tokenYMint } = lbPairMap.get(
lbPairPubkey.toBase58()
);
return [reserveX, reserveY, tokenXMint, tokenYMint];
}).flat();
const binArrayPubkeySet = /* @__PURE__ */ new Set();
matchingLimitOrders.forEach((lo) => {
lo.getBinArrayKeysCoverage(program.programId).forEach((key) => {
binArrayPubkeySet.add(key.toBase58());
});
});
const binArrayKeys = Array.from(binArrayPubkeySet).map(
(key) => new (0, _web3js.PublicKey)(key)
);
const [clockAccInfo, ...rest] = await chunkedGetMultipleAccountInfos(
connection,
[_web3js.SYSVAR_CLOCK_PUBKEY, ...binArrayKeys, ...reserveAndMintKeys]
);
const binArraysAccInfo = rest.slice(0, binArrayKeys.length);
const reserveAndMintAccInfo = rest.slice(binArrayKeys.length);
const clock = ClockLayout.decode(clockAccInfo.data);
const binArrayMap = /* @__PURE__ */ new Map();
binArrayKeys.forEach((binArrayPubkey, i) => {
const accInfo = binArraysAccInfo[i];
if (accInfo) {
binArrayMap.set(
binArrayPubkey.toBase58(),
decodeAccount(program, "binArray", accInfo.data)
);
}
});
const seenMints = /* @__PURE__ */ new Set();
const mintsWithAccount = matchingLbPairKeys.flatMap((lbPairPubkey, idx) => {
const { tokenXMint, tokenYMint } = lbPairMap.get(
lbPairPubkey.toBase58()
);
const index = idx * 4;
return [
{
mintAddress: tokenXMint,
mintAccountInfo: reserveAndMintAccInfo[index + 2]
},
{
mintAddress: tokenYMint,
mintAccountInfo: reserveAndMintAccInfo[index + 3]
}
];
}).filter(({ mintAddress, mintAccountInfo }) => {
if (!mintAccountInfo || seenMints.has(mintAddress.toBase58())) {
return false;
}
seenMints.add(mintAddress.toBase58());
return true;
});
const mintHookAccountsMap = await getMultipleMintsExtraAccountMetasForTransferHook(
connection,
mintsWithAccount
);
const lbPairTokenMap = /* @__PURE__ */ new Map();
matchingLbPairKeys.forEach((lbPairPubkey, idx) => {
const index = idx * 4;
const reserveXAccount = reserveAndMintAccInfo[index];
const reserveYAccount = reserveAndMintAccInfo[index + 1];
const mintXAccount = reserveAndMintAccInfo[index + 2];
const mintYAccount = reserveAndMintAccInfo[index + 3];
if (!reserveXAccount || !reserveYAccount) {
throw new Error(
`Reserve account for LB Pair ${lbPairPubkey.toBase58()} not found`
);
}
if (!mintXAccount || !mintYAccount) {
throw new Error(
`Mint account for LB Pair ${lbPairPubkey.toBase58()} not found`
);
}
const lbPairState = lbPairMap.get(lbPairPubkey.toBase58());
const reserveAccX = _spltoken.AccountLayout.decode(reserveXAccount.data);
const reserveAccY = _spltoken.AccountLayout.decode(reserveYAccount.data);
const mintX = _spltoken.unpackMint.call(void 0,
reserveAccX.mint,
mintXAccount,
mintXAccount.owner
);
const mintY = _spltoken.unpackMint.call(void 0,
reserveAccY.mint,
mintYAccount,
mintYAccount.owner
);
const { tokenXProgram, tokenYProgram } = getTokenProgramId(lbPairState);
const tokenX = {
publicKey: lbPairState.tokenXMint,
reserve: lbPairState.reserveX,
amount: reserveAccX.amount,
mint: mintX,
owner: tokenXProgram,
transferHookAccountMetas: _nullishCoalesce(mintHookAccountsMap.get(lbPairState.tokenXMint.toBase58()), () => ( []))
};
const tokenY = {
publicKey: lbPairState.tokenYMint,
reserve: lbPairState.reserveY,
amount: reserveAccY.amount,
mint: mintY,
owner: tokenYProgram,
transferHookAccountMetas: _nullishCoalesce(mintHookAccountsMap.get(lbPairState.tokenYMint.toBase58()), () => ( []))
};
lbPairTokenMap.set(lbPairPubkey.toBase58(), {
tokenX,
tokenY,
mintX,
mintY
});
});
const limitOrdersMap = /* @__PURE__ */ new Map();
for (const lo of matchingLimitOrders) {
const lbPairKey = lo.lbPair().toBase58();
const lbPairState = lbPairMap.get(lbPairKey);
const { tokenX, tokenY, mintX, mintY } = lbPairTokenMap.get(lbPairKey);
const parsedLo = lo.parseInfo(
program.programId,
lbPairState,
mintX,
mintY,
clock,
binArrayMap
);
const entry = {
publicKey: lo.address(),
limitOrderData: parsedLo
};
const existing = limitOrdersMap.get(lbPairKey);
if (existing) {
existing.limitOrders.push(entry);
} else {
limitOrdersMap.set(lbPairKey, {
publicKey: lo.lbPair(),
lbPair: lbPairState,
tokenX,
tokenY,
limitOrders: [entry]
});
}
}
return limitOrdersMap;
}
static getPricePerLamport(tokenXDecimal, tokenYDecimal, price) {
return new (0, _decimaljs2.default)(price).mul(new (0, _decimaljs2.default)(10 ** (tokenYDecimal - tokenXDecimal))).toString();
}
static getBinIdFromPrice(price, binStep, min) {
const binStepNum = new (0, _decimaljs2.default)(binStep).div(new (0, _decimaljs2.default)(BASIS_POINT_MAX));
const binId = new (0, _decimaljs2.default)(price).log().dividedBy(new (0, _decimaljs2.default)(1).add(binStepNum).log());
return (min ? binId.floor() : binId.ceil()).toNumber();
}
/**
* The function `getLbPairLockInfo` retrieves all pair positions that has locked liquidity.
* @param {number} [lockDurationOpt] - An optional value indicating the minimum position lock duration that the function should return.
* Depending on the lbPair activationType, the param should be a number of seconds or a number of slots.
* @param {GetPositionsOpt} [getPositionsOpt] - Optional settings for chunked position fetching
* @returns The function `getLbPairLockInfo` returns a `Promise` that resolves to a `PairLockInfo`
* object. The `PairLockInfo` object contains an array of `PositionLockInfo` objects.
*/
async getLbPairLockInfo(lockDurationOpt, getPositionsOpt) {
const lockDuration = lockDurationOpt | 0;
const positionAccounts = await chunkedGetProgramAccounts(
this.program.provider.connection,
this.program.programId,
[positionLbPairFilter(this.pubkey)],
_optionalChain([getPositionsOpt, 'optionalAccess', _84 => _84.chunkSize]),
_optionalChain([getPositionsOpt, 'optionalAccess', _85 => _85.onChunkFetched]),
_optionalChain([getPositionsOpt, 'optionalAccess', _86 => _86.isParallelExecution])
);
const lbPairPositions = positionAccounts.map((acc) => {
return wrapPosition(this.program, acc.pubkey, acc.account);
});
const clockAccInfo = await this.program.provider.connection.getAccountInfo(
_web3js.SYSVAR_CLOCK_PUBKEY
);
const clock = ClockLayout.decode(clockAccInfo.data);
const currentPoint = this.lbPair.activationType == 0 /* Slot */ ? clock.slot : clock.unixTimestamp;
const minLockReleasePoint = currentPoint.add(new (0, _anchor.BN)(lockDuration));
const positionsWithLock = lbPairPositions.filter(
(p) => p.lockReleasePoint().gt(minLockReleasePoint)
);
if (positionsWithLock.length == 0) {
return {
positions: []
};
}
const binArrayPubkeySetV2 = /* @__PURE__ */ new Set();
positionsWithLock.forEach((position) => {
const binArrayKeys = position.getBinArrayKeysCoverage(
this.program.programId
);
binArrayKeys.forEach((key) => {
binArrayPubkeySetV2.add(key.toBase58());
});
});
const binArrayPubkeyArrayV2 = Array.from(binArrayPubkeySetV2).map(
(pubkey) => new (0, _web3js.PublicKey)(pubkey)
);
const binArraysAccInfo = await chunkedGetMultipleAccountInfos(
this.program.provider.connection,
binArrayPubkeyArrayV2
);
const positionBinArraysMapV2 = /* @__PURE__ */ new Map();
for (let i = 0; i < binArraysAccInfo.length; i++) {
const binArrayPubkey = binArrayPubkeyArrayV2[i];
const binArrayAccBufferV2 = binArraysAccInfo[i];
if (!binArrayAccBufferV2)
throw new Error(
`Bin Array account ${binArrayPubkey.toBase58()} not found`
);
const binArrayAccInfo = decodeAccount(
this.program,
"binArray",
binArrayAccBufferV2.data
);
positionBinArraysMapV2.set(binArrayPubkey.toBase58(), binArrayAccInfo);
}
const positionsLockInfo = await Promise.all(
positionsWithLock.map(async (position) => {
const positionData = await DLMM.processPosition(
this.program,
this.lbPair,
clock,
position,
this.tokenX.mint,
this.tokenY.mint,
this.rewards[0].mint,
this.rewards[1].mint,
positionBinArraysMapV2
);
return {
positionAddress: position.address(),
owner: position.owner(),
lockReleasePoint: position.lockReleasePoint().toNumber(),
tokenXAmount: positionData.totalXAmount,
tokenYAmount: positionData.totalYAmount
};
})
);
return {
positions: positionsLockInfo
};
}
/** Public methods */
/**
* Create a new customizable permissionless pair. Support both token and token 2022.
* @param connection A connection to the Solana cluster.
* @param binStep The bin step for the pair.
* @param tokenX The mint of the first token.
* @param tokenY The mint of the second token.
* @param activeId The ID of the initial active bin. Represent the starting price.
* @param feeBps The fee rate for swaps in the pair, in basis points.
* @param activationType The type of activation for the pair.
* @param hasAlphaVault Whether the pair has an alpha vault.
* @param creatorKey The public key of the creator of the pair.
* @param activationPoint The timestamp at which the pair will be activated.
* @param creatorPoolOnOffControl Whether the creator has control over enable or disable the pool.
* @params concreteFunctionType The concrete function type of the pair, limit order or liquidity mining. Default to limit order if not provided.
* @params collectFeeMode The collect fee mode of the pair, input only or only token Y. Default to input only if not provided.
* @param opt An options object.
* @returns A transaction that creates the pair.
*/
static async createCustomizablePermissionlessLbPair2(connection, binStep, tokenX, tokenY, activeId, feeBps, activationType, hasAlphaVault, creatorKey, activationPoint, creatorPoolOnOffControl, concreteFunctionType, collectFeeMode, opt) {
const program = createProgram(connection, opt);
const [tokenBadgeX] = deriveTokenBadge(tokenX, program.programId);
const [tokenBadgeY] = deriveTokenBadge(tokenY, program.programId);
const [
tokenXAccount,
tokenYAccount,
tokenBadgeXAccount,
tokenBadgeYAccount
] = await connection.getMultipleAccountsInfo([
tokenX,
tokenY,
tokenBadgeX,
tokenBadgeY
]);
const [lbPair] = deriveCustomizablePermissionlessLbPair(
tokenX,
tokenY,
program.programId
);
const [reserveX] = deriveReserve(tokenX, lbPair, program.programId);
const [reserveY] = deriveReserve(tokenY, lbPair, program.programId);
const [oracle] = deriveOracle(lbPair, program.programId);
const activeBinArrayIndex = binIdToBinArrayIndex(activeId);
const binArrayBitmapExtension = isOverflowDefaultBinArrayBitmap(
activeBinArrayIndex
) ? deriveBinArrayBitmapExtension(lbPair, program.programId)[0] : null;
const [baseFactor, baseFeePowerFactor] = computeBaseFactorFromFeeBps(
binStep,
feeBps
);
const ixData = {
activeId: activeId.toNumber(),
binStep: binStep.toNumber(),
baseFactor: baseFactor.toNumber(),
concreteFunctionType: concreteFunctionType ? concreteFunctionType : 0 /* LimitOrder */,
collectFeeMode: collectFeeMode ? collectFeeMode : 0 /* InputOnly */,
activationType,
activationPoint: activationPoint ? activationPoint : null,
hasAlphaVault,
creatorPoolOnOffControl: creatorPoolOnOffControl ? creatorPoolOnOffControl : false,
baseFeePowerFactor: baseFeePowerFactor.toNumber(),
padding: Array(60).fill(0)
};
const preInstructions = [];
const userTokenX = _spltoken.getAssociatedTokenAddressSync.call(void 0,
tokenX,
creatorKey,
true,
tokenXAccount.owner
);
const createUserTokenXIx = _spltoken.createAssociatedTokenAccountIdempotentInstruction.call(void 0,
creatorKey,
userTokenX,
creatorKey,
tokenX,
tokenXAccount.owner
);
preInstructions.push(createUserTokenXIx);
const userTokenY = _spltoken.getAssociatedTokenAddressSync.call(void 0,
tokenY,
creatorKey,
true,
tokenYAccount.owner
);
const createUserTokenYIx = _spltoken.createAssociatedTokenAccountIdempotentInstruction.call(void 0,
creatorKey,
userTokenY,
creatorKey,
tokenY,
tokenYAccount.owner
);
preInstructions.push(createUserTokenYIx);
const postInstructions = [];
if ((tokenX.equals(_spltoken.NATIVE_MINT) || tokenY.equals(_spltoken.NATIVE_MINT)) && !_optionalChain([opt, 'optionalAccess', _87 => _87.skipSolWrappingOperation])) {
const wrapAmount = BigInt(1);
if (tokenX.equals(_spltoken.NATIVE_MINT)) {
const wrapSOLIxX = wrapSOLInstruction(
creatorKey,
userTokenX,
wrapAmount
);
preInstructions.push(...wrapSOLIxX);
}
if (tokenY.equals(_spltoken.NATIVE_MINT)) {
const wrapSOLIxY = wrapSOLInstruction(
creatorKey,
userTokenY,
wrapAmount
);
preInstructions.push(...wrapSOLIxY);
}
const unwrapSOLIx = await unwrapSOLInstruction(creatorKey);
if (unwrapSOLIx) {
postInstructions.push(unwrapSOLIx);
}
}
return program.methods.initializeCustomizablePermissionlessLbPair2(ixData).accountsPartial({
tokenBadgeX: tokenBadgeXAccount ? tokenBadgeX : program.programId,
tokenBadgeY: tokenBadgeYAccount ? tokenBadgeY : program.programId,
lbPair,
reserveX,
reserveY,
binArrayBitmapExtension,
tokenMintX: tokenX,
tokenMintY: tokenY,
oracle,
systemProgram: _web3js.SystemProgram.programId,
userTokenX,
userTokenY,
funder: creatorKey,
tokenProgramX: tokenXAccount.owner,
tokenProgramY: tokenYAccount.owner
}).preInstructions(preInstructions).postInstructions(postInstructions).transaction();
}
/**
* Create a new customizable permissionless pair. Support only token program.
* @param connection A connection to the Solana cluster.
* @param binStep The bin step for the pair.
* @param tokenX The mint of the first token.
* @param tokenY The mint of the second token.
* @param activeId The ID of the initial active bin. Represent the starting price.
* @param feeBps The fee rate for swaps in the pair, in basis points.
* @param activationType The type of activation for the pair.
* @param hasAlphaVault Whether the pair has an alpha vault.
* @param creatorKey The public key of the creator of the pair.
* @param activationPoint The timestamp at which the pair will be activated.
* @param creatorPoolOnOffControl Whether the creator has control over enable or disable the pool.
* @params concreteFunctionType The concrete function type of the pair, limit order or liquidity mining. Default to limit order if not provided.
* @params collectFeeMode The collect fee
* @param opt An options object.
* @returns A transaction that creates the pair.
*/
static async createCustomizablePermissionlessLbPair(connection, binStep, tokenX, tokenY, activeId, feeBps, activationType, hasAlphaVault, creatorKey, activationPoint, creatorPoolOnOffControl, concreteFunctionType, collectFeeMode, opt) {
const program = createProgram(connection, opt);
const [lbPair] = deriveCustomizablePermissionlessLbPair(
tokenX,
tokenY,
program.programId
);
const [tokenXAccount, tokenYAccount] = await connection.getMultipleAccountsInfo([tokenX, tokenY]);
const [reserveX] = deriveReserve(tokenX, lbPair, program.programId);
const [reserveY] = deriveReserve(tokenY, lbPair, program.programId);
const [oracle] = deriveOracle(lbPair, program.programId);
const activeBinArrayIndex = binIdToBinArrayIndex(activeId);
const binArrayBitmapExtension = isOverflowDefaultBinArrayBitmap(
activeBinArrayIndex
) ? deriveBinArrayBitmapExtension(lbPair, program.programId)[0] : null;
const [baseFactor, baseFeePowerFactor] = computeBaseFactorFromFeeBps(
binStep,
feeBps
);
if (!baseFeePowerFactor.isZero()) {
throw "base factor for the give fee bps overflow u16";
}
const ixData = {
activeId: activeId.toNumber(),
binStep: binStep.toNumber(),
baseFactor: baseFactor.toNumber(),
concreteFunctionType: concreteFunctionType ? concreteFunctionType : 0 /* LimitOrder */,
collectFeeMode: collectFeeMode ? collectFeeMode : 0 /* InputOnly */,
activationType,
activationPoint: activationPoint ? activationPoint : null,
hasAlphaVault,
baseFeePowerFactor: 0,
creatorPoolOnOffControl: creatorPoolOnOffControl ? creatorPoolOnOffControl : false,
padding: Array(60).fill(0)
};
const preInstructions = [];
const userTokenX = _spltoken.getAssociatedTokenAddressSync.call(void 0,
tokenX,
creatorKey,
true,
tokenXAccount.owner
);
const createUserTokenXIx = _spltoken.createAssociatedTokenAccountIdempotentInstruction.call(void 0,
creatorKey,
userTokenX,
creatorKey,
tokenX,
tokenXAccount.owner
);
preInstructions.push(createUserTokenXIx);
const userTokenY = _spltoken.getAssociatedTokenAddressSync.call(void 0,
tokenY,
creatorKey,
true,
tokenYAccount.owner
);
const createUserTokenYIx = _spltoken.createAssociatedTokenAccountIdempotentInstruction.call(void 0,
creatorKey,
userTokenY,
creatorKey,
tokenY,
tokenYAccount.owner
);
preInstructions.push(createUserTokenYIx);
const postInstructions = [];
if ((tokenX.equals(_spltoken.NATIVE_MINT) || tokenY.equals(_spltoken.NATIVE_MINT)) && !_optionalChain([opt, 'optionalAccess', _88 => _88.skipSolWrappingOperation])) {
const wrapAmount = BigInt(1);
if (tokenX.equals(_spltoken.NATIVE_MINT)) {
const wrapSOLIxX = wrapSOLInstruction(
creatorKey,
userTokenX,
wrapAmount
);
preInstructions.push(...wrapSOLIxX);
}
if (tokenY.equals(_spltoken.NATIVE_MINT)) {
const wrapSOLIxY = wrapSOLInstruction(
creatorKey,
userTokenY,
wrapAmount
);
preInstructions.push(...wrapSOLIxY);
}
const unwrapSOLIx = await unwrapSOLInstruction(creatorKey);
if (unwrapSOLIx) {
postInstructions.push(unwrapSOLIx);
}
}
return program.methods.initializeCustomizablePermissionlessLbPair(ixData).accountsPartial({
lbPair,
reserveX,
reserveY,
binArrayBitmapExtension,
tokenMintX: tokenX,
tokenMintY: tokenY,
oracle,
systemProgram: _web3js.SystemProgram.programId,
userTokenX,
userTokenY,
funder: creatorKey
}).preInstructions(preInstructions).postInstructions(postInstructions).transaction();
}
/**
* Create a new liquidity pair. Support only token program.
* @param connection A connection to the Solana cluster.
* @param funder The public key of the funder of the pair.
* @param tokenX The mint of the first token.
* @param tokenY The mint of the second token.
* @param binStep The bin step for the pair.
* @param baseFactor The base factor for the pair.
* @param presetParameter The public key of the preset parameter account.
* @param activeId The ID of the initial active bin. Represent the starting price.
* @param opt An options object.
* @returns A transaction that creates the pair.
* @throws If the pair already exists.
*/
static async createLbPair(connection, funder, tokenX, tokenY, binStep, baseFactor, presetParameter, activeId, opt) {
const program = createProgram(connection, opt);
const existsPool = await this.getPairPubkeyIfExists(
connection,
tokenX,
tokenY,
binStep,
baseFactor,
new (0, _anchor.BN)(0)
);
if (existsPool) {
throw new Error("Pool already exists");
}
const [lbPair] = deriveLbPair2(
tokenX,
tokenY,
binStep,
baseFactor,
program.programId
);
const [reserveX] = deriveReserve(tokenX, lbPair, program.programId);
const [reserveY] = deriveReserve(tokenY, lbPair, program.programId);
const [oracle] = deriveOracle(lbPair, program.programId);
const activeBinArrayIndex = binIdToBinArrayIndex(activeId);
const binArrayBitmapExtension = isOverflowDefaultBinArrayBitmap(
activeBinArrayIndex
) ? deriveBinArrayBitmapExtension(lbPair, program.programId)[0] : null;
return program.methods.initializeLbPair(activeId.toNumber(), binStep.toNumber()).accountsPartial({
funder,
lbPair,
rent: _web3js.SYSVAR_RENT_PUBKEY,
reserveX,
reserveY,
binArrayBitmapExtension,
tokenMintX: tokenX,
tokenMintY: tokenY,
tokenProgram: _spltoken.TOKEN_PROGRAM_ID,
oracle,
presetParameter,
systemProgram: _web3js.SystemProgram.programId
}).transaction();
}
/**
* Create a new liquidity pair. Support both token and token2022 program.
* @param connection A connection to the Solana cluster.
* @param funder The public key of the funder of the pair.
* @param tokenX The mint of the first token.
* @param tokenY The mint of the second token.
* @param presetParameter The public key of the preset parameter account.
* @param activeId The ID of the initial active bin. Represent the starting price.
* @param opt An options object.
* @returns A transaction that creates the pair.
* @throws If the pair already exists.
*/
static async createLbPair2(connection, funder, tokenX, tokenY, presetParameter, activeId, opt) {
const program = createProgram(connection, opt);
const [tokenBadgeX] = deriveTokenBadge(tokenX, program.programId);
const [tokenBadgeY] = deriveTokenBadge(tokenY, program.programId);
const [
tokenXAccount,
tokenYAccount,
tokenBadgeXAccount,
tokenBadgeYAccount
] = await connection.getMultipleAccountsInfo([
tokenX,
tokenY,
tokenBadgeX,
tokenBadgeY
]);
const presetParameterState = await program.account.presetParameter2.fetch(presetParameter);
const existsPool = await this.getPairPubkeyIfExists(
connection,
tokenX,
tokenY,
new (0, _anchor.BN)(presetParameterState.binStep),
new (0, _anchor.BN)(presetParameterState.baseFactor),
new (0, _anchor.BN)(presetParameterState.baseFeePowerFactor),
presetParameterState.concreteFunctionType,
presetParameterState.collectFeeMode,
{
cluster: _optionalChain([opt, 'optionalAccess', _89 => _89.cluster]),
programId: _optionalChain([opt, 'optionalAccess', _90 => _90.programId])
}
);
if (existsPool) {
throw new Error("Pool already exists");
}
const [lbPair] = deriveLbPairWithPresetParamWithIndexKey(
presetParameter,
tokenX,
tokenY,
program.programId
);
const [reserveX] = deriveReserve(tokenX, lbPair, program.programId);
const [reserveY] = deriveReserve(tokenY, lbPair, program.programId);
const [oracle] = deriveOracle(lbPair, program.programId);
const activeBinArrayIndex = binIdToBinArrayIndex(activeId);
const binArrayBitmapExtension = isOverflowDefaultBinArrayBitmap(
activeBinArrayIndex
) ? deriveBinArrayBitmapExtension(lbPair, program.programId)[0] : null;
return program.methods.initializeLbPair2({
activeId: activeId.toNumber(),
padding: Array(96).fill(0)
}).accountsPartial({
funder,
lbPair,
reserveX,
reserveY,
binArrayBitmapExtension,
tokenMintX: tokenX,
tokenMintY: tokenY,
tokenBadgeX: tokenBadgeXAccount ? tokenBadgeX : program.programId,
tokenBadgeY: tokenBadgeYAccount ? tokenBadgeY : program.programId,
tokenProgramX: tokenXAccount.owner,
tokenProgramY: tokenYAccount.owner,
oracle,
presetParameter,
systemProgram: _web3js.SystemProgram.programId
}).transaction();
}
/**
* The function `refetchStates` retrieves and updates various states and data related to bin arrays
* and lb pairs.
*/
async refetchStates() {
const binArrayBitmapExtensionPubkey = deriveBinArrayBitmapExtension(
this.pubkey,
this.program.programId
)[0];
const [
lbPairAccountInfo,
binArrayBitmapExtensionAccountInfo,
reserveXAccountInfo,
reserveYAccountInfo,
mintXAccountInfo,
mintYAccountInfo,
reward0VaultAccountInfo,
reward1VaultAccountInfo,
rewardMint0AccountInfo,
rewardMint1AccountInfo,
clockAccountInfo
] = await chunkedGetMultipleAccountInfos(this.program.provider.connection, [
this.pubkey,
binArrayBitmapExtensionPubkey,
this.lbPair.reserveX,
this.lbPair.reserveY,
this.lbPair.tokenXMint,
this.lbPair.tokenYMint,
this.lbPair.rewardInfos[0].vault,
this.lbPair.rewardInfos[1].vault,
this.lbPair.rewardInfos[0].mint,
this.lbPair.rewardInfos[1].mint,
_web3js.SYSVAR_CLOCK_PUBKEY
]);
const lbPairState = decodeAccount(
this.program,
"lbPair",
lbPairAccountInfo.data
);
if (binArrayBitmapExtensionAccountInfo) {
const binArrayBitmapExtensionState = decodeAccount(
this.program,
"binArrayBitmapExtension",
binArrayBitmapExtensionAccountInfo.data
);
if (binArrayBitmapExtensionState) {
this.binArrayBitmapExtension = {
account: binArrayBitmapExtensionState,
publicKey: binArrayBitmapExtensionPubkey
};
}
}
const reserveXBalance = _spltoken.AccountLayout.decode(reserveXAccountInfo.data);
const reserveYBalance = _spltoken.AccountLayout.decode(reserveYAccountInfo.data);
const [
tokenXTransferHook,
tokenYTransferHook,
reward0TransferHook,
reward1TransferHook
] = await Promise.all([
getExtraAccountMetasForTransferHook(
this.program.provider.connection,
lbPairState.tokenXMint,
mintXAccountInfo
),
getExtraAccountMetasForTransferHook(
this.program.provider.connection,
lbPairState.tokenYMint,
mintYAccountInfo
),
rewardMint0AccountInfo ? getExtraAccountMetasForTransferHook(
this.program.provider.connection,
lbPairState.rewardInfos[0].mint,
rewardMint0AccountInfo
) : [],
rewardMint1AccountInfo ? getExtraAccountMetasForTransferHook(
this.program.provider.connection,
lbPairState.rewardInfos[1].mint,
rewardMint1AccountInfo
) : []
]);
const mintX = _spltoken.unpackMint.call(void 0,
this.tokenX.publicKey,
mintXAccountInfo,
mintXAccountInfo.owner
);
const mintY = _spltoken.unpackMint.call(void 0,
this.tokenY.publicKey,
mintYAccountInfo,
mintYAccountInfo.owner
);
this.tokenX = {
amount: reserveXBalance.amount,
mint: mintX,
publicKey: lbPairState.tokenXMint,
reserve: lbPairState.reserveX,
owner: mintXAccountInfo.owner,
transferHookAccountMetas: tokenXTransferHook
};
this.tokenY = {
amount: reserveYBalance.amount,
mint: mintY,
publicKey: lbPairState.tokenYMint,
reserve: lbPairState.reserveY,
owner: mintYAccountInfo.owner,
transferHookAccountMetas: tokenYTransferHook
};
this.rewards[0] = null;
this.rewards[1] = null;
if (!lbPairState.rewardInfos[0].mint.equals(_web3js.PublicKey.default)) {
this.rewards[0] = {
publicKey: lbPairState.rewardInfos[0].mint,
reserve: lbPairState.rewardInfos[0].vault,
mint: _spltoken.unpackMint.call(void 0,
lbPairState.rewardInfos[0].mint,
rewardMint0AccountInfo,
rewardMint0AccountInfo.owner
),
amount: _spltoken.AccountLayout.decode(reward0VaultAccountInfo.data).amount,
owner: rewardMint0AccountInfo.owner,
transferHookAccountMetas: reward0TransferHook
};
}
if (!lbPairState.rewardInfos[1].mint.equals(_web3js.PublicKey.default)) {
this.rewards[1] = {
publicKey: lbPairState.rewardInfos[1].mint,
reserve: lbPairState.rewardInfos[1].vault,
mint: _spltoken.unpackMint.call(void 0,
lbPairState.rewardInfos[1].mint,
rewardMint1AccountInfo,
rewardMint1AccountInfo.owner
),
amount: _spltoken.AccountLayout.decode(reward1VaultAccountInfo.data).amount,
owner: rewardMint1AccountInfo.owner,
transferHookAccountMetas: reward1TransferHook
};
}
const clock = ClockLayout.decode(clockAccountInfo.data);
this.clock = clock;
this.lbPair = lbPairState;
}
/**
* Set the status of a permissionless LB pair to either enabled or disabled. This require pool field `creator_pool_on_off_control` to be true and type `CustomizablePermissionless`.
* Pool creator can enable/disable the pair anytime before the pool is opened / activated. Once the pool activation time is passed, the pool creator can only enable the pair.
* Useful for token launches which do not have fixed activation time.
* @param enable If true, the pair will be enabled. If false, the pair will be disabled.
* @param creator The public key of the pool creator.
* @returns a Promise that resolves to the transaction.
*/
async setPairStatusPermissionless(enable, creator) {
const status = enable ? 0 : 1;
const tx = await this.program.methods.setPairStatusPermissionless(status).accountsPartial({
lbPair: this.pubkey,
signer: creator
}).transaction();
const { blockhash, lastValidBlockHeight } = await this.program.provider.connection.getLatestBlockhash("confirmed");
return new (0, _web3js.Transaction)({
feePayer: this.lbPair.creator,
blockhash,
lastValidBlockHeight
}).add(tx);
}
/**
* The function `getBinArrays` returns an array of `BinArrayAccount` objects
* @returns a Promise that resolves to an array of BinArrayAccount objects.
*/
async getBinArrays() {
return this.program.account.binArray.all([
binArrayLbPairFilter(this.pubkey)
]);
}
/**
* The function `getBinArrayAroundActiveBin` retrieves a specified number of `BinArrayAccount`
* objects from the blockchain, based on the active bin and its surrounding bin arrays.
* @param
* swapForY - The `swapForY` parameter is a boolean value that indicates whether the swap is using quote token as input.
* [count=4] - The `count` parameter is the number of bin arrays to retrieve on left and right respectively. By default, it is set to 4.
* @returns an array of `BinArrayAccount` objects.
*/
async getBinArrayForSwap(swapForY, count = 4) {
await this.refetchStates();
const binArraysPubkey = /* @__PURE__ */ new Set();
let shouldStop = false;
let activeIdToLoop = this.lbPair.activeId;
while (!shouldStop) {
const binArrayIndex = findNextBinArrayIndexWithLiquidity(
swapForY,
new (0, _anchor.BN)(activeIdToLoop),
this.lbPair,
_nullishCoalesce(_optionalChain([this, 'access', _91 => _91.binArrayBitmapExtension, 'optionalAccess', _92 => _92.account]), () => ( null))
);
if (binArrayIndex === null)
shouldStop = true;
else {
const [binArrayPubKey] = deriveBinArray(
this.pubkey,
binArrayIndex,
this.program.programId
);
binArraysPubkey.add(binArrayPubKey.toBase58());
const [lowerBinId, upperBinId] = getBinArrayLowerUpperBinId(binArrayIndex);
activeIdToLoop = swapForY ? lowerBinId.toNumber() - 1 : upperBinId.toNumber() + 1;
}
if (binArraysPubkey.size === count)
shouldStop = true;
}
const accountsToFetch = Array.from(binArraysPubkey).map(
(pubkey) => new (0, _web3js.PublicKey)(pubkey)
);
const binArraysAccInfoBuffer = await chunkedGetMultipleAccountInfos(
this.program.provider.connection,
accountsToFetch
);
const binArrays = await Promise.all(
binArraysAccInfoBuffer.map(async (accInfo, idx) => {
const account = decodeAccount(
this.program,
"binArray",
accInfo.data
);
const publicKey = accountsToFetch[idx];
return {
account,
publicKey
};
})
);
return binArrays;
}
/**
* The function `calculateFeeInfo` calculates the base fee rate percentage and maximum fee rate percentage
* given the base factor, bin step, and optional base fee power factor.
* @param baseFactor - The base factor of the pair.
* @param binStep - The bin step of the pair.
* @param baseFeePowerFactor - Optional parameter to allow small bin step to have bigger fee rate. Default to 0.
* @returns an object of type `Omit<FeeInfo, "protocolFeePercentage">` with the following properties: baseFeeRatePercentage and maxFeeRatePercentage.
*/
static calculateFeeInfo(baseFactor, binStep, baseFeePowerFactor) {
const baseFeeRate = new (0, _anchor.BN)(baseFactor).mul(new (0, _anchor.BN)(binStep)).mul(new (0, _anchor.BN)(10)).mul(new (0, _anchor.BN)(10).pow(new (0, _anchor.BN)(_nullishCoalesce(baseFeePowerFactor, () => ( 0)))));
const baseFeeRatePercentage = new (0, _decimaljs2.default)(baseFeeRate.toString()).mul(new (0, _decimaljs2.default)(100)).div(new (0, _decimaljs2.default)(FEE_PRECISION.toString()));
const maxFeeRatePercentage = new (0, _decimaljs2.default)(MAX_FEE_RATE.toString()).mul(new (0, _decimaljs2.default)(100)).div(new (0, _decimaljs2.default)(FEE_PRECISION.toString()));
return {
baseFeeRatePercentage,
maxFeeRatePercentage
};
}
/**
* The function `getFeeInfo` calculates and returns the base fee rate percentage, maximum fee rate
* percentage, and protocol fee percentage.
* @returns an object of type `FeeInfo` with the following properties: baseFeeRatePercentage, maxFeeRatePercentage, and protocolFeePercentage.
*/
getFeeInfo() {
const { baseFactor, protocolShare } = this.lbPair.parameters;
const { baseFeeRatePercentage, maxFeeRatePercentage } = DLMM.calculateFeeInfo(
baseFactor,
this.lbPair.binStep,
this.lbPair.parameters.baseFeePowerFactor
);
const protocolFeePercentage = new (0, _decimaljs2.default)(protocolShare.toString()).mul(new (0, _decimaljs2.default)(100)).div(new (0, _decimaljs2.default)(BASIS_POINT_MAX));
return {
baseFeeRatePercentage,
maxFeeRatePercentage,
protocolFeePercentage
};
}
/**
* The function calculates and returns a dynamic fee
* @returns a Decimal value representing the dynamic fee.
*/
getDynamicFee() {
let vParameterClone = Object.assign({}, this.lbPair.vParameters);
let activeId = new (0, _anchor.BN)(this.lbPair.activeId);
const sParameters3 = this.lbPair.parameters;
const currentTimestamp = Date.now() / 1e3;
DLMM.updateReference(
activeId.toNumber(),
vParameterClone,
sParameters3,
currentTimestamp
);
DLMM.updateVolatilityAccumulator(
vParameterClone,
sParameters3,
activeId.toNumber()
);
const totalFee = getTotalFee(
this.lbPair.binStep,
sParameters3,
vParameterClone
);
return new (0, _decimaljs2.default)(totalFee.toString()).div(new (0, _decimaljs2.default)(FEE_PRECISION.toString())).mul(100);
}
/**
* The function `getEmissionRate` returns the emission rates for two rewards.
* @returns an object of type `EmissionRate`. The object has two properties: `rewardOne` and
* `rewardTwo`, both of which are of type `Decimal`.
*/
getEmissionRate() {
const now = Date.now() / 1e3;
const [rewardOneEmissionRate, rewardTwoEmissionRate] = this.lbPair.rewardInfos.map(
({ rewardRate, rewardDurationEnd }) => now > rewardDurationEnd.toNumber() ? void 0 : rewardRate
);
return {
rewardOne: rewardOneEmissionRate ? new (0, _decimaljs2.default)(rewardOneEmissionRate.toString()).div(PRECISION) : void 0,
rewardTwo: rewardTwoEmissionRate ? new (0, _decimaljs2.default)(rewardTwoEmissionRate.toString()).div(PRECISION) : void 0
};
}
/**
* The function `getBinsAroundActiveBin` retrieves a specified number of bins to the left and right
* of the active bin and returns them along with the active bin ID.
* @param {number} numberOfBinsToTheLeft - The parameter `numberOfBinsToTheLeft` represents the
* number of bins to the left of the active bin that you want to retrieve. It determines how many
* bins you want to include in the result that are positioned to the left of the active bin.
* @param {number} numberOfBinsToTheRight - The parameter `numberOfBinsToTheRight` represents the
* number of bins to the right of the active bin that you want to retrieve.
* @returns an object with two properties: "activeBin" and "bins". The value of "activeBin" is the
* value of "this.lbPair.activeId", and the value of "bins" is the result of calling the "getBins"
* function with the specified parameters.
*/
async getBinsAroundActiveBin(numberOfBinsToTheLeft, numberOfBinsToTheRight) {
const lowerBinId = this.lbPair.activeId - numberOfBinsToTheLeft - 1;
const upperBinId = this.lbPair.activeId + numberOfBinsToTheRight + 1;
const bins = await this.getBins(
this.pubkey,
lowerBinId,
upperBinId,
this.tokenX.mint.decimals,
this.tokenY.mint.decimals
);
return { activeBin: this.lbPair.activeId, bins };
}
/**
* The function `getBinsBetweenMinAndMaxPrice` retrieves a list of bins within a specified price
* range.
* @param {number} minPrice - The minimum price value for filtering the bins.
* @param {number} maxPrice - The `maxPrice` parameter is the maximum price value that you want to
* use for filtering the bins.
* @returns an object with two properties: "activeBin" and "bins". The value of "activeBin" is the
* active bin ID of the lbPair, and the value of "bins" is an array of BinLiquidity objects.
*/
async getBinsBetweenMinAndMaxPrice(minPrice, maxPrice) {
const lowerBinId = this.getBinIdFromPrice(minPrice, true) - 1;
const upperBinId = this.getBinIdFromPrice(maxPrice, false) + 1;
const bins = await this.getBins(
this.pubkey,
lowerBinId,
upperBinId,
this.tokenX.mint.decimals,
this.tokenY.mint.decimals
);
return { activeBin: this.lbPair.activeId, bins };
}
/**
* The function `getBinsBetweenLowerAndUpperBound` retrieves a list of bins between a lower and upper
* bin ID and returns the active bin ID and the list of bins.
* @param {number} lowerBinId - The lowerBinId parameter is a number that represents the ID of the
* lowest bin.
* @param {number} upperBinId - The upperBinID parameter is a number that represents the ID of the
* highest bin.
* @param {BinArray} [lowerBinArrays] - The `lowerBinArrays` parameter is an optional parameter of
* type `BinArray`. It represents an array of bins that are below the lower bin ID.
* @param {BinArray} [upperBinArrays] - The parameter `upperBinArrays` is an optional parameter of
* type `BinArray`. It represents an array of bins that are above the upper bin ID.
* @returns an object with two properties: "activeBin" and "bins". The value of "activeBin" is the
* active bin ID of the lbPair, and the value of "bins" is an array of BinLiquidity objects.
*/
async getBinsBetweenLowerAndUpperBound(lowerBinId, upperBinId, lowerBinArray, upperBinArray) {
const bins = await this.getBins(
this.pubkey,
lowerBinId,
upperBinId,
this.tokenX.mint.decimals,
this.tokenY.mint.decimals,
lowerBinArray,
upperBinArray
);
return { activeBin: this.lbPair.activeId, bins };
}
/**
* The function converts a real price of bin to a lamport value
* @param {number} price - The `price` parameter is a number representing the price of a token.
* @returns {string} price per Lamport of bin
*/
toPricePerLamport(price) {
return DLMM.getPricePerLamport(
this.tokenX.mint.decimals,
this.tokenY.mint.decimals,
price
);
}
/**
* The function converts a price per lamport value to a real price of bin
* @param {number} pricePerLamport - The parameter `pricePerLamport` is a number representing the
* price per lamport.
* @returns {string} real price of bin
*/
fromPricePerLamport(pricePerLamport) {
return new (0, _decimaljs2.default)(pricePerLamport).div(
new (0, _decimaljs2.default)(
10 ** (this.tokenY.mint.decimals - this.tokenX.mint.decimals)
)
).toString();
}
/**
* The function retrieves the active bin ID and its corresponding price.
* @returns an object with two properties: "binId" which is a number, and "price" which is a string.
*/
async getActiveBin() {
const { activeId } = await this.program.account.lbPair.fetch(this.pubkey);
const [activeBinState] = await this.getBins(
this.pubkey,
activeId,
activeId,
this.tokenX.mint.decimals,
this.tokenY.mint.decimals
);
return activeBinState;
}
/**
* The function get bin ID based on a given price and a boolean flag indicating whether to
* round down or up.
* @param {number} price - The price parameter is a number that represents the price value.
* @param {boolean} min - The "min" parameter is a boolean value that determines whether to round
* down or round up the calculated binId. If "min" is true, the binId will be rounded down (floor),
* otherwise it will be rounded up (ceil).
* @returns {number} which is the binId calculated based on the given price and whether the minimum
* value should be used.
*/
getBinIdFromPrice(price, min) {
return DLMM.getBinIdFromPrice(price, this.lbPair.binStep, min);
}
/**
* The function `getLimitOrderByUserAndLbPair` retrieves all limit orders for a user in the current LB pair
* and parses them with on-chain bin array and clock state.
* @param {PublicKey} userPubKey - The public key of the user who owns the limit orders.
* @returns A Promise that resolves to an array of parsed limit orders with their public keys.
*/
async getLimitOrderByUserAndLbPair(userPubKey) {
const limitOrderAccounts = await chunkedGetProgramAccounts(
this.program.provider.connection,
this.program.programId,
[
limitOrderFilter(),
limitOrderOwnerFilter(userPubKey),
limitOrderLbPairFilter(this.pubkey)
]
);
const limitOrders = limitOrderAccounts.map(
({ account, pubkey }) => {
return wrapLimitOrder(this.program, pubkey, account);
}
);
const binArrayPubkeysSet = /* @__PURE__ */ new Set();
limitOrders.forEach((lo) => {
const binArrayPubkeys = lo.getBinArrayKeysCoverage(
this.program.programId
);
binArrayPubkeys.forEach((key) => {
binArrayPubkeysSet.add(key.toString());
});
});
const binArrayPubkeyArrays = Array.from(binArrayPubkeysSet).map(
(pubkey) => new (0, _web3js.PublicKey)(pubkey)
);
const lbPairAndBinArrays = await chunkedGetMultipleAccountInfos(
this.program.provider.connection,
[this.pubkey, _web3js.SYSVAR_CLOCK_PUBKEY, ...binArrayPubkeyArrays]
);
const [lbPairAccInfo, clockAccInfo, ...binArraysAccInfo] = lbPairAndBinArrays;
const clock = ClockLayout.decode(clockAccInfo.data);
const lbPairState = decodeAccount(
this.program,
"lbPair",
lbPairAccInfo.data
);
const binArrayMap = /* @__PURE__ */ new Map();
for (let i = 0; i < binArraysAccInfo.length; i++) {
const binArrayPubkey = binArrayPubkeyArrays[i];
const binArrayAccInfo = binArraysAccInfo[i];
const binArrayState = decodeAccount(
this.program,
"binArray",
binArrayAccInfo.data
);
binArrayMap.set(binArrayPubkey.toBase58(), binArrayState);
}
const parsedLimitOrder = limitOrders.map(
(lo) => {
const parsedLo = lo.parseInfo(
this.program.programId,
lbPairState,
this.tokenX.mint,
this.tokenY.mint,
clock,
binArrayMap
);
return {
publicKey: lo.address(),
limitOrderData: parsedLo
};
}
);
return parsedLimitOrder;
}
/**
* Fetches and parses a single limit order by address for the current LB pair.
*
* This method loads the limit order account, the LB pair state, clock sysvar,
* and all required bin arrays to produce a parsed limit order view.
* @param {PublicKey} limitOrder - The public key of the limit order account.
* @returns A Promise that resolves to the parsed limit order with its public key.
*/
async getLimitOrder(limitOrder) {
const limitOrderAccount = await this.program.provider.connection.getAccountInfo(limitOrder);
const limitOrderState = wrapLimitOrder(
this.program,
limitOrder,
limitOrderAccount
);
const binArrayPubkeyArrays = limitOrderState.getBinArrayKeysCoverage(
this.program.programId
);
const lbPairAndBinArrays = await chunkedGetMultipleAccountInfos(
this.program.provider.connection,
[this.pubkey, _web3js.SYSVAR_CLOCK_PUBKEY, ...binArrayPubkeyArrays]
);
const [lbPairAccInfo, clockAccInfo, ...binArraysAccInfo] = lbPairAndBinArrays;
const clock = ClockLayout.decode(clockAccInfo.data);
const lbPairState = decodeAccount(
this.program,
"lbPair",
lbPairAccInfo.data
);
const binArrayMap = /* @__PURE__ */ new Map();
for (let i = 0; i < binArraysAccInfo.length; i++) {
const binArrayPubkey = binArrayPubkeyArrays[i];
const binArrayAccInfo = binArraysAccInfo[i];
const binArrayState = decodeAccount(
this.program,
"binArray",
binArrayAccInfo.data
);
binArrayMap.set(binArrayPubkey.toBase58(), binArrayState);
}
const parsedLo = limitOrderState.parseInfo(
this.program.programId,
lbPairState,
this.tokenX.mint,
this.tokenY.mint,
clock,
binArrayMap
);
return {
publicKey: limitOrder,
limitOrderData: parsedLo
};
}
/**
* The function `getPositionsByUserAndLbPair` retrieves positions by user and LB pair, including
* active bin and user positions.
* @param {PublicKey} [userPubKey] - The `userPubKey` parameter is an optional parameter of type
* `PublicKey`. It represents the public key of a user. If no `userPubKey` is provided, the function
* will return an object with an empty `userPositions` array and the active bin information obtained
* from the `getActive
* @param {GetPositionsOpt} [getPositionsOpt] - Optional settings for chunked position fetching
* @returns The function `getPositionsByUserAndLbPair` returns a Promise that resolves to an object
* with two properties:
* - "activeBin" which is an object with two properties: "binId" and "price". The value of "binId"
* is the active bin ID of the lbPair, and the value of "price" is the price of the active bin.
* - "userPositions" which is an array of Position objects.
*/
async getPositionsByUserAndLbPair(userPubKey, getPositionsOpt) {
const promiseResults = await Promise.all([
this.getActiveBin(),
userPubKey && chunkedGetProgramAccounts(
this.program.provider.connection,
this.program.programId,
[
positionV2Filter(),
positionOwnerFilter(userPubKey),
positionLbPairFilter(this.pubkey)
],
_optionalChain([getPositionsOpt, 'optionalAccess', _93 => _93.chunkSize]),
_optionalChain([getPositionsOpt, 'optionalAccess', _94 => _94.onChunkFetched]),
_optionalChain([getPositionsOpt, 'optionalAccess', _95 => _95.isParallelExecution])
)
]);
const [activeBin, positionsV2] = promiseResults;
if (!activeBin) {
throw new Error("Error fetching active bin");
}
if (!userPubKey) {
return {
activeBin,
userPositions: []
};
}
const positions = [
...positionsV2.map(
(p) => wrapPosition(this.program, p.pubkey, p.account)
)
];
if (!positions) {
throw new Error("Error fetching positions");
}
const binArrayPubkeySetV2 = /* @__PURE__ */ new Set();
positions.forEach((position) => {
const binArrayKeys = position.getBinArrayKeysCoverage(
this.program.programId
);
binArrayKeys.forEach((key) => {
binArrayPubkeySetV2.add(key.toBase58());
});
});
const binArrayPubkeyArrayV2 = Array.from(binArrayPubkeySetV2).map(
(pubkey) => new (0, _web3js.PublicKey)(pubkey)
);
const lbPairAndBinArrays = await chunkedGetMultipleAccountInfos(
this.program.provider.connection,
[this.pubkey, _web3js.SYSVAR_CLOCK_PUBKEY, ...binArrayPubkeyArrayV2]
);
const [lbPairAccInfo, clockAccInfo, ...binArraysAccInfo] = lbPairAndBinArrays;
const positionBinArraysMapV2 = /* @__PURE__ */ new Map();
for (let i = 0; i < binArraysAccInfo.length; i++) {
const binArrayPubkey = binArrayPubkeyArrayV2[i];
const binArrayAccBufferV2 = binArraysAccInfo[i];
if (binArrayAccBufferV2) {
const binArrayAccInfo = decodeAccount(
this.program,
"binArray",
binArrayAccBufferV2.data
);
positionBinArraysMapV2.set(binArrayPubkey.toBase58(), binArrayAccInfo);
}
}
if (!lbPairAccInfo)
throw new Error(`LB Pair account ${this.pubkey.toBase58()} not found`);
const clock = ClockLayout.decode(clockAccInfo.data);
const userPositions = await Promise.all(
positions.map(async (position) => {
return {
publicKey: position.address(),
positionData: await DLMM.processPosition(
this.program,
this.lbPair,
clock,
position,
this.tokenX.mint,
this.tokenY.mint,
_optionalChain([this, 'access', _96 => _96.rewards, 'access', _97 => _97[0], 'optionalAccess', _98 => _98.mint]),
_optionalChain([this, 'access', _99 => _99.rewards, 'access', _100 => _100[1], 'optionalAccess', _101 => _101.mint]),
positionBinArraysMapV2
),
version: position.version()
};
})
);
return {
activeBin,
userPositions
};
}
/**
* Estimates the cost to extend a position by a specified number of bins. Max position length is 1400
*
* The function calculates the rent cost required to expand a position and the cost
* to create necessary bin arrays for the new position range.
*
* @param currentMinBinId - The current minimum bin ID of the position.
* @param currentMaxBinId - The current maximum bin ID of the position.
* @param binCountToExpand - The number of bins to expand the position by.
* @returns An object containing:
* - positionExtendCost: The estimated rent cost in lamports for extending the position.
* - binArrayCost: The estimated cost for creating necessary bin arrays.
*/
async quoteExtendPosition(currentMinBinId, currentMaxBinId, binCountToExpand) {
const positionExtendCost = await getPositionExpandRentExemption(
currentMinBinId,
currentMaxBinId,
this.program.provider.connection,
binCountToExpand
);
const lowerBinArrayIndex = binIdToBinArrayIndex(currentMinBinId);
const upperBinArrayIndex = binIdToBinArrayIndex(currentMaxBinId);
const binArraysCount = (await this.binArraysToBeCreate(lowerBinArrayIndex, upperBinArrayIndex)).length;
const binArrayCost = new (0, _decimaljs2.default)(binArraysCount).mul(
new (0, _decimaljs2.default)(BIN_ARRAY_FEE)
);
return {
positionExtendCost: new (0, _decimaljs2.default)(positionExtendCost).div(
new (0, _decimaljs2.default)(_web3js.LAMPORTS_PER_SOL)
),
binArrayCost
};
}
async quoteCreatePosition({ strategy }) {
const { minBinId, maxBinId } = strategy;
const binCount = maxBinId - minBinId + 1;
let positionCount = Math.floor(binCount / MAX_BINS_PER_POSITION.toNumber());
if (binCount % MAX_BINS_PER_POSITION.toNumber() > 0) {
positionCount++;
}
let positionReallocCost = 0;
let lastUpperBinId = minBinId;
for (let i = 0; i < positionCount; i++) {
const lowerBinId = lastUpperBinId;
const upperBinId = Math.min(
maxBinId,
lowerBinId + DEFAULT_BIN_PER_POSITION.toNumber() - 1
);
const maxUpperBinId = Math.min(
maxBinId,
upperBinId + MAX_BINS_PER_POSITION.toNumber() - 1
);
const binToExpand = maxUpperBinId - upperBinId;
const { positionExtendCost } = await this.quoteExtendPosition(
new (0, _anchor.BN)(lowerBinId),
new (0, _anchor.BN)(upperBinId),
new (0, _anchor.BN)(binToExpand)
);
positionReallocCost += positionExtendCost.toNumber();
lastUpperBinId = upperBinId;
}
const lowerBinArrayIndex = binIdToBinArrayIndex(new (0, _anchor.BN)(minBinId));
const upperBinArrayIndex = _anchor.BN.max(
binIdToBinArrayIndex(new (0, _anchor.BN)(maxBinId)),
lowerBinArrayIndex.add(new (0, _anchor.BN)(1))
);
let bitmapExtensionCost = 0;
if (isOverflowDefaultBinArrayBitmap(lowerBinArrayIndex) || isOverflowDefaultBinArrayBitmap(upperBinArrayIndex)) {
bitmapExtensionCost = BIN_ARRAY_BITMAP_FEE;
}
const binArraysCount = (await this.binArraysToBeCreate(lowerBinArrayIndex, upperBinArrayIndex)).length;
const transactionCount = Math.ceil(
(maxBinId - minBinId + 1) / DEFAULT_BIN_PER_POSITION.toNumber()
);
const binArrayCost = binArraysCount * BIN_ARRAY_FEE;
return {
positionCount,
positionCost: positionCount * POSITION_FEE,
positionReallocCost,
bitmapExtensionCost,
binArraysCount,
binArrayCost,
transactionCount
};
}
/**
* Quote the cost to create a limit order
* @param bins - Array of bin IDs (absolute, or relative offsets from active bin if relativeBin is set) to place limit orders in.
* @param relativeBin - When set, the `bin.id` in `params.bins` will be treated as relative to the current active bin, which mean bin.id = bin.id + activeId. Otherwise, it will be absolute bin id.
*/
async quoteCreateLimitOrder({
bins,
relativeBin
}) {
const binCount = bins.length;
if (binCount <= 0 || binCount > MAX_BIN_PER_LIMIT_ORDER.toNumber()) {
throw new Error(
`Bin count must be between 1 and ${MAX_BIN_PER_LIMIT_ORDER.toNumber()}`
);
}
for (let i = 1; i < binCount; i++) {
const prevBinId = bins[i - 1].id;
const currentBinId = bins[i].id;
if (currentBinId <= prevBinId) {
throw new Error(`Bin IDs must be in increasing order`);
}
}
const resolvedBinIds = bins.map(
(bin) => relativeBin == null ? bin.id : bin.id + this.lbPair.activeId
);
const { binArrayBitmapExtension, binArrayAccountMetas } = getBinArrayInfoForNonContiguousBinIds(
resolvedBinIds,
this.program.programId,
this.pubkey
);
const requireBitmapExtension = !binArrayBitmapExtension.equals(
this.program.programId
);
const limitOrderAccountSize = 8 + LIMIT_ORDER_MIN_SIZE + binCount * LIMIT_ORDER_BIN_DATA_SIZE;
const limitOrderCost = await this.program.provider.connection.getMinimumBalanceForRentExemption(
limitOrderAccountSize
);
const binArrayPubkeys = binArrayAccountMetas.map((acc) => acc.pubkey);
const accountsToFetch = [...binArrayPubkeys];
if (requireBitmapExtension) {
accountsToFetch.push(binArrayBitmapExtension);
}
const accounts = await chunkedGetMultipleAccountInfos(
this.program.provider.connection,
accountsToFetch
);
const binArrayAccounts = accounts.splice(0, binArrayPubkeys.length);
const bitmapExtensionAccount = accounts.splice(0, accounts.length).pop();
const uninitializedBinArrayCount = binArrayAccounts.filter(
(acc) => acc === null
).length;
let bitmapExtensionCost = 0;
if (requireBitmapExtension && !bitmapExtensionAccount) {
bitmapExtensionCost = BIN_ARRAY_BITMAP_FEE;
}
const binArrayCost = uninitializedBinArrayCount * BIN_ARRAY_FEE;
return {
limitOrderCost: limitOrderCost / _web3js.LAMPORTS_PER_SOL,
binArraysCount: uninitializedBinArrayCount,
binArrayCost,
bitmapExtensionCost
};
}
/**
* Creates an empty position and initializes the corresponding bin arrays if needed.
* @param param0 The settings of the requested new position.
* @returns A promise that resolves into a transaction for creating the requested position.
*/
async createEmptyPosition({
positionPubKey,
minBinId,
maxBinId,
user
}) {
const createPositionIx = await this.program.methods.initializePosition(minBinId, maxBinId - minBinId + 1).accountsPartial({
payer: user,
position: positionPubKey,
lbPair: this.pubkey,
owner: user,
rent: _web3js.SYSVAR_RENT_PUBKEY
}).instruction();
const binArrayIndexes = getBinArrayIndexesCoverage(
new (0, _anchor.BN)(minBinId),
new (0, _anchor.BN)(maxBinId)
);
const createBinArrayIxs = await this.createBinArraysIfNeeded(
binArrayIndexes,
user
);
const instructions = [createPositionIx, ...createBinArrayIxs];
const setCUIx = await getEstimatedComputeUnitIxWithBuffer(
this.program.provider.connection,
instructions,
user
);
const { blockhash, lastValidBlockHeight } = await this.program.provider.connection.getLatestBlockhash("confirmed");
return new (0, _web3js.Transaction)({
blockhash,
lastValidBlockHeight,
feePayer: user
}).add(setCUIx, ...instructions);
}
/**
* The function `getPosition` retrieves position information for a given public key and processes it
* using various data to return a `LbPosition` object.
* @param {PublicKey} positionPubKey - The `getPosition` function you provided is an asynchronous
* function that fetches position information based on a given public key. Here's a breakdown of the
* parameters used in the function:
* @returns The `getPosition` function returns a Promise that resolves to an object of type
* `LbPosition`. The object contains the following properties:
* - `publicKey`: The public key of the position account
* - `positionData`: Position Object
* - `version`: The version of the position (in this case, `Position.V2`)
*/
async getPosition(positionPubKey) {
const positionAccountInfo = await this.program.provider.connection.getAccountInfo(positionPubKey);
if (!positionAccountInfo) {
throw new Error(
`Position account ${positionPubKey.toBase58()} not found`
);
}
let position = wrapPosition(
this.program,
positionPubKey,
positionAccountInfo
);
const binArrayKeys = position.getBinArrayKeysCoverage(
this.program.programId
);
const [clockAccInfo, ...binArrayAccountsInfo] = await chunkedGetMultipleAccountInfos(this.program.provider.connection, [
_web3js.SYSVAR_CLOCK_PUBKEY,
...binArrayKeys
]);
const clock = ClockLayout.decode(clockAccInfo.data);
const binArrayMap = /* @__PURE__ */ new Map();
for (let i = 0; i < binArrayAccountsInfo.length; i++) {
if (binArrayAccountsInfo[i]) {
const binArrayState = decodeAccount(
this.program,
"binArray",
binArrayAccountsInfo[i].data
);
binArrayMap.set(binArrayKeys[i].toBase58(), binArrayState);
}
}
return {
publicKey: positionPubKey,
positionData: await DLMM.processPosition(
this.program,
this.lbPair,
clock,
position,
this.tokenX.mint,
this.tokenY.mint,
_optionalChain([this, 'access', _102 => _102.rewards, 'access', _103 => _103[0], 'optionalAccess', _104 => _104.mint]),
_optionalChain([this, 'access', _105 => _105.rewards, 'access', _106 => _106[1], 'optionalAccess', _107 => _107.mint]),
binArrayMap
),
version: position.version()
};
}
/**
* Creates multiple positions and adds liquidity by strategy. It allow parallel execution of transactions.
* @param positionKeypairGenerator A function that generates a specified number of keypairs.
* @param totalXAmount The total amount of token X to be added.
* @param totalYAmount The total amount of token Y to be added.
* @param strategy The strategy for adding liquidity.
* @param owner The owner of the position.
* @param payer The payer of the transaction.
* @param slippagePercentage The slippage percentage for adding liquidity.
* @returns An object with two properties: `initPositionIxs` and `addLiquidityIxs`.
*/
async initializeMultiplePositionAndAddLiquidityByStrategy2(positionKeypairGenerator, totalXAmount, totalYAmount, strategy, owner, payer, slippagePercentage, altAddress) {
const maxActiveBinSlippage = getAndCapMaxActiveBinSlippage(
slippagePercentage,
this.lbPair.binStep,
MAX_ACTIVE_BIN_SLIPPAGE
);
const { minBinId, maxBinId } = strategy;
const binCount = getBinCount(minBinId, maxBinId);
const defaultAltAddressString = _nullishCoalesce(altAddress, () => ( ALT_ADDRESS[_optionalChain([this, 'access', _108 => _108.opt, 'optionalAccess', _109 => _109.cluster])]));
if (defaultAltAddressString) {
altAddress = new (0, _web3js.PublicKey)(defaultAltAddressString);
}
const maxResizeIxAllowed = altAddress ? 5 : 3;
const maxBinPerParallelizedPosition = DEFAULT_BIN_PER_POSITION.toNumber() + MAX_RESIZE_LENGTH.toNumber() * maxResizeIxAllowed;
const positionCount = Math.ceil(binCount / maxBinPerParallelizedPosition);
const positionKeypairs = await positionKeypairGenerator(positionCount);
const liquidityStrategyParameters = buildLiquidityStrategyParameters(
totalXAmount,
totalYAmount,
new (0, _anchor.BN)(minBinId - this.lbPair.activeId),
new (0, _anchor.BN)(maxBinId - this.lbPair.activeId),
new (0, _anchor.BN)(this.lbPair.binStep),
strategy.singleSidedX,
new (0, _anchor.BN)(this.lbPair.activeId),
getLiquidityStrategyParameterBuilder(strategy.strategyType)
);
let startBinId = minBinId;
const response = { instructionsByPositions: [], lookupTableAddress: altAddress };
for (const position of positionKeypairs) {
const txsIxs = [];
const endBinId = Math.min(
startBinId + maxBinPerParallelizedPosition - 1,
maxBinId
);
const finalPositionWidth = endBinId - startBinId + 1;
const initialPositionWidth = finalPositionWidth > DEFAULT_BIN_PER_POSITION.toNumber() ? DEFAULT_BIN_PER_POSITION.toNumber() : finalPositionWidth;
const initPositionIx = await this.program.methods.initializePosition2(startBinId, initialPositionWidth).accountsPartial({
position: position.publicKey,
lbPair: this.pubkey,
owner,
payer
}).instruction();
const extendPositionIxs = [];
let currentEndBinId = startBinId + initialPositionWidth - 1;
while (true) {
if (currentEndBinId == endBinId)
break;
currentEndBinId = Math.min(
currentEndBinId + MAX_RESIZE_LENGTH.toNumber(),
endBinId
);
const increaseLengthIx = await this.program.methods.increasePositionLength2(currentEndBinId).accountsPartial({
lbPair: this.pubkey,
position: position.publicKey,
funder: payer,
owner
}).instruction();
extendPositionIxs.push(increaseLengthIx);
}
const addLiquidityIxs = await chunkDepositWithRebalanceEndpoint(
this,
strategy,
slippagePercentage,
maxActiveBinSlippage,
position.publicKey,
startBinId,
endBinId,
liquidityStrategyParameters,
owner,
payer,
true,
_optionalChain([this, 'access', _110 => _110.opt, 'optionalAccess', _111 => _111.skipSolWrappingOperation])
);
for (const instructions of addLiquidityIxs) {
const txIxs = [];
txIxs.push(initPositionIx);
txIxs.push(...extendPositionIxs);
txIxs.push(...instructions);
const setCuIx = await getEstimatedComputeUnitIxWithBuffer(
this.program.provider.connection,
txIxs,
payer,
0.1,
altAddress
);
txIxs.unshift(setCuIx);
txsIxs.push(txIxs);
}
response.instructionsByPositions.push({
positionKeypair: position,
transactionInstructions: txsIxs
});
startBinId = endBinId + 1;
}
return response;
}
/**
* Creates multiple positions and adds liquidity by strategy without chainsaw issues.
* @param positionKeypairGenerator A function that generates a specified number of keypairs.
* @param totalXAmount The total amount of token X to be added.
* @param totalYAmount The total amount of token Y to be added.
* @param strategy The strategy for adding liquidity.
* @param owner The owner of the position.
* @param payer The payer of the transaction.
* @param slippagePercentage The slippage percentage for adding liquidity.
* @returns An object with two properties: `initPositionIxs` and `addLiquidityIxs`.
*/
async initializeMultiplePositionAndAddLiquidityByStrategy(positionKeypairGenerator, totalXAmount, totalYAmount, strategy, owner, payer, slippagePercentage) {
const maxActiveBinSlippage = getAndCapMaxActiveBinSlippage(
slippagePercentage,
this.lbPair.binStep,
MAX_ACTIVE_BIN_SLIPPAGE
);
const { minBinId, maxBinId } = strategy;
const binCount = getBinCount(minBinId, maxBinId);
const positionCount = getPositionCountByBinCount(binCount);
const positionKeypairs = await positionKeypairGenerator(positionCount);
const liquidityStrategyParameters = buildLiquidityStrategyParameters(
totalXAmount,
totalYAmount,
new (0, _anchor.BN)(minBinId - this.lbPair.activeId),
new (0, _anchor.BN)(maxBinId - this.lbPair.activeId),
new (0, _anchor.BN)(this.lbPair.binStep),
strategy.singleSidedX,
new (0, _anchor.BN)(this.lbPair.activeId),
getLiquidityStrategyParameterBuilder(strategy.strategyType)
);
const instructionsByPositions = [];
let startBinId = minBinId;
const initializeAtaIxs = [];
if (!this.tokenX.publicKey.equals(_spltoken.NATIVE_MINT)) {
const ownerAtaX = _spltoken.getAssociatedTokenAddressSync.call(void 0,
this.tokenX.publicKey,
owner,
true,
this.tokenX.owner
);
initializeAtaIxs.push(
_spltoken.createAssociatedTokenAccountIdempotentInstruction.call(void 0,
owner,
ownerAtaX,
owner,
this.tokenX.publicKey,
this.tokenX.owner
)
);
}
if (!this.tokenY.publicKey.equals(_spltoken.NATIVE_MINT)) {
const ownerAtaY = _spltoken.getAssociatedTokenAddressSync.call(void 0,
this.tokenY.publicKey,
owner,
true,
this.tokenY.owner
);
initializeAtaIxs.push(
_spltoken.createAssociatedTokenAccountIdempotentInstruction.call(void 0,
owner,
ownerAtaY,
owner,
this.tokenY.publicKey,
this.tokenY.owner
)
);
}
for (const position of positionKeypairs) {
const endBinId = Math.min(
startBinId + MAX_BINS_PER_POSITION.toNumber() - 1,
maxBinId
);
const binCount2 = getBinCount(startBinId, endBinId);
const positionWidth = Math.min(
binCount2,
DEFAULT_BIN_PER_POSITION.toNumber()
);
const initPositionIx = await this.program.methods.initializePosition(startBinId, positionWidth).accountsPartial({
position: position.publicKey,
lbPair: this.pubkey,
owner,
payer,
rent: _web3js.SYSVAR_RENT_PUBKEY
}).instruction();
const chunkedAddLiquidityIx = await chunkDepositWithRebalanceEndpoint(
this,
strategy,
slippagePercentage,
maxActiveBinSlippage,
position.publicKey,
startBinId,
endBinId,
liquidityStrategyParameters,
owner,
payer,
false,
_optionalChain([this, 'access', _112 => _112.opt, 'optionalAccess', _113 => _113.skipSolWrappingOperation])
);
instructionsByPositions.push({
positionKeypair: position,
initializePositionIx: initPositionIx,
initializeAtaIxs,
addLiquidityIxs: chunkedAddLiquidityIx
});
startBinId = endBinId + 1;
}
return {
instructionsByPositions
};
}
/**
* Adds liquidity to an existing position using a specified strategy, allowing for chunkable transactions.
* If adding liquidity to bin out of position range, it will automatically expand. The limitation is 70 bins.
*
* @param {TInitializePositionAndAddLiquidityParamsByStrategy} params - The parameters required for adding liquidity.
* @param {PublicKey} params.positionPubKey - The public key of the position to which liquidity is being added.
* @param {BN} params.totalXAmount - The total amount of token X to be added as liquidity.
* @param {BN} params.totalYAmount - The total amount of token Y to be added as liquidity.
* @param {StrategyParameters} params.strategy - The strategy parameters for adding liquidity.
* @param {PublicKey} params.user - The public key of the user adding liquidity.
* @param {number} params.slippage - The slippage percentage allowed for the transaction.
*
* @returns {Promise<Transaction[]>} A promise that resolves to an array of transactions for adding liquidity.
*/
async addLiquidityByStrategyChunkable({
positionPubKey,
totalXAmount,
totalYAmount,
strategy,
user,
slippage
}) {
const maxActiveBinSlippage = getAndCapMaxActiveBinSlippage(
slippage,
this.lbPair.binStep,
MAX_ACTIVE_BIN_SLIPPAGE
);
const { minBinId, maxBinId } = strategy;
const liquidityStrategyParameters = buildLiquidityStrategyParameters(
totalXAmount,
totalYAmount,
new (0, _anchor.BN)(minBinId - this.lbPair.activeId),
new (0, _anchor.BN)(maxBinId - this.lbPair.activeId),
new (0, _anchor.BN)(this.lbPair.binStep),
strategy.singleSidedX,
new (0, _anchor.BN)(this.lbPair.activeId),
getLiquidityStrategyParameterBuilder(strategy.strategyType)
);
const chunkedAddLiquidityIx = await chunkDepositWithRebalanceEndpoint(
this,
strategy,
slippage,
maxActiveBinSlippage,
positionPubKey,
minBinId,
maxBinId,
liquidityStrategyParameters,
user,
user,
true,
_optionalChain([this, 'access', _114 => _114.opt, 'optionalAccess', _115 => _115.skipSolWrappingOperation])
);
const latestBlockhashInfo = await this.program.provider.connection.getLatestBlockhash();
return chunkedAddLiquidityIx.map((ixs) => {
return new (0, _web3js.Transaction)({
...latestBlockhashInfo,
feePayer: user
}).add(...ixs);
});
}
/**
* The function `initializePositionAndAddLiquidityByStrategy` function is used to initializes a position and adds liquidity
* @param {TInitializePositionAndAddLiquidityParamsByStrategy}
* - `positionPubKey`: The public key of the position account. (usually use `new Keypair()`)
* - `totalXAmount`: The total amount of token X to be added to the liquidity pool.
* - `totalYAmount`: The total amount of token Y to be added to the liquidity pool.
* - `strategy`: The strategy parameters to be used for the liquidity pool (Can use `calculateStrategyParameter` to calculate).
* - `user`: The public key of the user account.
* - `slippage`: The slippage percentage to be used for the liquidity pool.
* @returns {Promise<Transaction>} The function `initializePositionAndAddLiquidityByStrategy` returns a `Promise` that
* resolves to either a single `Transaction` object.
*/
async initializePositionAndAddLiquidityByStrategy({
positionPubKey,
totalXAmount,
totalYAmount,
strategy,
user,
slippage
}) {
const { maxBinId, minBinId } = strategy;
const maxActiveBinSlippage = slippage ? Math.ceil(slippage / (this.lbPair.binStep / 100)) : MAX_ACTIVE_BIN_SLIPPAGE;
const preInstructions = [];
const initializePositionIx = await this.program.methods.initializePosition(minBinId, maxBinId - minBinId + 1).accountsPartial({
payer: user,
position: positionPubKey,
lbPair: this.pubkey,
owner: user,
rent: _web3js.SYSVAR_RENT_PUBKEY
}).instruction();
preInstructions.push(initializePositionIx);
const binArrayIndexes = getBinArrayIndexesCoverage(
new (0, _anchor.BN)(minBinId),
new (0, _anchor.BN)(maxBinId)
);
const binArrayAccountMetas = getBinArrayAccountMetasCoverage(
new (0, _anchor.BN)(minBinId),
new (0, _anchor.BN)(maxBinId),
this.pubkey,
this.program.programId
);
const createBinArrayIxs = await this.createBinArraysIfNeeded(
binArrayIndexes,
user
);
preInstructions.push(...createBinArrayIxs);
const [
{ ataPubKey: userTokenX, ix: createPayerTokenXIx },
{ ataPubKey: userTokenY, ix: createPayerTokenYIx }
] = await Promise.all([
getOrCreateATAInstruction(
this.program.provider.connection,
this.tokenX.publicKey,
user,
this.tokenX.owner
),
getOrCreateATAInstruction(
this.program.provider.connection,
this.tokenY.publicKey,
user,
this.tokenY.owner
)
]);
createPayerTokenXIx && preInstructions.push(createPayerTokenXIx);
createPayerTokenYIx && preInstructions.push(createPayerTokenYIx);
if (this.tokenX.publicKey.equals(_spltoken.NATIVE_MINT) && !totalXAmount.isZero() && !_optionalChain([this, 'access', _116 => _116.opt, 'optionalAccess', _117 => _117.skipSolWrappingOperation])) {
const wrapSOLIx = wrapSOLInstruction(
user,
userTokenX,
BigInt(totalXAmount.toString())
);
preInstructions.push(...wrapSOLIx);
}
if (this.tokenY.publicKey.equals(_spltoken.NATIVE_MINT) && !totalYAmount.isZero() && !_optionalChain([this, 'access', _118 => _118.opt, 'optionalAccess', _119 => _119.skipSolWrappingOperation])) {
const wrapSOLIx = wrapSOLInstruction(
user,
userTokenY,
BigInt(totalYAmount.toString())
);
preInstructions.push(...wrapSOLIx);
}
const postInstructions = [];
if ([
this.tokenX.publicKey.toBase58(),
this.tokenY.publicKey.toBase58()
].includes(_spltoken.NATIVE_MINT.toBase58()) && !_optionalChain([this, 'access', _120 => _120.opt, 'optionalAccess', _121 => _121.skipSolWrappingOperation])) {
const closeWrappedSOLIx = await unwrapSOLInstruction(user);
closeWrappedSOLIx && postInstructions.push(closeWrappedSOLIx);
}
const minBinArrayIndex = binIdToBinArrayIndex(new (0, _anchor.BN)(minBinId));
const maxBinArrayIndex = binIdToBinArrayIndex(new (0, _anchor.BN)(maxBinId));
const useExtension = isOverflowDefaultBinArrayBitmap(minBinArrayIndex) || isOverflowDefaultBinArrayBitmap(maxBinArrayIndex);
const binArrayBitmapExtension = useExtension ? deriveBinArrayBitmapExtension(this.pubkey, this.program.programId)[0] : null;
const activeId = this.lbPair.activeId;
const strategyParameters = toStrategyParameters(strategy);
const liquidityParams = {
amountX: totalXAmount,
amountY: totalYAmount,
activeId,
maxActiveBinSlippage,
strategyParameters
};
const addLiquidityAccounts = {
position: positionPubKey,
lbPair: this.pubkey,
userTokenX,
userTokenY,
reserveX: this.lbPair.reserveX,
reserveY: this.lbPair.reserveY,
tokenXMint: this.lbPair.tokenXMint,
tokenYMint: this.lbPair.tokenYMint,
binArrayBitmapExtension,
sender: user,
tokenXProgram: this.tokenX.owner,
tokenYProgram: this.tokenY.owner,
memoProgram: MEMO_PROGRAM_ID
};
const { slices, accounts: transferHookAccounts } = this.getPotentialToken2022IxDataAndAccounts(0 /* Liquidity */);
const programMethod = this.program.methods.addLiquidityByStrategy2(
liquidityParams,
{
slices
}
);
const addLiquidityIx = await programMethod.accountsPartial(addLiquidityAccounts).remainingAccounts(transferHookAccounts).remainingAccounts(binArrayAccountMetas).instruction();
const instructions = [
...preInstructions,
addLiquidityIx,
...postInstructions
];
const setCUIx = await getEstimatedComputeUnitIxWithBuffer(
this.program.provider.connection,
instructions,
user
);
instructions.unshift(setCUIx);
const { blockhash, lastValidBlockHeight } = await this.program.provider.connection.getLatestBlockhash("confirmed");
return new (0, _web3js.Transaction)({
blockhash,
lastValidBlockHeight,
feePayer: user
}).add(...instructions);
}
/**
* @deprecated Use `initializePositionAndAddLiquidityByStrategy` instead which support both token and token2022.
* The function `initializePositionAndAddLiquidityByWeight` function is used to initializes a position and adds liquidity
* @param {TInitializePositionAndAddLiquidityParams}
* - `positionPubKey`: The public key of the position account. (usually use `new Keypair()`)
* - `totalXAmount`: The total amount of token X to be added to the liquidity pool.
* - `totalYAmount`: The total amount of token Y to be added to the liquidity pool.
* - `xYAmountDistribution`: An array of objects of type `XYAmountDistribution` that represents (can use `calculateSpotDistribution`, `calculateBidAskDistribution` & `calculateNormalDistribution`)
* - `user`: The public key of the user account.
* - `slippage`: The slippage percentage to be used for the liquidity pool.
* @returns {Promise<Transaction|Transaction[]>} The function `initializePositionAndAddLiquidityByWeight` returns a `Promise` that
* resolves to either a single `Transaction` object (if less than 26bin involved) or an array of `Transaction` objects.
*/
async initializePositionAndAddLiquidityByWeight({
positionPubKey,
totalXAmount,
totalYAmount,
xYAmountDistribution,
user,
slippage
}) {
const { lowerBinId, upperBinId, binIds } = this.processXYAmountDistribution(xYAmountDistribution);
const maxActiveBinSlippage = slippage ? Math.ceil(slippage / (this.lbPair.binStep / 100)) : MAX_ACTIVE_BIN_SLIPPAGE;
if (upperBinId >= lowerBinId + DEFAULT_BIN_PER_POSITION.toNumber()) {
throw new Error(
`Position must be within a range of 1 to ${DEFAULT_BIN_PER_POSITION.toNumber()} bins.`
);
}
const preInstructions = [];
const initializePositionIx = await this.program.methods.initializePosition(lowerBinId, upperBinId - lowerBinId + 1).accountsPartial({
payer: user,
position: positionPubKey,
lbPair: this.pubkey,
owner: user,
rent: _web3js.SYSVAR_RENT_PUBKEY
}).instruction();
preInstructions.push(initializePositionIx);
const lowerBinArrayIndex = binIdToBinArrayIndex(new (0, _anchor.BN)(lowerBinId));
const [binArrayLower] = deriveBinArray(
this.pubkey,
lowerBinArrayIndex,
this.program.programId
);
const upperBinArrayIndex = _anchor.BN.max(
lowerBinArrayIndex.add(new (0, _anchor.BN)(1)),
binIdToBinArrayIndex(new (0, _anchor.BN)(upperBinId))
);
const [binArrayUpper] = deriveBinArray(
this.pubkey,
upperBinArrayIndex,
this.program.programId
);
const createBinArrayIxs = await this.createBinArraysIfNeeded(
[lowerBinArrayIndex, upperBinArrayIndex],
user
);
preInstructions.push(...createBinArrayIxs);
const [
{ ataPubKey: userTokenX, ix: createPayerTokenXIx },
{ ataPubKey: userTokenY, ix: createPayerTokenYIx }
] = await Promise.all([
getOrCreateATAInstruction(
this.program.provider.connection,
this.tokenX.publicKey,
user,
this.tokenX.owner
),
getOrCreateATAInstruction(
this.program.provider.connection,
this.tokenY.publicKey,
user,
this.tokenY.owner
)
]);
createPayerTokenXIx && preInstructions.push(createPayerTokenXIx);
createPayerTokenYIx && preInstructions.push(createPayerTokenYIx);
if (this.tokenX.publicKey.equals(_spltoken.NATIVE_MINT) && !totalXAmount.isZero() && !_optionalChain([this, 'access', _122 => _122.opt, 'optionalAccess', _123 => _123.skipSolWrappingOperation])) {
const wrapSOLIx = wrapSOLInstruction(
user,
userTokenX,
BigInt(totalXAmount.toString())
);
preInstructions.push(...wrapSOLIx);
}
if (this.tokenY.publicKey.equals(_spltoken.NATIVE_MINT) && !totalYAmount.isZero() && !_optionalChain([this, 'access', _124 => _124.opt, 'optionalAccess', _125 => _125.skipSolWrappingOperation])) {
const wrapSOLIx = wrapSOLInstruction(
user,
userTokenY,
BigInt(totalYAmount.toString())
);
preInstructions.push(...wrapSOLIx);
}
const postInstructions = [];
if ([
this.tokenX.publicKey.toBase58(),
this.tokenY.publicKey.toBase58()
].includes(_spltoken.NATIVE_MINT.toBase58()) && !_optionalChain([this, 'access', _126 => _126.opt, 'optionalAccess', _127 => _127.skipSolWrappingOperation])) {
const closeWrappedSOLIx = await unwrapSOLInstruction(user);
closeWrappedSOLIx && postInstructions.push(closeWrappedSOLIx);
}
const minBinId = Math.min(...binIds);
const maxBinId = Math.max(...binIds);
const minBinArrayIndex = binIdToBinArrayIndex(new (0, _anchor.BN)(minBinId));
const maxBinArrayIndex = binIdToBinArrayIndex(new (0, _anchor.BN)(maxBinId));
const useExtension = isOverflowDefaultBinArrayBitmap(minBinArrayIndex) || isOverflowDefaultBinArrayBitmap(maxBinArrayIndex);
const binArrayBitmapExtension = useExtension ? deriveBinArrayBitmapExtension(this.pubkey, this.program.programId)[0] : null;
const activeId = this.lbPair.activeId;
const binLiquidityDist = toWeightDistribution(
totalXAmount,
totalYAmount,
xYAmountDistribution.map((item) => ({
binId: item.binId,
xAmountBpsOfTotal: item.xAmountBpsOfTotal,
yAmountBpsOfTotal: item.yAmountBpsOfTotal
})),
this.lbPair.binStep
);
if (binLiquidityDist.length === 0) {
throw new Error("No liquidity to add");
}
const liquidityParams = {
amountX: totalXAmount,
amountY: totalYAmount,
binLiquidityDist,
activeId,
maxActiveBinSlippage
};
const addLiquidityAccounts = {
position: positionPubKey,
lbPair: this.pubkey,
userTokenX,
userTokenY,
reserveX: this.lbPair.reserveX,
reserveY: this.lbPair.reserveY,
tokenXMint: this.lbPair.tokenXMint,
tokenYMint: this.lbPair.tokenYMint,
binArrayLower,
binArrayUpper,
binArrayBitmapExtension,
sender: user,
tokenXProgram: _spltoken.TOKEN_PROGRAM_ID,
tokenYProgram: _spltoken.TOKEN_PROGRAM_ID
};
const oneSideLiquidityParams = {
amount: totalXAmount.isZero() ? totalYAmount : totalXAmount,
activeId,
maxActiveBinSlippage,
binLiquidityDist
};
const oneSideAddLiquidityAccounts = {
binArrayLower,
binArrayUpper,
lbPair: this.pubkey,
binArrayBitmapExtension: null,
sender: user,
position: positionPubKey,
reserve: totalXAmount.isZero() ? this.lbPair.reserveY : this.lbPair.reserveX,
tokenMint: totalXAmount.isZero() ? this.lbPair.tokenYMint : this.lbPair.tokenXMint,
tokenProgram: _spltoken.TOKEN_PROGRAM_ID,
userToken: totalXAmount.isZero() ? userTokenY : userTokenX
};
const isOneSideDeposit = totalXAmount.isZero() || totalYAmount.isZero();
const programMethod = isOneSideDeposit ? this.program.methods.addLiquidityOneSide(oneSideLiquidityParams) : this.program.methods.addLiquidityByWeight(liquidityParams);
if (xYAmountDistribution.length < MAX_BIN_LENGTH_ALLOWED_IN_ONE_TX) {
const addLiqIx2 = await programMethod.accountsPartial(
isOneSideDeposit ? oneSideAddLiquidityAccounts : addLiquidityAccounts
).instruction();
const instructions = [...preInstructions, addLiqIx2, ...postInstructions];
const setCUIx2 = await getEstimatedComputeUnitIxWithBuffer(
this.program.provider.connection,
instructions,
user
);
instructions.unshift(setCUIx2);
const { blockhash: blockhash2, lastValidBlockHeight: lastValidBlockHeight2 } = await this.program.provider.connection.getLatestBlockhash("confirmed");
return new (0, _web3js.Transaction)({
blockhash: blockhash2,
lastValidBlockHeight: lastValidBlockHeight2,
feePayer: user
}).add(...instructions);
}
const addLiqIx = await programMethod.accountsPartial(
isOneSideDeposit ? oneSideAddLiquidityAccounts : addLiquidityAccounts
).instruction();
const setCUIx = await getEstimatedComputeUnitIxWithBuffer(
this.program.provider.connection,
[addLiqIx],
user,
DEFAULT_ADD_LIQUIDITY_CU
// The function return multiple transactions that dependent on each other, simulation will fail
);
const mainInstructions = [setCUIx, addLiqIx];
const transactions = [];
const { blockhash, lastValidBlockHeight } = await this.program.provider.connection.getLatestBlockhash("confirmed");
if (preInstructions.length) {
const preInstructionsTx = new (0, _web3js.Transaction)({
blockhash,
lastValidBlockHeight,
feePayer: user
}).add(...preInstructions);
transactions.push(preInstructionsTx);
}
const mainTx = new (0, _web3js.Transaction)({
blockhash,
lastValidBlockHeight,
feePayer: user
}).add(...mainInstructions);
transactions.push(mainTx);
if (postInstructions.length) {
const postInstructionsTx = new (0, _web3js.Transaction)({
blockhash,
lastValidBlockHeight,
feePayer: user
}).add(...postInstructions);
transactions.push(postInstructionsTx);
}
return transactions;
}
/**
* The `addLiquidityByStrategy` function is used to add liquidity to existing position
* @param {TInitializePositionAndAddLiquidityParamsByStrategy}
* - `positionPubKey`: The public key of the position account. (usually use `new Keypair()`)
* - `totalXAmount`: The total amount of token X to be added to the liquidity pool.
* - `totalYAmount`: The total amount of token Y to be added to the liquidity pool.
* - `strategy`: The strategy parameters to be used for the liquidity pool (Can use `calculateStrategyParameter` to calculate).
* - `user`: The public key of the user account.
* - `slippage`: The slippage percentage to be used for the liquidity pool.
* @returns {Promise<Transaction>} The function `addLiquidityByWeight` returns a `Promise` that resolves to either a single
* `Transaction` object
*/
async addLiquidityByStrategy({
positionPubKey,
totalXAmount,
totalYAmount,
strategy,
user,
slippage
}) {
const { maxBinId, minBinId } = strategy;
const maxActiveBinSlippage = slippage ? Math.ceil(slippage / (this.lbPair.binStep / 100)) : MAX_ACTIVE_BIN_SLIPPAGE;
const preInstructions = [];
const minBinArrayIndex = binIdToBinArrayIndex(new (0, _anchor.BN)(minBinId));
const maxBinArrayIndex = binIdToBinArrayIndex(new (0, _anchor.BN)(maxBinId));
const useExtension = isOverflowDefaultBinArrayBitmap(minBinArrayIndex) || isOverflowDefaultBinArrayBitmap(maxBinArrayIndex);
const binArrayBitmapExtension = useExtension ? deriveBinArrayBitmapExtension(this.pubkey, this.program.programId)[0] : null;
const strategyParameters = toStrategyParameters(strategy);
const binArrayIndexes = getBinArrayIndexesCoverage(
new (0, _anchor.BN)(minBinId),
new (0, _anchor.BN)(maxBinId)
);
const binArrayAccountsMeta = getBinArrayAccountMetasCoverage(
new (0, _anchor.BN)(minBinId),
new (0, _anchor.BN)(maxBinId),
this.pubkey,
this.program.programId
);
const createBinArrayIxs = await this.createBinArraysIfNeeded(
binArrayIndexes,
user
);
preInstructions.push(...createBinArrayIxs);
const [
{ ataPubKey: userTokenX, ix: createPayerTokenXIx },
{ ataPubKey: userTokenY, ix: createPayerTokenYIx }
] = await Promise.all([
getOrCreateATAInstruction(
this.program.provider.connection,
this.tokenX.publicKey,
user,
this.tokenX.owner
),
getOrCreateATAInstruction(
this.program.provider.connection,
this.tokenY.publicKey,
user,
this.tokenY.owner
)
]);
createPayerTokenXIx && preInstructions.push(createPayerTokenXIx);
createPayerTokenYIx && preInstructions.push(createPayerTokenYIx);
if (this.tokenX.publicKey.equals(_spltoken.NATIVE_MINT) && !totalXAmount.isZero() && !_optionalChain([this, 'access', _128 => _128.opt, 'optionalAccess', _129 => _129.skipSolWrappingOperation])) {
const wrapSOLIx = wrapSOLInstruction(
user,
userTokenX,
BigInt(totalXAmount.toString())
);
preInstructions.push(...wrapSOLIx);
}
if (this.tokenY.publicKey.equals(_spltoken.NATIVE_MINT) && !totalYAmount.isZero() && !_optionalChain([this, 'access', _130 => _130.opt, 'optionalAccess', _131 => _131.skipSolWrappingOperation])) {
const wrapSOLIx = wrapSOLInstruction(
user,
userTokenY,
BigInt(totalYAmount.toString())
);
preInstructions.push(...wrapSOLIx);
}
const postInstructions = [];
if ([
this.tokenX.publicKey.toBase58(),
this.tokenY.publicKey.toBase58()
].includes(_spltoken.NATIVE_MINT.toBase58()) && !_optionalChain([this, 'access', _132 => _132.opt, 'optionalAccess', _133 => _133.skipSolWrappingOperation])) {
const closeWrappedSOLIx = await unwrapSOLInstruction(user);
closeWrappedSOLIx && postInstructions.push(closeWrappedSOLIx);
}
const liquidityParams = {
amountX: totalXAmount,
amountY: totalYAmount,
activeId: this.lbPair.activeId,
maxActiveBinSlippage,
strategyParameters
};
const addLiquidityAccounts = {
position: positionPubKey,
lbPair: this.pubkey,
userTokenX,
userTokenY,
reserveX: this.lbPair.reserveX,
reserveY: this.lbPair.reserveY,
tokenXMint: this.lbPair.tokenXMint,
tokenYMint: this.lbPair.tokenYMint,
binArrayBitmapExtension,
sender: user,
tokenXProgram: this.tokenX.owner,
tokenYProgram: this.tokenY.owner,
memoProgram: MEMO_PROGRAM_ID
};
const { slices, accounts: transferHookAccounts } = this.getPotentialToken2022IxDataAndAccounts(0 /* Liquidity */);
const programMethod = this.program.methods.addLiquidityByStrategy2(
liquidityParams,
{
slices
}
);
const addLiquidityIx = await programMethod.accounts(addLiquidityAccounts).remainingAccounts(transferHookAccounts).remainingAccounts(binArrayAccountsMeta).instruction();
const instructions = [
...preInstructions,
addLiquidityIx,
...postInstructions
];
const setCUIx = await getEstimatedComputeUnitIxWithBuffer(
this.program.provider.connection,
instructions,
user
);
instructions.unshift(setCUIx);
const { blockhash, lastValidBlockHeight } = await this.program.provider.connection.getLatestBlockhash("confirmed");
return new (0, _web3js.Transaction)({
blockhash,
lastValidBlockHeight,
feePayer: user
}).add(...instructions);
}
/**
* The `addLiquidityByWeight2` function is used to add liquidity to existing position
* @param {TInitializePositionAndAddLiquidityParams}
* - `positionPubKey`: The public key of the position account. (usually use `new Keypair()`)
* - `totalXAmount`: The total amount of token X to be added to the liquidity pool.
* - `totalYAmount`: The total amount of token Y to be added to the liquidity pool.
* - `xYAmountDistribution`: An array of objects of type `XYAmountDistribution` that represents (can use `calculateSpotDistribution`, `calculateBidAskDistribution` & `calculateNormalDistribution`)
* - `user`: The public key of the user account.
* - `slippage`: The slippage percentage to be used for the liquidity pool.
* - `binPerChunk`: The number of bins per chunk when chunking into multiple transactions
* @returns {Promise<Transaction[]>} The function `addLiquidityByWeight2` returns a `Promise` that resolves to transactions
*/
async addLiquidityByWeight2({
positionPubKey,
totalXAmount,
totalYAmount,
xYAmountDistribution,
user,
slippage
}, binPerChunk) {
const maxActiveBinSlippage = slippage ? Math.ceil(slippage / (this.lbPair.binStep / 100)) : MAX_ACTIVE_BIN_SLIPPAGE;
const positionAccount = await this.program.account.positionV2.fetch(positionPubKey);
const { lowerBinId, upperBinId, binIds } = this.processXYAmountDistribution(xYAmountDistribution);
if (lowerBinId < positionAccount.lowerBinId)
throw new Error(
`Lower Bin ID (${lowerBinId}) lower than Position Lower Bin Id (${positionAccount.lowerBinId})`
);
if (upperBinId > positionAccount.upperBinId)
throw new Error(
`Upper Bin ID (${upperBinId}) higher than Position Upper Bin Id (${positionAccount.upperBinId})`
);
const userTokenX = _spltoken.getAssociatedTokenAddressSync.call(void 0,
this.tokenX.mint.address,
user,
true,
this.tokenX.owner
);
const userTokenY = _spltoken.getAssociatedTokenAddressSync.call(void 0,
this.tokenY.mint.address,
user,
true,
this.tokenY.owner
);
const createUserTokenXIx = _spltoken.createAssociatedTokenAccountIdempotentInstruction.call(void 0,
user,
userTokenX,
user,
this.lbPair.tokenXMint,
this.tokenX.owner
);
const createUserTokenYIx = _spltoken.createAssociatedTokenAccountIdempotentInstruction.call(void 0,
user,
userTokenY,
user,
this.lbPair.tokenYMint,
this.tokenY.owner
);
const fromBinId = Math.min(...binIds);
const toBinId = Math.max(...binIds);
const chunkedBinRange = chunkBinRange(fromBinId, toBinId, binPerChunk);
const groupedInstructions = [];
for (const { lowerBinId: lowerBinId2, upperBinId: upperBinId2 } of chunkedBinRange) {
const binArrayAccountsMeta = getBinArrayAccountMetasCoverage(
new (0, _anchor.BN)(lowerBinId2),
new (0, _anchor.BN)(upperBinId2),
this.pubkey,
this.program.programId
);
const lowerBinArrayIndex = binIdToBinArrayIndex(new (0, _anchor.BN)(lowerBinId2));
const upperBinArrayIndex = binIdToBinArrayIndex(new (0, _anchor.BN)(upperBinId2));
const useExtension = isOverflowDefaultBinArrayBitmap(lowerBinArrayIndex) || isOverflowDefaultBinArrayBitmap(upperBinArrayIndex);
const binArrayBitmapExtension = useExtension ? deriveBinArrayBitmapExtension(this.pubkey, this.program.programId)[0] : null;
const { slices, accounts: transferHookAccounts } = this.getPotentialToken2022IxDataAndAccounts(0 /* Liquidity */);
const binCount = upperBinId2 - lowerBinId2 + 1;
const chunkedXYAmountDistribution = xYAmountDistribution.splice(
0,
binCount
);
const chunkedQuoteDistribution = [];
let totalChunkedXAmount = new (0, _anchor.BN)(0);
let totalChunkedYAmount = new (0, _anchor.BN)(0);
let totalYValue = new (0, _anchor.BN)(0);
for (let i = 0; i < chunkedXYAmountDistribution.length; i++) {
const distribution = chunkedXYAmountDistribution[i];
const yAmount = totalYAmount.mul(distribution.yAmountBpsOfTotal).div(new (0, _anchor.BN)(BASIS_POINT_MAX));
const xAmount = totalXAmount.mul(distribution.xAmountBpsOfTotal).div(new (0, _anchor.BN)(BASIS_POINT_MAX));
const binPrice = getQPriceFromId(
new (0, _anchor.BN)(distribution.binId),
new (0, _anchor.BN)(this.lbPair.binStep)
);
const yValueOfX = totalXAmount.mul(distribution.xAmountBpsOfTotal).mul(binPrice).shrn(SCALE_OFFSET).div(new (0, _anchor.BN)(BASIS_POINT_MAX));
totalChunkedXAmount = totalChunkedXAmount.add(xAmount);
totalChunkedYAmount = totalChunkedYAmount.add(yAmount);
totalYValue = totalYValue.add(yAmount.add(yValueOfX));
chunkedQuoteDistribution.push({
binId: distribution.binId,
yValue: yValueOfX.add(yAmount)
});
}
const chunkedBinLiquidityDistribution = chunkedQuoteDistribution.map(
({ binId, yValue }) => {
const weight = yValue.mul(new (0, _anchor.BN)(65535)).div(totalYValue);
return {
binId,
weight: weight.toNumber()
};
}
);
const preInstructions = [
createUserTokenXIx,
createUserTokenYIx
];
const postInstructions = [];
const createBinArrayIxs = await this.createBinArraysIfNeeded(
[lowerBinArrayIndex, upperBinArrayIndex],
user
);
preInstructions.push(...createBinArrayIxs);
if (this.tokenX.publicKey.equals(_spltoken.NATIVE_MINT) && !totalChunkedXAmount.isZero() && !_optionalChain([this, 'access', _134 => _134.opt, 'optionalAccess', _135 => _135.skipSolWrappingOperation])) {
const wrapSOLIx = wrapSOLInstruction(
user,
userTokenX,
BigInt(totalChunkedXAmount.toString())
);
preInstructions.push(...wrapSOLIx);
const closeWrappedSOLIx = await unwrapSOLInstruction(user);
closeWrappedSOLIx && postInstructions.push(closeWrappedSOLIx);
}
if (this.tokenY.publicKey.equals(_spltoken.NATIVE_MINT) && !totalChunkedYAmount.isZero() && !_optionalChain([this, 'access', _136 => _136.opt, 'optionalAccess', _137 => _137.skipSolWrappingOperation])) {
const wrapSOLIx = wrapSOLInstruction(
user,
userTokenY,
BigInt(totalChunkedYAmount.toString())
);
preInstructions.push(...wrapSOLIx);
const closeWrappedSOLIx = await unwrapSOLInstruction(user);
closeWrappedSOLIx && postInstructions.push(closeWrappedSOLIx);
}
const addLiqIx = await this.program.methods.addLiquidityByWeight2(
{
amountX: totalChunkedXAmount,
amountY: totalChunkedYAmount,
activeId: this.lbPair.activeId,
maxActiveBinSlippage,
binLiquidityDist: chunkedBinLiquidityDistribution
},
{
slices
}
).accountsPartial({
position: positionPubKey,
lbPair: this.pubkey,
userTokenX,
userTokenY,
reserveX: this.lbPair.reserveX,
reserveY: this.lbPair.reserveY,
tokenXMint: this.lbPair.tokenXMint,
tokenYMint: this.lbPair.tokenYMint,
sender: user,
tokenXProgram: this.tokenX.owner,
tokenYProgram: this.tokenY.owner,
binArrayBitmapExtension
}).remainingAccounts([...transferHookAccounts, ...binArrayAccountsMeta]).instruction();
const instruction = [...preInstructions, addLiqIx, ...postInstructions];
groupedInstructions.push(instruction);
}
const groupedInstructionsWithCUIx = await Promise.all(
groupedInstructions.map(async (ixs) => {
const setCUIx = await getEstimatedComputeUnitIxWithBuffer(
this.program.provider.connection,
ixs,
user,
0.3
// Extra 30% buffer CU
);
return [setCUIx, ...ixs];
})
);
const { blockhash, lastValidBlockHeight } = await this.program.provider.connection.getLatestBlockhash("confirmed");
return groupedInstructionsWithCUIx.map((ixs) => {
return new (0, _web3js.Transaction)({
blockhash,
lastValidBlockHeight,
feePayer: user
}).add(...ixs);
});
}
/**
* @deprecated Use `addLiquidityByStrategy` instead which support both token and token2022.
* The `addLiquidityByWeight` function is used to add liquidity to existing position
* @param {TInitializePositionAndAddLiquidityParams}
* - `positionPubKey`: The public key of the position account. (usually use `new Keypair()`)
* - `totalXAmount`: The total amount of token X to be added to the liquidity pool.
* - `totalYAmount`: The total amount of token Y to be added to the liquidity pool.
* - `xYAmountDistribution`: An array of objects of type `XYAmountDistribution` that represents (can use `calculateSpotDistribution`, `calculateBidAskDistribution` & `calculateNormalDistribution`)
* - `user`: The public key of the user account.
* - `slippage`: The slippage percentage to be used for the liquidity pool.
* @returns {Promise<Transaction|Transaction[]>} The function `addLiquidityByWeight` returns a `Promise` that resolves to either a single
* `Transaction` object (if less than 26bin involved) or an array of `Transaction` objects.
*/
async addLiquidityByWeight({
positionPubKey,
totalXAmount,
totalYAmount,
xYAmountDistribution,
user,
slippage
}) {
const maxActiveBinSlippage = slippage ? Math.ceil(slippage / (this.lbPair.binStep / 100)) : MAX_ACTIVE_BIN_SLIPPAGE;
const positionAccount = await this.program.account.positionV2.fetch(positionPubKey);
const { lowerBinId, upperBinId, binIds } = this.processXYAmountDistribution(xYAmountDistribution);
if (lowerBinId < positionAccount.lowerBinId)
throw new Error(
`Lower Bin ID (${lowerBinId}) lower than Position Lower Bin Id (${positionAccount.lowerBinId})`
);
if (upperBinId > positionAccount.upperBinId)
throw new Error(
`Upper Bin ID (${upperBinId}) higher than Position Upper Bin Id (${positionAccount.upperBinId})`
);
const minBinId = Math.min(...binIds);
const maxBinId = Math.max(...binIds);
const minBinArrayIndex = binIdToBinArrayIndex(new (0, _anchor.BN)(minBinId));
const maxBinArrayIndex = binIdToBinArrayIndex(new (0, _anchor.BN)(maxBinId));
const useExtension = isOverflowDefaultBinArrayBitmap(minBinArrayIndex) || isOverflowDefaultBinArrayBitmap(maxBinArrayIndex);
const binArrayBitmapExtension = useExtension ? deriveBinArrayBitmapExtension(this.pubkey, this.program.programId)[0] : null;
const activeId = this.lbPair.activeId;
const binLiquidityDist = toWeightDistribution(
totalXAmount,
totalYAmount,
xYAmountDistribution.map((item) => ({
binId: item.binId,
xAmountBpsOfTotal: item.xAmountBpsOfTotal,
yAmountBpsOfTotal: item.yAmountBpsOfTotal
})),
this.lbPair.binStep
);
if (binLiquidityDist.length === 0) {
throw new Error("No liquidity to add");
}
const lowerBinArrayIndex = binIdToBinArrayIndex(
new (0, _anchor.BN)(positionAccount.lowerBinId)
);
const [binArrayLower] = deriveBinArray(
this.pubkey,
lowerBinArrayIndex,
this.program.programId
);
const upperBinArrayIndex = _anchor.BN.max(
lowerBinArrayIndex.add(new (0, _anchor.BN)(1)),
binIdToBinArrayIndex(new (0, _anchor.BN)(positionAccount.upperBinId))
);
const [binArrayUpper] = deriveBinArray(
this.pubkey,
upperBinArrayIndex,
this.program.programId
);
const preInstructions = [];
const createBinArrayIxs = await this.createBinArraysIfNeeded(
[lowerBinArrayIndex, upperBinArrayIndex],
user
);
preInstructions.push(...createBinArrayIxs);
const [
{ ataPubKey: userTokenX, ix: createPayerTokenXIx },
{ ataPubKey: userTokenY, ix: createPayerTokenYIx }
] = await Promise.all([
getOrCreateATAInstruction(
this.program.provider.connection,
this.tokenX.publicKey,
user,
this.tokenX.owner
),
getOrCreateATAInstruction(
this.program.provider.connection,
this.tokenY.publicKey,
user,
this.tokenY.owner
)
]);
createPayerTokenXIx && preInstructions.push(createPayerTokenXIx);
createPayerTokenYIx && preInstructions.push(createPayerTokenYIx);
if (this.tokenX.publicKey.equals(_spltoken.NATIVE_MINT) && !totalXAmount.isZero() && !_optionalChain([this, 'access', _138 => _138.opt, 'optionalAccess', _139 => _139.skipSolWrappingOperation])) {
const wrapSOLIx = wrapSOLInstruction(
user,
userTokenX,
BigInt(totalXAmount.toString())
);
preInstructions.push(...wrapSOLIx);
}
if (this.tokenY.publicKey.equals(_spltoken.NATIVE_MINT) && !totalYAmount.isZero() && !_optionalChain([this, 'access', _140 => _140.opt, 'optionalAccess', _141 => _141.skipSolWrappingOperation])) {
const wrapSOLIx = wrapSOLInstruction(
user,
userTokenY,
BigInt(totalYAmount.toString())
);
preInstructions.push(...wrapSOLIx);
}
const postInstructions = [];
if ([
this.tokenX.publicKey.toBase58(),
this.tokenY.publicKey.toBase58()
].includes(_spltoken.NATIVE_MINT.toBase58()) && !_optionalChain([this, 'access', _142 => _142.opt, 'optionalAccess', _143 => _143.skipSolWrappingOperation])) {
const closeWrappedSOLIx = await unwrapSOLInstruction(user);
closeWrappedSOLIx && postInstructions.push(closeWrappedSOLIx);
}
const liquidityParams = {
amountX: totalXAmount,
amountY: totalYAmount,
binLiquidityDist,
activeId,
maxActiveBinSlippage
};
const addLiquidityAccounts = {
position: positionPubKey,
lbPair: this.pubkey,
userTokenX,
userTokenY,
reserveX: this.lbPair.reserveX,
reserveY: this.lbPair.reserveY,
tokenXMint: this.lbPair.tokenXMint,
tokenYMint: this.lbPair.tokenYMint,
binArrayLower,
binArrayUpper,
binArrayBitmapExtension,
sender: user,
tokenXProgram: _spltoken.TOKEN_PROGRAM_ID,
tokenYProgram: _spltoken.TOKEN_PROGRAM_ID
};
const oneSideLiquidityParams = {
amount: totalXAmount.isZero() ? totalYAmount : totalXAmount,
activeId,
maxActiveBinSlippage,
binLiquidityDist
};
const oneSideAddLiquidityAccounts = {
binArrayLower,
binArrayUpper,
lbPair: this.pubkey,
binArrayBitmapExtension: null,
sender: user,
position: positionPubKey,
reserve: totalXAmount.isZero() ? this.lbPair.reserveY : this.lbPair.reserveX,
tokenMint: totalXAmount.isZero() ? this.lbPair.tokenYMint : this.lbPair.tokenXMint,
tokenProgram: _spltoken.TOKEN_PROGRAM_ID,
userToken: totalXAmount.isZero() ? userTokenY : userTokenX
};
const isOneSideDeposit = totalXAmount.isZero() || totalYAmount.isZero();
const programMethod = isOneSideDeposit ? this.program.methods.addLiquidityOneSide(oneSideLiquidityParams) : this.program.methods.addLiquidityByWeight(liquidityParams);
if (xYAmountDistribution.length < MAX_BIN_LENGTH_ALLOWED_IN_ONE_TX) {
const addLiqIx2 = await programMethod.accountsPartial(
isOneSideDeposit ? oneSideAddLiquidityAccounts : addLiquidityAccounts
).instruction();
const instructions = [...preInstructions, addLiqIx2, ...postInstructions];
const setCUIx2 = await getEstimatedComputeUnitIxWithBuffer(
this.program.provider.connection,
instructions,
user
);
instructions.unshift(setCUIx2);
const { blockhash: blockhash2, lastValidBlockHeight: lastValidBlockHeight2 } = await this.program.provider.connection.getLatestBlockhash("confirmed");
return new (0, _web3js.Transaction)({
blockhash: blockhash2,
lastValidBlockHeight: lastValidBlockHeight2,
feePayer: user
}).add(...instructions);
}
const addLiqIx = await programMethod.accountsPartial(
isOneSideDeposit ? oneSideAddLiquidityAccounts : addLiquidityAccounts
).instruction();
const setCUIx = await getEstimatedComputeUnitIxWithBuffer(
this.program.provider.connection,
[addLiqIx],
user
);
const mainInstructions = [setCUIx, addLiqIx];
const transactions = [];
const { blockhash, lastValidBlockHeight } = await this.program.provider.connection.getLatestBlockhash("confirmed");
if (preInstructions.length) {
const preInstructionsTx = new (0, _web3js.Transaction)({
blockhash,
lastValidBlockHeight,
feePayer: user
}).add(...preInstructions);
transactions.push(preInstructionsTx);
}
const mainTx = new (0, _web3js.Transaction)({
blockhash,
lastValidBlockHeight,
feePayer: user
}).add(...mainInstructions);
transactions.push(mainTx);
if (postInstructions.length) {
const postInstructionsTx = new (0, _web3js.Transaction)({
blockhash,
lastValidBlockHeight,
feePayer: user
}).add(...postInstructions);
transactions.push(postInstructionsTx);
}
return transactions;
}
/**
* The `removeLiquidity` function is used to remove liquidity from a position,
* with the option to claim rewards and close the position.
* @param
* - `user`: The public key of the user account.
* - `position`: The public key of the position account.
* - `fromBinId`: The ID of the starting bin to remove liquidity from. Must within position range.
* - `toBinId`: The ID of the ending bin to remove liquidity from. Must within position range.
* - `liquiditiesBpsToRemove`: An array of numbers (percentage) that represent the liquidity to remove from each bin.
* - `shouldClaimAndClose`: A boolean flag that indicates whether to claim rewards and close the position.
* - `skipUnwrapSOL`: A boolean flag that indicates whether to skip unwrapping SOL. Enable this when using zap-sdk to ensure accuracy in SOL zap out amount when SOL is in token
* @returns {Promise<Transaction[]>}
*/
async removeLiquidity({
user,
position,
fromBinId,
toBinId,
bps,
shouldClaimAndClose = false,
skipUnwrapSOL = false
}) {
const positionAccount = await this.program.provider.connection.getAccountInfo(position);
const positionState = wrapPosition(this.program, position, positionAccount);
const lbPair = positionState.lbPair();
const owner = positionState.owner();
const feeOwner = positionState.feeOwner();
const liquidityShares = positionState.liquidityShares();
const feeInfos = positionState.feeInfos();
const rewardInfos = positionState.rewardInfos();
const binDataWithBinId = liquidityShares.map((share, i) => {
const feeInfo = feeInfos[i];
const rewardInfo = rewardInfos[i];
const hasFees = feeInfo && (!feeInfo.feeXPending.isZero() || !feeInfo.feeYPending.isZero());
const hasRewards = rewardInfo && rewardInfo.rewardPendings.some((pending) => !pending.isZero());
return {
share,
binId: positionState.lowerBinId().add(new (0, _anchor.BN)(i)),
hasFeesOrRewards: hasFees || hasRewards
};
});
const binIdsWithLiquidity = binDataWithBinId.filter((bin) => {
return !bin.share.isZero();
});
const binIdsWithLiquidityOrFees = binDataWithBinId.filter((bin) => {
return !bin.share.isZero() || bin.hasFeesOrRewards;
});
const hasLiquidity = binIdsWithLiquidity.length > 0;
if (!hasLiquidity && !shouldClaimAndClose) {
throw new Error("No liquidity to remove");
}
const activeBins = shouldClaimAndClose ? binIdsWithLiquidityOrFees : binIdsWithLiquidity;
const lowerActiveBinId = activeBins[0].binId.toNumber();
const upperActiveBinId = activeBins[activeBins.length - 1].binId.toNumber();
if (fromBinId < lowerActiveBinId) {
fromBinId = lowerActiveBinId;
}
if (toBinId > upperActiveBinId) {
toBinId = upperActiveBinId;
}
const walletToReceiveFee = feeOwner.equals(_web3js.PublicKey.default) ? user : feeOwner;
const userTokenX = _spltoken.getAssociatedTokenAddressSync.call(void 0,
this.lbPair.tokenXMint,
owner,
true,
this.tokenX.owner
);
const userTokenY = _spltoken.getAssociatedTokenAddressSync.call(void 0,
this.lbPair.tokenYMint,
owner,
true,
this.tokenY.owner
);
const feeOwnerTokenX = _spltoken.getAssociatedTokenAddressSync.call(void 0,
this.lbPair.tokenXMint,
walletToReceiveFee,
true,
this.tokenX.owner
);
const feeOwnerTokenY = _spltoken.getAssociatedTokenAddressSync.call(void 0,
this.lbPair.tokenYMint,
walletToReceiveFee,
true,
this.tokenY.owner
);
const createUserTokenXIx = _spltoken.createAssociatedTokenAccountIdempotentInstruction.call(void 0,
user,
userTokenX,
owner,
this.lbPair.tokenXMint,
this.tokenX.owner
);
const createUserTokenYIx = _spltoken.createAssociatedTokenAccountIdempotentInstruction.call(void 0,
user,
userTokenY,
owner,
this.lbPair.tokenYMint,
this.tokenY.owner
);
const createFeeOwnerTokenXIx = _spltoken.createAssociatedTokenAccountIdempotentInstruction.call(void 0,
user,
feeOwnerTokenX,
walletToReceiveFee,
this.lbPair.tokenXMint,
this.tokenX.owner
);
const createFeeOwnerTokenYIx = _spltoken.createAssociatedTokenAccountIdempotentInstruction.call(void 0,
user,
feeOwnerTokenY,
walletToReceiveFee,
this.lbPair.tokenYMint,
this.tokenY.owner
);
const chunkedBinRange = chunkBinRange(fromBinId, toBinId);
const groupedInstructions = [];
for (const { lowerBinId, upperBinId } of chunkedBinRange) {
const binArrayAccountsMeta = getBinArrayAccountMetasCoverage(
new (0, _anchor.BN)(lowerBinId),
new (0, _anchor.BN)(upperBinId),
this.pubkey,
this.program.programId
);
const { slices, accounts: transferHookAccounts } = this.getPotentialToken2022IxDataAndAccounts(0 /* Liquidity */);
const preInstructions = [];
const postInstructions = [];
if (shouldClaimAndClose) {
const claimSwapFeeIx = await this.program.methods.claimFee2(lowerBinId, upperBinId, {
slices
}).accountsPartial({
lbPair: this.pubkey,
sender: user,
position,
reserveX: this.lbPair.reserveX,
reserveY: this.lbPair.reserveY,
tokenXMint: this.tokenX.publicKey,
tokenYMint: this.tokenY.publicKey,
userTokenX: feeOwnerTokenX,
userTokenY: feeOwnerTokenY,
tokenProgramX: this.tokenX.owner,
tokenProgramY: this.tokenY.owner,
memoProgram: MEMO_PROGRAM_ID
}).remainingAccounts(transferHookAccounts).remainingAccounts(binArrayAccountsMeta).instruction();
preInstructions.push(createFeeOwnerTokenXIx);
preInstructions.push(createFeeOwnerTokenYIx);
postInstructions.push(claimSwapFeeIx);
for (let i = 0; i < 2; i++) {
const rewardInfo = this.lbPair.rewardInfos[i];
if (!rewardInfo || rewardInfo.mint.equals(_web3js.PublicKey.default))
continue;
const userRewardAccount = _spltoken.getAssociatedTokenAddressSync.call(void 0,
rewardInfo.mint,
user,
true,
this.rewards[i].owner
);
const createUserRewardAccountIx = _spltoken.createAssociatedTokenAccountIdempotentInstruction.call(void 0,
user,
userRewardAccount,
user,
rewardInfo.mint,
this.rewards[i].owner
);
preInstructions.push(createUserRewardAccountIx);
const { slices: slices2, accounts: transferHookAccounts2 } = this.getPotentialToken2022IxDataAndAccounts(1 /* Reward */, i);
const claimRewardIx = await this.program.methods.claimReward2(new (0, _anchor.BN)(i), lowerBinId, upperBinId, {
slices: slices2
}).accountsPartial({
lbPair: this.pubkey,
sender: user,
position,
rewardVault: rewardInfo.vault,
rewardMint: rewardInfo.mint,
tokenProgram: this.rewards[i].owner,
userTokenAccount: userRewardAccount,
memoProgram: MEMO_PROGRAM_ID
}).remainingAccounts(transferHookAccounts2).remainingAccounts(binArrayAccountsMeta).instruction();
postInstructions.push(claimRewardIx);
}
const closePositionIx = await this.program.methods.closePositionIfEmpty().accountsPartial({
rentReceiver: owner,
// Must be position owner
position,
sender: user
}).instruction();
postInstructions.push(closePositionIx);
}
if ([
this.tokenX.publicKey.toBase58(),
this.tokenY.publicKey.toBase58()
].includes(_spltoken.NATIVE_MINT.toBase58()) && (!skipUnwrapSOL || !_optionalChain([this, 'access', _144 => _144.opt, 'optionalAccess', _145 => _145.skipSolWrappingOperation]))) {
const closeWrappedSOLIx = await unwrapSOLInstruction(user);
closeWrappedSOLIx && postInstructions.push(closeWrappedSOLIx);
}
preInstructions.push(createUserTokenXIx);
preInstructions.push(createUserTokenYIx);
const binArrayBitmapExtension = this.binArrayBitmapExtension ? this.binArrayBitmapExtension.publicKey : this.program.programId;
const instructions = [...preInstructions];
if (hasLiquidity) {
const removeLiquidityTx = await this.program.methods.removeLiquidityByRange2(lowerBinId, upperBinId, bps.toNumber(), {
slices
}).accountsPartial({
position,
lbPair,
userTokenX,
userTokenY,
reserveX: this.lbPair.reserveX,
reserveY: this.lbPair.reserveY,
tokenXMint: this.tokenX.publicKey,
tokenYMint: this.tokenY.publicKey,
binArrayBitmapExtension,
tokenXProgram: this.tokenX.owner,
tokenYProgram: this.tokenY.owner,
sender: user,
memoProgram: MEMO_PROGRAM_ID
}).remainingAccounts(transferHookAccounts).remainingAccounts(binArrayAccountsMeta).instruction();
instructions.push(removeLiquidityTx);
}
instructions.push(...postInstructions);
groupedInstructions.push(instructions);
}
const groupedInstructionsWithCUIx = await Promise.all(
groupedInstructions.map(async (ixs) => {
const setCUIx = await getEstimatedComputeUnitIxWithBuffer(
this.program.provider.connection,
ixs,
user,
0.3
// Extra 30% buffer CU
);
return [setCUIx, ...ixs];
})
);
const { blockhash, lastValidBlockHeight } = await this.program.provider.connection.getLatestBlockhash("confirmed");
return groupedInstructionsWithCUIx.map((ixs) => {
return new (0, _web3js.Transaction)({
blockhash,
lastValidBlockHeight,
feePayer: user
}).add(...ixs);
});
}
/**
* The `closePositionIfEmpty` function closes a position if it is empty. Else, it does nothing.
*/
async closePositionIfEmpty({
owner,
position
}) {
const closePositionIfEmptyIx = await this.program.methods.closePositionIfEmpty().accountsPartial({
rentReceiver: owner,
position: position.publicKey,
sender: owner
}).instruction();
const setCUIx = await getEstimatedComputeUnitIxWithBuffer(
this.program.provider.connection,
[closePositionIfEmptyIx],
owner
);
const { blockhash, lastValidBlockHeight } = await this.program.provider.connection.getLatestBlockhash("confirmed");
return new (0, _web3js.Transaction)({
blockhash,
lastValidBlockHeight,
feePayer: owner
}).add(setCUIx, closePositionIfEmptyIx);
}
/**
* The `closePosition` function closes a position
* @param
* - `owner`: The public key of the owner of the position.
* - `position`: The public key of the position account.
* @returns {Promise<Transaction>}
*/
async closePosition({
owner,
position
}) {
const closePositionIx = await this.program.methods.closePosition2().accountsPartial({
rentReceiver: owner,
position: position.publicKey,
sender: owner
}).instruction();
const setCUIx = await getEstimatedComputeUnitIxWithBuffer(
this.program.provider.connection,
[closePositionIx],
owner
);
const { blockhash, lastValidBlockHeight } = await this.program.provider.connection.getLatestBlockhash("confirmed");
return new (0, _web3js.Transaction)({
blockhash,
lastValidBlockHeight,
feePayer: owner
}).add(setCUIx, closePositionIx);
}
/**
* The `swapQuoteExactOut` function returns a quote for a swap
* @param
* - `outAmount`: Amount of lamport to swap out
* - `swapForY`: Swap token X to Y when it is true, else reversed.
* - `allowedSlippage`: Allowed slippage for the swap. Expressed in BPS. To convert from slippage percentage to BPS unit: SLIPPAGE_PERCENTAGE * 100
* - `maxExtraBinArrays`: Maximum number of extra binArrays to return
* @returns {SwapQuote}
* - `inAmount`: Amount of lamport to swap in
* - `outAmount`: Amount of lamport to swap out
* - `fee`: Fee amount
* - `protocolFee`: Protocol fee amount
* - `maxInAmount`: Maximum amount of lamport to swap in
* - `binArraysPubkey`: Array of bin arrays involved in the swap
* @throws {DlmmSdkError}
*
*/
swapQuoteExactOut(outAmount, swapForY, allowedSlippage, binArrays, maxExtraBinArrays = 0) {
const currentTimestamp = Date.now() / 1e3;
const [inMint, outMint] = swapForY ? [this.tokenX.mint, this.tokenY.mint] : [this.tokenY.mint, this.tokenX.mint];
let outAmountLeft = calculateTransferFeeIncludedAmount(
outAmount,
outMint,
this.clock.epoch.toNumber()
).amount;
if (maxExtraBinArrays < 0 || maxExtraBinArrays > MAX_EXTRA_BIN_ARRAYS) {
throw new DlmmSdkError(
"INVALID_MAX_EXTRA_BIN_ARRAYS",
`maxExtraBinArrays must be a value between 0 and ${MAX_EXTRA_BIN_ARRAYS}`
);
}
let vParameterClone = Object.assign({}, this.lbPair.vParameters);
let activeId = new (0, _anchor.BN)(this.lbPair.activeId);
const binStep = this.lbPair.binStep;
const sParameters3 = this.lbPair.parameters;
const supportLimitOrder = isSupportLimitOrder(this.lbPair);
const feeOnInput = getFeeMode(this.lbPair, swapForY).feeOnInput;
DLMM.updateReference(
activeId.toNumber(),
vParameterClone,
sParameters3,
currentTimestamp
);
let startBinId = activeId;
let binArraysForSwap = /* @__PURE__ */ new Map();
let actualInAmount = new (0, _anchor.BN)(0);
let feeAmount = new (0, _anchor.BN)(0);
let protocolFeeAmount = new (0, _anchor.BN)(0);
while (!outAmountLeft.isZero()) {
let binArrayAccountToSwap = findNextBinArrayWithLiquidity(
swapForY,
activeId,
this.lbPair,
_nullishCoalesce(_optionalChain([this, 'access', _146 => _146.binArrayBitmapExtension, 'optionalAccess', _147 => _147.account]), () => ( null)),
binArrays
);
if (binArrayAccountToSwap == null) {
throw new DlmmSdkError(
"SWAP_QUOTE_INSUFFICIENT_LIQUIDITY",
"Insufficient liquidity in binArrays"
);
}
binArraysForSwap.set(binArrayAccountToSwap.publicKey, true);
if (isBinIdWithinBinArray(activeId, binArrayAccountToSwap.account.index)) {
const bin = getBinFromBinArray(
activeId.toNumber(),
binArrayAccountToSwap.account
);
const maxOutAmount = getBinMaxAmountOut(
bin,
swapForY,
supportLimitOrder
);
if (!maxOutAmount.isZero()) {
DLMM.updateVolatilityAccumulator(
vParameterClone,
sParameters3,
activeId.toNumber()
);
const { amountIn, amountOut, fee, protocolFee } = swapExactOutQuoteAtBin(
bin,
binStep,
sParameters3,
vParameterClone,
outAmountLeft,
swapForY,
supportLimitOrder,
feeOnInput
);
if (!amountOut.isZero()) {
outAmountLeft = outAmountLeft.sub(amountOut);
actualInAmount = actualInAmount.add(amountIn);
feeAmount = feeAmount.add(fee);
protocolFeeAmount = protocolFeeAmount.add(protocolFee);
}
}
}
if (!outAmountLeft.isZero()) {
if (swapForY) {
activeId = activeId.sub(new (0, _anchor.BN)(1));
} else {
activeId = activeId.add(new (0, _anchor.BN)(1));
}
}
}
const startPrice = getPriceOfBinByBinId(
startBinId.toNumber(),
this.lbPair.binStep
);
const endPrice = getPriceOfBinByBinId(
activeId.toNumber(),
this.lbPair.binStep
);
const priceImpact = startPrice.sub(endPrice).abs().div(startPrice).mul(new (0, _decimaljs2.default)(100));
actualInAmount = calculateTransferFeeIncludedAmount(
actualInAmount,
inMint,
this.clock.epoch.toNumber()
).amount;
const maxInAmount = actualInAmount.mul(new (0, _anchor.BN)(BASIS_POINT_MAX).add(allowedSlippage)).div(new (0, _anchor.BN)(BASIS_POINT_MAX));
if (maxExtraBinArrays > 0 && maxExtraBinArrays <= MAX_EXTRA_BIN_ARRAYS) {
const extraBinArrays = new Array();
while (extraBinArrays.length < maxExtraBinArrays) {
let binArrayAccountToSwap = findNextBinArrayWithLiquidity(
swapForY,
activeId,
this.lbPair,
_nullishCoalesce(_optionalChain([this, 'access', _148 => _148.binArrayBitmapExtension, 'optionalAccess', _149 => _149.account]), () => ( null)),
binArrays
);
if (binArrayAccountToSwap == null) {
break;
}
const binArrayAccountToSwapExisted = binArraysForSwap.has(
binArrayAccountToSwap.publicKey
);
if (binArrayAccountToSwapExisted) {
if (swapForY) {
activeId = activeId.sub(new (0, _anchor.BN)(1));
} else {
activeId = activeId.add(new (0, _anchor.BN)(1));
}
} else {
extraBinArrays.push(binArrayAccountToSwap.publicKey);
const [lowerBinId, upperBinId] = getBinArrayLowerUpperBinId(
binArrayAccountToSwap.account.index
);
if (swapForY) {
activeId = lowerBinId.sub(new (0, _anchor.BN)(1));
} else {
activeId = upperBinId.add(new (0, _anchor.BN)(1));
}
}
}
extraBinArrays.forEach((binArrayPubkey) => {
binArraysForSwap.set(binArrayPubkey, true);
});
}
const binArraysPubkey = Array.from(binArraysForSwap.keys());
return {
inAmount: actualInAmount,
maxInAmount,
outAmount,
priceImpact,
fee: feeAmount,
protocolFee: protocolFeeAmount,
binArraysPubkey
};
}
/**
* The `swapQuote` function returns a quote for a swap
* @param
* - `inAmount`: Amount of lamport to swap in
* - `swapForY`: Swap token X to Y when it is true, else reversed.
* - `allowedSlippage`: Allowed slippage for the swap. Expressed in BPS. To convert from slippage percentage to BPS unit: SLIPPAGE_PERCENTAGE * 100
* - `binArrays`: binArrays for swapQuote.
* - `isPartialFill`: Flag to check whether the the swapQuote is partial fill, default = false.
* - `maxExtraBinArrays`: Maximum number of extra binArrays to return
* @returns {SwapQuote}
* - `consumedInAmount`: Amount of lamport to swap in
* - `outAmount`: Amount of lamport to swap out
* - `fee`: Fee amount
* - `protocolFee`: Protocol fee amount
* - `minOutAmount`: Minimum amount of lamport to swap out
* - `priceImpact`: Price impact of the swap
* - `binArraysPubkey`: Array of bin arrays involved in the swap
* @throws {DlmmSdkError}
*/
swapQuote(inAmount, swapForY, allowedSlippage, binArrays, isPartialFill, maxExtraBinArrays = 0) {
const currentTimestamp = Date.now() / 1e3;
if (maxExtraBinArrays < 0 || maxExtraBinArrays > MAX_EXTRA_BIN_ARRAYS) {
throw new DlmmSdkError(
"INVALID_MAX_EXTRA_BIN_ARRAYS",
`maxExtraBinArrays must be a value between 0 and ${MAX_EXTRA_BIN_ARRAYS}`
);
}
const [inMint, outMint] = swapForY ? [this.tokenX.mint, this.tokenY.mint] : [this.tokenY.mint, this.tokenX.mint];
let transferFeeExcludedAmountIn = calculateTransferFeeExcludedAmount(
inAmount,
inMint,
this.clock.epoch.toNumber()
).amount;
let inAmountLeft = transferFeeExcludedAmountIn;
let vParameterClone = Object.assign({}, this.lbPair.vParameters);
let activeId = new (0, _anchor.BN)(this.lbPair.activeId);
const binStep = this.lbPair.binStep;
const sParameters3 = this.lbPair.parameters;
const supportLimitOrder = isSupportLimitOrder(this.lbPair);
const feeOnInput = getFeeMode(this.lbPair, swapForY).feeOnInput;
DLMM.updateReference(
activeId.toNumber(),
vParameterClone,
sParameters3,
currentTimestamp
);
let startBin = null;
let binArraysForSwap = /* @__PURE__ */ new Map();
let totalOutAmount = new (0, _anchor.BN)(0);
let feeAmount = new (0, _anchor.BN)(0);
let protocolFeeAmount = new (0, _anchor.BN)(0);
let lastFilledActiveBinId = activeId;
while (!inAmountLeft.isZero()) {
let binArrayAccountToSwap = findNextBinArrayWithLiquidity(
swapForY,
activeId,
this.lbPair,
_nullishCoalesce(_optionalChain([this, 'access', _150 => _150.binArrayBitmapExtension, 'optionalAccess', _151 => _151.account]), () => ( null)),
binArrays
);
if (binArrayAccountToSwap == null) {
if (isPartialFill) {
break;
} else {
throw new DlmmSdkError(
"SWAP_QUOTE_INSUFFICIENT_LIQUIDITY",
"Insufficient liquidity in binArrays for swapQuote"
);
}
}
binArraysForSwap.set(binArrayAccountToSwap.publicKey, true);
if (isBinIdWithinBinArray(activeId, binArrayAccountToSwap.account.index)) {
const bin = getBinFromBinArray(
activeId.toNumber(),
binArrayAccountToSwap.account
);
const maxAmountOut = getBinMaxAmountOut(
bin,
swapForY,
supportLimitOrder
);
if (!maxAmountOut.isZero()) {
DLMM.updateVolatilityAccumulator(
vParameterClone,
sParameters3,
activeId.toNumber()
);
const { amountIn, amountOut, fee, protocolFee } = swapExactInQuoteAtBin(
bin,
binStep,
sParameters3,
vParameterClone,
inAmountLeft,
swapForY,
supportLimitOrder,
feeOnInput
);
if (!amountIn.isZero()) {
inAmountLeft = inAmountLeft.sub(amountIn);
totalOutAmount = totalOutAmount.add(amountOut);
feeAmount = feeAmount.add(fee);
protocolFeeAmount = protocolFeeAmount.add(protocolFee);
if (!startBin) {
startBin = bin;
}
lastFilledActiveBinId = activeId;
}
}
}
if (!inAmountLeft.isZero()) {
if (swapForY) {
activeId = activeId.sub(new (0, _anchor.BN)(1));
} else {
activeId = activeId.add(new (0, _anchor.BN)(1));
}
}
}
if (!startBin) {
throw new DlmmSdkError(
"SWAP_QUOTE_INSUFFICIENT_LIQUIDITY",
"Insufficient liquidity"
);
}
const actualInAmount = transferFeeExcludedAmountIn.sub(inAmountLeft);
let transferFeeIncludedInAmount = calculateTransferFeeIncludedAmount(
actualInAmount,
inMint,
this.clock.epoch.toNumber()
).amount;
transferFeeIncludedInAmount = transferFeeIncludedInAmount.gt(inAmount) ? inAmount : transferFeeIncludedInAmount;
const outAmountWithoutSlippage = getAmountOut(
startBin,
actualInAmount.sub(
computeFeeFromAmount(
binStep,
sParameters3,
vParameterClone,
actualInAmount
)
),
swapForY
);
const priceImpact = new (0, _decimaljs2.default)(totalOutAmount.toString()).sub(new (0, _decimaljs2.default)(outAmountWithoutSlippage.toString())).div(new (0, _decimaljs2.default)(outAmountWithoutSlippage.toString())).mul(new (0, _decimaljs2.default)(100)).abs();
const endPrice = getPriceOfBinByBinId(
lastFilledActiveBinId.toNumber(),
this.lbPair.binStep
);
if (maxExtraBinArrays > 0 && maxExtraBinArrays <= MAX_EXTRA_BIN_ARRAYS) {
const extraBinArrays = new Array();
while (extraBinArrays.length < maxExtraBinArrays) {
let binArrayAccountToSwap = findNextBinArrayWithLiquidity(
swapForY,
activeId,
this.lbPair,
_nullishCoalesce(_optionalChain([this, 'access', _152 => _152.binArrayBitmapExtension, 'optionalAccess', _153 => _153.account]), () => ( null)),
binArrays
);
if (binArrayAccountToSwap == null) {
break;
}
const binArrayAccountToSwapExisted = binArraysForSwap.has(
binArrayAccountToSwap.publicKey
);
if (binArrayAccountToSwapExisted) {
if (swapForY) {
activeId = activeId.sub(new (0, _anchor.BN)(1));
} else {
activeId = activeId.add(new (0, _anchor.BN)(1));
}
} else {
extraBinArrays.push(binArrayAccountToSwap.publicKey);
const [lowerBinId, upperBinId] = getBinArrayLowerUpperBinId(
binArrayAccountToSwap.account.index
);
if (swapForY) {
activeId = lowerBinId.sub(new (0, _anchor.BN)(1));
} else {
activeId = upperBinId.add(new (0, _anchor.BN)(1));
}
}
}
extraBinArrays.forEach((binArrayPubkey) => {
binArraysForSwap.set(binArrayPubkey, true);
});
}
const binArraysPubkey = Array.from(binArraysForSwap.keys());
const transferFeeExcludedAmountOut = calculateTransferFeeExcludedAmount(
totalOutAmount,
outMint,
this.clock.epoch.toNumber()
).amount;
const minOutAmount = transferFeeExcludedAmountOut.mul(new (0, _anchor.BN)(BASIS_POINT_MAX).sub(allowedSlippage)).div(new (0, _anchor.BN)(BASIS_POINT_MAX));
return {
consumedInAmount: transferFeeIncludedInAmount,
outAmount: transferFeeExcludedAmountOut,
fee: feeAmount,
protocolFee: protocolFeeAmount,
minOutAmount,
priceImpact,
binArraysPubkey,
endPrice,
feeOnInput
};
}
async swapExactOut({
inToken,
outToken,
outAmount,
maxInAmount,
lbPair,
user,
binArraysPubkey
}) {
const preInstructions = [];
const postInstructions = [];
const [inTokenProgram, outTokenProgram] = inToken.equals(
this.lbPair.tokenXMint
) ? [this.tokenX.owner, this.tokenY.owner] : [this.tokenY.owner, this.tokenX.owner];
const [
{ ataPubKey: userTokenIn, ix: createInTokenAccountIx },
{ ataPubKey: userTokenOut, ix: createOutTokenAccountIx }
] = await Promise.all([
getOrCreateATAInstruction(
this.program.provider.connection,
inToken,
user,
inTokenProgram
),
getOrCreateATAInstruction(
this.program.provider.connection,
outToken,
user,
outTokenProgram
)
]);
createInTokenAccountIx && preInstructions.push(createInTokenAccountIx);
createOutTokenAccountIx && preInstructions.push(createOutTokenAccountIx);
if (inToken.equals(_spltoken.NATIVE_MINT) && !_optionalChain([this, 'access', _154 => _154.opt, 'optionalAccess', _155 => _155.skipSolWrappingOperation])) {
const wrapSOLIx = wrapSOLInstruction(
user,
userTokenIn,
BigInt(maxInAmount.toString())
);
preInstructions.push(...wrapSOLIx);
const closeWrappedSOLIx = await unwrapSOLInstruction(user);
closeWrappedSOLIx && postInstructions.push(closeWrappedSOLIx);
}
if (outToken.equals(_spltoken.NATIVE_MINT) && !_optionalChain([this, 'access', _156 => _156.opt, 'optionalAccess', _157 => _157.skipSolWrappingOperation])) {
const closeWrappedSOLIx = await unwrapSOLInstruction(user);
closeWrappedSOLIx && postInstructions.push(closeWrappedSOLIx);
}
const { slices, accounts: transferHookAccounts } = this.getPotentialToken2022IxDataAndAccounts(0 /* Liquidity */);
const binArrays = binArraysPubkey.map((pubkey) => {
return {
isSigner: false,
isWritable: true,
pubkey
};
});
const swapIx = await this.program.methods.swapExactOut2(maxInAmount, outAmount, { slices }).accountsPartial({
lbPair,
reserveX: this.lbPair.reserveX,
reserveY: this.lbPair.reserveY,
tokenXMint: this.lbPair.tokenXMint,
tokenYMint: this.lbPair.tokenYMint,
tokenXProgram: this.tokenX.owner,
tokenYProgram: this.tokenY.owner,
user,
userTokenIn,
userTokenOut,
binArrayBitmapExtension: this.binArrayBitmapExtension ? this.binArrayBitmapExtension.publicKey : null,
oracle: this.lbPair.oracle,
hostFeeIn: null,
memoProgram: MEMO_PROGRAM_ID
}).remainingAccounts(transferHookAccounts).remainingAccounts(binArrays).instruction();
const instructions = [...preInstructions, swapIx, ...postInstructions];
instructions.push(
_web3js.ComputeBudgetProgram.setComputeUnitLimit({
units: 14e5
})
);
const { blockhash, lastValidBlockHeight } = await this.program.provider.connection.getLatestBlockhash("confirmed");
return new (0, _web3js.Transaction)({
blockhash,
lastValidBlockHeight,
feePayer: user
}).add(...instructions);
}
/**
* Returns a transaction to be signed and sent by user performing swap.
* @param {SwapWithPriceImpactParams}
* - `inToken`: The public key of the token to be swapped in.
* - `outToken`: The public key of the token to be swapped out.
* - `inAmount`: The amount of token to be swapped in.
* - `priceImpact`: Accepted price impact bps.
* - `lbPair`: The public key of the liquidity pool.
* - `user`: The public key of the user account.
* - `binArraysPubkey`: Array of bin arrays involved in the swap
* @returns {Promise<Transaction>}
*/
async swapWithPriceImpact({
inToken,
outToken,
inAmount,
lbPair,
user,
priceImpact,
binArraysPubkey
}) {
const preInstructions = [];
const postInstructions = [];
const [inTokenProgram, outTokenProgram] = inToken.equals(
this.lbPair.tokenXMint
) ? [this.tokenX.owner, this.tokenY.owner] : [this.tokenY.owner, this.tokenX.owner];
const [
{ ataPubKey: userTokenIn, ix: createInTokenAccountIx },
{ ataPubKey: userTokenOut, ix: createOutTokenAccountIx }
] = await Promise.all([
getOrCreateATAInstruction(
this.program.provider.connection,
inToken,
user,
inTokenProgram
),
getOrCreateATAInstruction(
this.program.provider.connection,
outToken,
user,
outTokenProgram
)
]);
createInTokenAccountIx && preInstructions.push(createInTokenAccountIx);
createOutTokenAccountIx && preInstructions.push(createOutTokenAccountIx);
if (inToken.equals(_spltoken.NATIVE_MINT) && !_optionalChain([this, 'access', _158 => _158.opt, 'optionalAccess', _159 => _159.skipSolWrappingOperation])) {
const wrapSOLIx = wrapSOLInstruction(
user,
userTokenIn,
BigInt(inAmount.toString())
);
preInstructions.push(...wrapSOLIx);
const closeWrappedSOLIx = await unwrapSOLInstruction(user);
closeWrappedSOLIx && postInstructions.push(closeWrappedSOLIx);
}
if (outToken.equals(_spltoken.NATIVE_MINT) && !_optionalChain([this, 'access', _160 => _160.opt, 'optionalAccess', _161 => _161.skipSolWrappingOperation])) {
const closeWrappedSOLIx = await unwrapSOLInstruction(user);
closeWrappedSOLIx && postInstructions.push(closeWrappedSOLIx);
}
const binArrays = binArraysPubkey.map((pubkey) => {
return {
isSigner: false,
isWritable: true,
pubkey
};
});
const { slices, accounts: transferHookAccounts } = this.getPotentialToken2022IxDataAndAccounts(0 /* Liquidity */);
const swapIx = await this.program.methods.swapWithPriceImpact2(
inAmount,
this.lbPair.activeId,
priceImpact.toNumber(),
{ slices }
).accountsPartial({
lbPair,
reserveX: this.lbPair.reserveX,
reserveY: this.lbPair.reserveY,
tokenXMint: this.lbPair.tokenXMint,
tokenYMint: this.lbPair.tokenYMint,
tokenXProgram: this.tokenX.owner,
tokenYProgram: this.tokenY.owner,
user,
userTokenIn,
userTokenOut,
binArrayBitmapExtension: this.binArrayBitmapExtension ? this.binArrayBitmapExtension.publicKey : null,
oracle: this.lbPair.oracle,
hostFeeIn: null,
memoProgram: MEMO_PROGRAM_ID
}).remainingAccounts(transferHookAccounts).remainingAccounts(binArrays).instruction();
const instructions = [...preInstructions, swapIx, ...postInstructions];
const setCUIx = await getEstimatedComputeUnitIxWithBuffer(
this.program.provider.connection,
instructions,
user
);
instructions.unshift(setCUIx);
const { blockhash, lastValidBlockHeight } = await this.program.provider.connection.getLatestBlockhash("confirmed");
return new (0, _web3js.Transaction)({
blockhash,
lastValidBlockHeight,
feePayer: user
}).add(...instructions);
}
/**
* Returns a transaction to be signed and sent by user performing swap.
* @param {SwapParams}
* - `inToken`: The public key of the token to be swapped in.
* - `outToken`: The public key of the token to be swapped out.
* - `inAmount`: The amount of token to be swapped in.
* - `minOutAmount`: The minimum amount of token to be swapped out.
* - `lbPair`: The public key of the liquidity pool.
* - `user`: The public key of the user account.
* - `binArraysPubkey`: Array of bin arrays involved in the swap
* @returns {Promise<Transaction>}
*/
async swap({
inToken,
outToken,
inAmount,
minOutAmount,
lbPair,
user,
binArraysPubkey
}) {
const preInstructions = [];
const postInstructions = [];
const [inTokenProgram, outTokenProgram] = inToken.equals(
this.lbPair.tokenXMint
) ? [this.tokenX.owner, this.tokenY.owner] : [this.tokenY.owner, this.tokenX.owner];
const [
{ ataPubKey: userTokenIn, ix: createInTokenAccountIx },
{ ataPubKey: userTokenOut, ix: createOutTokenAccountIx }
] = await Promise.all([
getOrCreateATAInstruction(
this.program.provider.connection,
inToken,
user,
inTokenProgram
),
getOrCreateATAInstruction(
this.program.provider.connection,
outToken,
user,
outTokenProgram
)
]);
createInTokenAccountIx && preInstructions.push(createInTokenAccountIx);
createOutTokenAccountIx && preInstructions.push(createOutTokenAccountIx);
if (inToken.equals(_spltoken.NATIVE_MINT) && !_optionalChain([this, 'access', _162 => _162.opt, 'optionalAccess', _163 => _163.skipSolWrappingOperation])) {
const wrapSOLIx = wrapSOLInstruction(
user,
userTokenIn,
BigInt(inAmount.toString())
);
preInstructions.push(...wrapSOLIx);
const closeWrappedSOLIx = await unwrapSOLInstruction(user);
closeWrappedSOLIx && postInstructions.push(closeWrappedSOLIx);
}
if (outToken.equals(_spltoken.NATIVE_MINT) && !_optionalChain([this, 'access', _164 => _164.opt, 'optionalAccess', _165 => _165.skipSolWrappingOperation])) {
const closeWrappedSOLIx = await unwrapSOLInstruction(user);
closeWrappedSOLIx && postInstructions.push(closeWrappedSOLIx);
}
const binArrays = binArraysPubkey.map((pubkey) => {
return {
isSigner: false,
isWritable: true,
pubkey
};
});
const { slices, accounts: transferHookAccounts } = this.getPotentialToken2022IxDataAndAccounts(0 /* Liquidity */);
const swapIx = await this.program.methods.swap2(inAmount, minOutAmount, { slices }).accountsPartial({
lbPair,
reserveX: this.lbPair.reserveX,
reserveY: this.lbPair.reserveY,
tokenXMint: this.lbPair.tokenXMint,
tokenYMint: this.lbPair.tokenYMint,
tokenXProgram: this.tokenX.owner,
tokenYProgram: this.tokenY.owner,
user,
userTokenIn,
userTokenOut,
binArrayBitmapExtension: this.binArrayBitmapExtension ? this.binArrayBitmapExtension.publicKey : null,
oracle: this.lbPair.oracle,
hostFeeIn: null,
memoProgram: MEMO_PROGRAM_ID
}).remainingAccounts(transferHookAccounts).remainingAccounts(binArrays).instruction();
const instructions = [...preInstructions, swapIx, ...postInstructions];
const setCUIx = await getEstimatedComputeUnitIxWithBuffer(
this.program.provider.connection,
instructions,
user
);
instructions.unshift(setCUIx);
const { blockhash, lastValidBlockHeight } = await this.program.provider.connection.getLatestBlockhash("confirmed");
return new (0, _web3js.Transaction)({
blockhash,
lastValidBlockHeight,
feePayer: user
}).add(...instructions);
}
/**
* The claimLMReward function is used to claim rewards for a specific position owned by a specific owner.
* @param
* - `owner`: The public key of the owner of the position.
* - `position`: The public key of the position account.
* @returns {Promise<Transaction[]>} Claim LM reward transactions.
*/
async claimLMReward({
owner,
position
}) {
if (isPositionNoReward(position.positionData)) {
throw new Error("No LM reward to claim");
}
const claimTransactions = await this.createClaimBuildMethod({
owner,
position
});
if (!claimTransactions.length)
return;
const claimTransactionWithCUIx = await Promise.all(
claimTransactions.map(async (tx) => {
const setCUIx = await getEstimatedComputeUnitIxWithBuffer(
this.program.provider.connection,
tx.instructions,
owner
);
return [setCUIx, ...tx.instructions];
})
);
const { blockhash, lastValidBlockHeight } = await this.program.provider.connection.getLatestBlockhash("confirmed");
return claimTransactionWithCUIx.map((ixs) => {
return new (0, _web3js.Transaction)({
blockhash,
lastValidBlockHeight,
feePayer: owner
}).add(...ixs);
});
}
/**
* The `claimAllLMRewards` function is used to claim all liquidity mining rewards for a given owner
* and their positions.
* @param
* - `owner`: The public key of the owner of the positions.
* - `positions`: An array of objects of type `PositionData` that represents the positions to claim rewards from.
* @returns {Promise<Transaction[]>} Array of claim LM reward and fees transactions.
*/
async claimAllLMRewards({
owner,
positions
}) {
if (positions.every((position) => isPositionNoReward(position.positionData))) {
throw new Error("No LM reward to claim");
}
const claimAllTxs = (await Promise.all(
positions.filter(
({ positionData: { rewardOne, rewardTwo } }) => !rewardOne.isZero() || !rewardTwo.isZero()
).map(async (position, idx) => {
return await this.createClaimBuildMethod({
owner,
position
});
})
)).flat();
const chunkedClaimAllTx = chunks(claimAllTxs, MAX_CLAIM_ALL_ALLOWED);
if (chunkedClaimAllTx.length === 0)
return [];
const chunkedClaimAllTxIx = await Promise.all(
chunkedClaimAllTx.map(async (txs) => {
const ixs = txs.map((t) => t.instructions).flat();
const setCUIx = await getEstimatedComputeUnitIxWithBuffer(
this.program.provider.connection,
ixs,
owner
);
return [setCUIx, ...ixs];
})
);
const { blockhash, lastValidBlockHeight } = await this.program.provider.connection.getLatestBlockhash("confirmed");
return Promise.all(
chunkedClaimAllTxIx.map(async (claimAllTx) => {
return new (0, _web3js.Transaction)({
feePayer: owner,
blockhash,
lastValidBlockHeight
}).add(...claimAllTx);
})
);
}
async setActivationPoint(activationPoint) {
const setActivationPointTx = await this.program.methods.setActivationPoint(activationPoint).accountsPartial({
lbPair: this.pubkey,
signer: this.lbPair.creator
}).transaction();
const { blockhash, lastValidBlockHeight } = await this.program.provider.connection.getLatestBlockhash("confirmed");
return new (0, _web3js.Transaction)({
feePayer: this.lbPair.creator,
blockhash,
lastValidBlockHeight
}).add(setActivationPointTx);
}
async setPairStatus(enabled) {
const pairStatus = enabled ? 0 : 1;
const tx = await this.program.methods.setPairStatus(pairStatus).accountsPartial({
lbPair: this.pubkey,
signer: this.lbPair.creator
}).transaction();
const { blockhash, lastValidBlockHeight } = await this.program.provider.connection.getLatestBlockhash("confirmed");
return new (0, _web3js.Transaction)({
feePayer: this.lbPair.creator,
blockhash,
lastValidBlockHeight
}).add(tx);
}
/**
* The function `claimSwapFee` is used to claim swap fees for a specific position owned by a specific owner.
* @param
* - `owner`: The public key of the owner of the position.
* - `position`: The public key of the position account.
* - `binRange`: The bin range to claim swap fees for. If not provided, the function claim swap fees for full range.
* @returns {Promise<Transaction[]>} Claim swap fee transactions.
*/
async claimSwapFee({
owner,
position
}) {
if (isPositionNoFee(position.positionData)) {
throw new Error("No fee to claim");
}
const claimFeeTxs = await this.createClaimSwapFeeMethod({
owner,
position
});
const claimFeeTxsWithCUIx = await Promise.all(
claimFeeTxs.map(async (tx) => {
const setCUIx = await getEstimatedComputeUnitIxWithBuffer(
this.program.provider.connection,
tx.instructions,
owner
);
return [setCUIx, ...tx.instructions];
})
);
const { blockhash, lastValidBlockHeight } = await this.program.provider.connection.getLatestBlockhash("confirmed");
return claimFeeTxsWithCUIx.map((ixs) => {
return new (0, _web3js.Transaction)({
blockhash,
lastValidBlockHeight,
feePayer: owner
}).add(...ixs);
});
}
/**
* The `claimAllSwapFee` function to claim swap fees for multiple positions owned by a specific owner.
* @param
* - `owner`: The public key of the owner of the positions.
* - `positions`: An array of objects of type `PositionData` that represents the positions to claim swap fees from.
* @returns {Promise<Transaction[]>} Array of claim swap fee transactions.
*/
async claimAllSwapFee({
owner,
positions
}) {
if (positions.every((position) => isPositionNoFee(position.positionData))) {
throw new Error("No fee to claim");
}
const claimAllTxs = (await Promise.all(
positions.filter(
({ positionData: { feeX, feeY } }) => !feeX.isZero() || !feeY.isZero()
).map(async (position) => {
return await this.createClaimSwapFeeMethod({
owner,
position
});
})
)).flat();
const chunkedClaimAllTx = chunks(claimAllTxs, MAX_CLAIM_ALL_ALLOWED);
if (chunkedClaimAllTx.length === 0)
return [];
const chunkedClaimAllTxIxs = await Promise.all(
chunkedClaimAllTx.map(async (tx) => {
const ixs = tx.map((t) => t.instructions).flat();
const setCUIx = await getEstimatedComputeUnitIxWithBuffer(
this.program.provider.connection,
ixs,
owner
);
return [setCUIx, ...ixs];
})
);
const { blockhash, lastValidBlockHeight } = await this.program.provider.connection.getLatestBlockhash("confirmed");
return Promise.all(
chunkedClaimAllTxIxs.map(async (claimAllTx) => {
return new (0, _web3js.Transaction)({
feePayer: owner,
blockhash,
lastValidBlockHeight
}).add(...claimAllTx);
})
);
}
/**
* The function `claimAllRewardsByPosition` allows a user to claim all rewards for a specific
* position.
* @param
* - `owner`: The public key of the owner of the position.
* - `position`: The public key of the position account.
* @returns {Promise<Transaction[]>} Array of claim reward transactions.
*/
async claimAllRewardsByPosition({
owner,
position
}) {
if (isPositionNoFee(position.positionData) && isPositionNoReward(position.positionData)) {
throw new Error("No fee/reward to claim");
}
const claimAllSwapFeeTxs = await this.createClaimSwapFeeMethod({
owner,
position
});
const claimAllLMTxs = await this.createClaimBuildMethod({
owner,
position
});
const claimAllTxs = chunks(
[...claimAllSwapFeeTxs, ...claimAllLMTxs],
MAX_CLAIM_ALL_ALLOWED
);
const { blockhash, lastValidBlockHeight } = await this.program.provider.connection.getLatestBlockhash("confirmed");
return Promise.all(
claimAllTxs.map(async (txs) => {
const instructions = txs.flatMap((tx) => tx.instructions);
const setCUIx = await getEstimatedComputeUnitIxWithBuffer(
this.program.provider.connection,
instructions,
owner
);
const transaction = new (0, _web3js.Transaction)({
feePayer: owner,
blockhash,
lastValidBlockHeight
}).add(setCUIx, ...instructions);
return transaction;
})
);
}
/**
* The `seedLiquidity` function create multiple grouped instructions. The grouped instructions will be [init ata + send lamport for token provde], [initialize bin array + initialize position instructions] and [deposit instruction]. Each grouped instructions can be executed parallelly.
* @param
* - `owner`: The public key of the positions owner.
* - `seedAmount`: Lamport amount to be seeded to the pool.
* - `minPrice`: Start price in UI format
* - `maxPrice`: End price in UI format
* - `base`: Base key
* - `txPayer`: Account rental fee payer
* - `feeOwner`: Fee owner key. Default to position owner
* - `operator`: Operator key
* - `lockReleasePoint`: Timelock. Point (slot/timestamp) the position can withdraw the liquidity,
* - `shouldSeedPositionOwner` (optional): Whether to send 1 lamport amount of token X to the position owner to prove ownership.
* @returns {Promise<SeedLiquidityResponse>}
*/
async seedLiquidity(owner, seedAmount, curvature, minPrice, maxPrice, base, payer, feeOwner, operator, lockReleasePoint, shouldSeedPositionOwner = false) {
let tokenOwnerProveAssociatedTokenAccountLamports = new (0, _anchor.BN)(0);
let totalPositionCount = new (0, _anchor.BN)(0);
let totalPositionLamports = new (0, _anchor.BN)(0);
let totalBinArraysCount = new (0, _anchor.BN)(0);
let totalBinArraysLamports = new (0, _anchor.BN)(0);
let binArrayBitmapLamports = new (0, _anchor.BN)(0);
const toLamportMultiplier = new (0, _decimaljs2.default)(
10 ** (this.tokenY.mint.decimals - this.tokenX.mint.decimals)
);
const minPricePerLamport = new (0, _decimaljs2.default)(minPrice).mul(toLamportMultiplier);
const maxPricePerLamport = new (0, _decimaljs2.default)(maxPrice).mul(toLamportMultiplier);
const minBinId = new (0, _anchor.BN)(
DLMM.getBinIdFromPrice(minPricePerLamport, this.lbPair.binStep, false)
);
const maxBinId = new (0, _anchor.BN)(
DLMM.getBinIdFromPrice(maxPricePerLamport, this.lbPair.binStep, true)
);
if (minBinId.toNumber() < this.lbPair.activeId) {
throw new Error("minPrice < current pair price");
}
if (minBinId.toNumber() >= maxBinId.toNumber()) {
throw new Error("Price range too small");
}
const k = 1 / curvature;
const binDepositAmount = generateAmountForBinRange(
seedAmount,
this.lbPair.binStep,
this.tokenX.mint.decimals,
this.tokenY.mint.decimals,
minBinId,
maxBinId,
k
);
const decompressMultiplier = findOptimumDecompressMultiplier(
binDepositAmount,
new (0, _anchor.BN)(this.tokenX.mint.decimals)
);
let { compressedBinAmount, compressionLoss } = compressBinAmount(
binDepositAmount,
decompressMultiplier
);
let {
newCompressedBinAmount: compressedBinDepositAmount,
loss: finalLoss
} = distributeAmountToCompressedBinsByRatio(
compressedBinAmount,
compressionLoss,
decompressMultiplier,
new (0, _anchor.BN)(2 ** 32 - 1)
// u32
);
const positionCount = getPositionCount(minBinId, maxBinId.sub(new (0, _anchor.BN)(1)));
const seederTokenX = _spltoken.getAssociatedTokenAddressSync.call(void 0,
this.lbPair.tokenXMint,
operator,
false,
this.tokenX.owner
);
const seederTokenY = _spltoken.getAssociatedTokenAddressSync.call(void 0,
this.lbPair.tokenYMint,
operator,
false,
this.tokenY.owner
);
const ownerTokenX = _spltoken.getAssociatedTokenAddressSync.call(void 0,
this.lbPair.tokenXMint,
owner,
false,
this.tokenX.owner
);
const [binArrayBitmapExtension] = deriveBinArrayBitmapExtension(
this.pubkey,
this.program.programId
);
const sendPositionOwnerTokenProveIxs = [];
const initializeBinArraysAndPositionIxs = [];
const addLiquidityIxs = [];
const appendedInitBinArrayIx = /* @__PURE__ */ new Set();
let appendedInitBinArrayBitmap = false;
if (shouldSeedPositionOwner) {
const positionOwnerTokenX = await this.program.provider.connection.getAccountInfo(ownerTokenX);
let requireTokenProve = false;
if (positionOwnerTokenX) {
const ownerTokenXState = _spltoken.unpackAccount.call(void 0,
ownerTokenX,
positionOwnerTokenX,
this.tokenX.owner
);
requireTokenProve = ownerTokenXState.amount == 0n;
} else {
requireTokenProve = true;
}
if (requireTokenProve) {
if (!positionOwnerTokenX) {
tokenOwnerProveAssociatedTokenAccountLamports = tokenOwnerProveAssociatedTokenAccountLamports.add(
TOKEN_ACCOUNT_FEE_BN
);
}
const initPositionOwnerTokenX = _spltoken.createAssociatedTokenAccountIdempotentInstruction.call(void 0,
payer,
ownerTokenX,
owner,
this.lbPair.tokenXMint,
this.tokenX.owner
);
const proveAmount = calculateTransferFeeIncludedAmount(
new (0, _anchor.BN)(1),
this.tokenX.mint,
this.clock.epoch.toNumber()
).amount;
sendPositionOwnerTokenProveIxs.push(initPositionOwnerTokenX);
const transferIx = _spltoken.createTransferCheckedInstruction.call(void 0,
seederTokenX,
this.lbPair.tokenXMint,
ownerTokenX,
operator,
BigInt(proveAmount.toString()),
this.tokenX.mint.decimals,
[],
this.tokenX.owner
);
transferIx.keys.push(...this.tokenX.transferHookAccountMetas);
sendPositionOwnerTokenProveIxs.push(transferIx);
}
}
const slices = [
{
accountsType: {
transferHookX: {}
},
length: this.tokenX.transferHookAccountMetas.length
}
];
const transferHookAccountMetas = this.tokenX.transferHookAccountMetas;
for (let i = 0; i < positionCount.toNumber(); i++) {
const lowerBinId = minBinId.add(DEFAULT_BIN_PER_POSITION.mul(new (0, _anchor.BN)(i)));
const upperBinId = lowerBinId.add(DEFAULT_BIN_PER_POSITION).sub(new (0, _anchor.BN)(1));
const binArrayAccountMetas = getBinArrayAccountMetasCoverage(
lowerBinId,
upperBinId,
this.pubkey,
this.program.programId
);
const binArrayIndexes = getBinArrayIndexesCoverage(
lowerBinId,
upperBinId
);
const [positionPda, _bump] = derivePosition(
this.pubkey,
base,
lowerBinId,
DEFAULT_BIN_PER_POSITION,
this.program.programId
);
const accounts = await this.program.provider.connection.getMultipleAccountsInfo([
...binArrayAccountMetas.map((acc) => acc.pubkey),
positionPda
]);
let instructions = [];
const binArrayAccounts = accounts.splice(0, binArrayAccountMetas.length);
for (let i2 = 0; i2 < binArrayAccountMetas.length; i2++) {
const account = binArrayAccounts[i2];
const pubkey = binArrayAccountMetas[i2].pubkey.toBase58();
const index = binArrayIndexes[i2];
if (!account && !appendedInitBinArrayIx.has(pubkey)) {
totalBinArraysCount = totalBinArraysCount.add(new (0, _anchor.BN)(1));
totalBinArraysLamports = totalBinArraysLamports.add(BIN_ARRAY_FEE_BN);
instructions.push(
await this.program.methods.initializeBinArray(index).accountsPartial({
lbPair: this.pubkey,
binArray: pubkey,
funder: payer
}).instruction()
);
}
}
const positionAccount = accounts.pop();
if (!positionAccount) {
totalPositionCount = totalPositionCount.add(new (0, _anchor.BN)(1));
totalPositionLamports = totalPositionLamports.add(POSITION_FEE_BN);
instructions.push(
await this.program.methods.initializePositionByOperator(
lowerBinId.toNumber(),
DEFAULT_BIN_PER_POSITION.toNumber(),
feeOwner,
lockReleasePoint
).accountsPartial({
lbPair: this.pubkey,
position: positionPda,
base,
owner,
operator,
operatorTokenX: seederTokenX,
ownerTokenX,
systemProgram: _web3js.SystemProgram.programId,
payer
}).instruction()
);
}
if (instructions.length > 0) {
initializeBinArraysAndPositionIxs.push(instructions);
instructions = [];
}
const positionDeposited = positionAccount && decodeAccount(
this.program,
"positionV2",
positionAccount.data
).liquidityShares.reduce((total, cur) => total.add(cur), new (0, _anchor.BN)(0)).gt(new (0, _anchor.BN)(0));
if (!positionDeposited) {
let overflowDefaultBinArrayBitmap = false;
for (const binArrayIndex of binArrayIndexes) {
if (isOverflowDefaultBinArrayBitmap(binArrayIndex)) {
if (!this.binArrayBitmapExtension && !appendedInitBinArrayBitmap) {
initializeBinArraysAndPositionIxs.push(
await this.program.methods.initializeBinArrayBitmapExtension().accountsPartial({
binArrayBitmapExtension,
funder: payer,
lbPair: this.pubkey,
rent: _web3js.SYSVAR_RENT_PUBKEY
}).instruction()
);
appendedInitBinArrayBitmap = true;
binArrayBitmapLamports = binArrayBitmapLamports.add(
BIN_ARRAY_BITMAP_FEE_BN
);
}
overflowDefaultBinArrayBitmap = true;
}
}
const cappedUpperBinId = Math.min(
upperBinId.toNumber(),
maxBinId.toNumber() - 1
);
const bins = [];
for (let i2 = lowerBinId.toNumber(); i2 <= cappedUpperBinId; i2++) {
bins.push({
binId: i2,
amount: compressedBinDepositAmount.get(i2).toNumber()
});
}
instructions.push(
await this.program.methods.addLiquidityOneSidePrecise2(
{
bins,
decompressMultiplier,
maxAmount: U64_MAX
},
{
slices
}
).accountsPartial({
position: positionPda,
lbPair: this.pubkey,
binArrayBitmapExtension: overflowDefaultBinArrayBitmap ? binArrayBitmapExtension : this.program.programId,
userToken: seederTokenX,
reserve: this.lbPair.reserveX,
tokenMint: this.lbPair.tokenXMint,
sender: operator,
tokenProgram: this.tokenX.owner
}).remainingAccounts([
...transferHookAccountMetas,
...binArrayAccountMetas
]).instruction()
);
if (i + 1 >= positionCount.toNumber() && !finalLoss.isZero()) {
const finalLossIncludesTransferFee = calculateTransferFeeIncludedAmount(
finalLoss,
this.tokenX.mint,
this.clock.epoch.toNumber()
).amount;
instructions.push(
await this.program.methods.addLiquidity2(
{
amountX: finalLossIncludesTransferFee,
amountY: new (0, _anchor.BN)(0),
binLiquidityDist: [
{
binId: cappedUpperBinId,
distributionX: BASIS_POINT_MAX,
distributionY: BASIS_POINT_MAX
}
]
},
{
slices
}
).accountsPartial({
position: positionPda,
lbPair: this.pubkey,
binArrayBitmapExtension: overflowDefaultBinArrayBitmap ? binArrayBitmapExtension : this.program.programId,
userTokenX: seederTokenX,
userTokenY: seederTokenY,
reserveX: this.lbPair.reserveX,
reserveY: this.lbPair.reserveY,
tokenXMint: this.lbPair.tokenXMint,
tokenYMint: this.lbPair.tokenYMint,
tokenXProgram: this.tokenX.owner,
tokenYProgram: this.tokenY.owner,
sender: operator
}).remainingAccounts([
...transferHookAccountMetas,
...getBinArrayAccountMetasCoverage(
new (0, _anchor.BN)(cappedUpperBinId),
new (0, _anchor.BN)(cappedUpperBinId),
this.pubkey,
this.program.programId
)
]).instruction()
);
}
addLiquidityIxs.push([
_web3js.ComputeBudgetProgram.setComputeUnitLimit({
units: DEFAULT_ADD_LIQUIDITY_CU
}),
...instructions
]);
}
}
return {
sendPositionOwnerTokenProveIxs,
initializeBinArraysAndPositionIxs,
addLiquidityIxs,
costBreakdown: {
tokenOwnerProveAssociatedTokenAccountLamports,
totalBinArraysCount,
totalBinArraysLamports,
totalPositionCount,
totalPositionLamports,
binArrayBitmapLamports
}
};
}
/**
* The `seedLiquiditySingleBin` function seed liquidity into a single bin.
* @param
* - `payer`: The public key of the tx payer.
* - `base`: Base key
* - `seedAmount`: Token X lamport amount to be seeded to the pool.
* - `price`: TokenX/TokenY Price in UI format
* - `roundingUp`: Whether to round up the price
* - `positionOwner`: The owner of the position
* - `feeOwner`: Position fee owner
* - `operator`: Operator of the position. Operator able to manage the position on behalf of the position owner. However, liquidity withdrawal issue by the operator can only send to the position owner.
* - `lockReleasePoint`: The lock release point of the position.
* - `shouldSeedPositionOwner` (optional): Whether to send 1 lamport amount of token X to the position owner to prove ownership.
*
* The returned instructions need to be executed sequentially if it was separated into multiple transactions.
* @returns {Promise<SeedLiquiditySingleBinResponse>}
*/
async seedLiquiditySingleBin(payer, base, seedAmount, price, roundingUp, positionOwner, feeOwner, operator, lockReleasePoint, shouldSeedPositionOwner = false) {
let tokenOwnerProveAssociatedTokenAccountLamports = new (0, _anchor.BN)(0);
let totalPositionCount = new (0, _anchor.BN)(0);
let totalPositionLamports = new (0, _anchor.BN)(0);
let totalBinArraysCount = new (0, _anchor.BN)(0);
let totalBinArraysLamports = new (0, _anchor.BN)(0);
let binArrayBitmapLamports = new (0, _anchor.BN)(0);
const pricePerLamport = DLMM.getPricePerLamport(
this.tokenX.mint.decimals,
this.tokenY.mint.decimals,
price
);
const binIdNumber = DLMM.getBinIdFromPrice(
pricePerLamport,
this.lbPair.binStep,
!roundingUp
);
const binId = new (0, _anchor.BN)(binIdNumber);
const [positionPda] = derivePosition(
this.pubkey,
base,
binId,
new (0, _anchor.BN)(1),
this.program.programId
);
const binArrayIndex = binIdToBinArrayIndex(binId);
const [binArrayKey] = deriveBinArray(
this.pubkey,
binArrayIndex,
this.program.programId
);
const preInstructions = [];
const [
{ ataPubKey: userTokenX, ix: createPayerTokenXIx },
{ ataPubKey: userTokenY, ix: createPayerTokenYIx }
] = await Promise.all([
getOrCreateATAInstruction(
this.program.provider.connection,
this.tokenX.publicKey,
operator,
this.tokenX.owner,
payer
),
getOrCreateATAInstruction(
this.program.provider.connection,
this.tokenY.publicKey,
operator,
this.tokenY.owner,
payer
)
]);
createPayerTokenXIx && preInstructions.push(createPayerTokenXIx);
createPayerTokenYIx && preInstructions.push(createPayerTokenYIx);
let [binArrayBitmapExtension] = deriveBinArrayBitmapExtension(
this.pubkey,
this.program.programId
);
const [binArrayAccount, positionAccount, bitmapExtensionAccount] = await this.program.provider.connection.getMultipleAccountsInfo([
binArrayKey,
positionPda,
binArrayBitmapExtension
]);
if (isOverflowDefaultBinArrayBitmap(binArrayIndex)) {
if (!bitmapExtensionAccount) {
preInstructions.push(
await this.program.methods.initializeBinArrayBitmapExtension().accountsPartial({
binArrayBitmapExtension,
funder: payer,
lbPair: this.pubkey,
rent: _web3js.SYSVAR_RENT_PUBKEY
}).instruction()
);
binArrayBitmapLamports = binArrayBitmapLamports.add(
BIN_ARRAY_BITMAP_FEE_BN
);
}
} else {
binArrayBitmapExtension = this.program.programId;
}
const operatorTokenX = _spltoken.getAssociatedTokenAddressSync.call(void 0,
this.lbPair.tokenXMint,
operator,
true,
this.tokenX.owner
);
const positionOwnerTokenX = _spltoken.getAssociatedTokenAddressSync.call(void 0,
this.lbPair.tokenXMint,
positionOwner,
true,
this.tokenX.owner
);
if (shouldSeedPositionOwner) {
const positionOwnerTokenXAccount = await this.program.provider.connection.getAccountInfo(
positionOwnerTokenX
);
const proveAmount = calculateTransferFeeIncludedAmount(
new (0, _anchor.BN)(1),
this.tokenX.mint,
this.clock.epoch.toNumber()
).amount;
if (positionOwnerTokenXAccount) {
const account = _spltoken.unpackAccount.call(void 0,
positionOwnerTokenX,
positionOwnerTokenXAccount,
this.tokenX.owner
);
if (account.amount == BigInt(0)) {
const transferIx = _spltoken.createTransferCheckedInstruction.call(void 0,
operatorTokenX,
this.lbPair.tokenXMint,
positionOwnerTokenX,
operator,
BigInt(proveAmount.toString()),
this.tokenX.mint.decimals,
[],
this.tokenX.owner
);
transferIx.keys.push(...this.tokenX.transferHookAccountMetas);
preInstructions.push(transferIx);
}
} else {
const createPositionOwnerTokenXIx = _spltoken.createAssociatedTokenAccountIdempotentInstruction.call(void 0,
payer,
positionOwnerTokenX,
positionOwner,
this.lbPair.tokenXMint,
this.tokenX.owner
);
preInstructions.push(createPositionOwnerTokenXIx);
const transferIx = _spltoken.createTransferCheckedInstruction.call(void 0,
operatorTokenX,
this.lbPair.tokenXMint,
positionOwnerTokenX,
operator,
BigInt(proveAmount.toString()),
this.tokenX.mint.decimals,
[],
this.tokenX.owner
);
transferIx.keys.push(...this.tokenX.transferHookAccountMetas);
preInstructions.push(transferIx);
tokenOwnerProveAssociatedTokenAccountLamports = tokenOwnerProveAssociatedTokenAccountLamports.add(
TOKEN_ACCOUNT_FEE_BN
);
}
}
if (!binArrayAccount) {
preInstructions.push(
await this.program.methods.initializeBinArray(binArrayIndex).accountsPartial({
binArray: binArrayKey,
funder: payer,
lbPair: this.pubkey
}).instruction()
);
totalBinArraysCount = totalBinArraysCount.add(new (0, _anchor.BN)(1));
totalBinArraysLamports = totalBinArraysLamports.add(BIN_ARRAY_FEE_BN);
}
if (!positionAccount) {
preInstructions.push(
await this.program.methods.initializePositionByOperator(
binId.toNumber(),
1,
feeOwner,
lockReleasePoint
).accountsPartial({
payer,
base,
position: positionPda,
lbPair: this.pubkey,
owner: positionOwner,
operator,
operatorTokenX,
ownerTokenX: positionOwnerTokenX
}).instruction()
);
totalPositionCount = totalPositionCount.add(new (0, _anchor.BN)(1));
totalPositionLamports = totalPositionLamports.add(POSITION_FEE_BN);
}
const slices = [
{
accountsType: {
transferHookX: {}
},
length: this.tokenX.transferHookAccountMetas.length
}
];
const transferHookAccountMetas = this.tokenX.transferHookAccountMetas;
const binLiquidityDist = {
binId: binIdNumber,
distributionX: BASIS_POINT_MAX,
distributionY: BASIS_POINT_MAX
};
const seedAmountIncludeTransferFee = calculateTransferFeeIncludedAmount(
seedAmount,
this.tokenX.mint,
this.clock.epoch.toNumber()
).amount;
const addLiquidityParams = {
amountX: seedAmountIncludeTransferFee,
amountY: new (0, _anchor.BN)(0),
binLiquidityDist: [binLiquidityDist]
};
const depositLiquidityIx = await this.program.methods.addLiquidity2(addLiquidityParams, {
slices
}).accountsPartial({
position: positionPda,
lbPair: this.pubkey,
binArrayBitmapExtension,
userTokenX,
userTokenY,
reserveX: this.lbPair.reserveX,
reserveY: this.lbPair.reserveY,
tokenXMint: this.lbPair.tokenXMint,
tokenYMint: this.lbPair.tokenYMint,
sender: operator,
tokenXProgram: this.tokenX.owner,
tokenYProgram: this.tokenY.owner
}).remainingAccounts([
...transferHookAccountMetas,
{
pubkey: binArrayKey,
isSigner: false,
isWritable: true
}
]).instruction();
const instructions = [...preInstructions, depositLiquidityIx];
return {
instructions,
costBreakdown: {
tokenOwnerProveAssociatedTokenAccountLamports,
totalBinArraysCount,
totalBinArraysLamports,
totalPositionCount,
totalPositionLamports,
binArrayBitmapLamports
}
};
}
/**
* Initializes bin arrays for the given bin array indexes if it wasn't initialized.
*
* @param {BN[]} binArrayIndexes - An array of bin array indexes to initialize.
* @param {PublicKey} funder - The public key of the funder.
* @return {Promise<TransactionInstruction[]>} An array of transaction instructions to initialize the bin arrays.
*/
async initializeBinArrays(binArrayIndexes, funder) {
const ixs = [];
for (const idx of binArrayIndexes) {
const [binArray] = deriveBinArray(
this.pubkey,
idx,
this.program.programId
);
const binArrayAccount = await this.program.provider.connection.getAccountInfo(binArray);
if (binArrayAccount === null) {
const initBinArrayIx = await this.program.methods.initializeBinArray(idx).accountsPartial({
binArray,
funder,
lbPair: this.pubkey
}).instruction();
ixs.push(initBinArrayIx);
}
}
if (ixs.length > 0) {
const setCUIx = await getEstimatedComputeUnitIxWithBuffer(
this.program.provider.connection,
ixs,
funder
);
ixs.unshift(setCUIx);
}
return ixs;
}
/**
*
* @param
* - `lowerBinId`: Lower bin ID of the position. This represent the lowest price of the position
* - `positionWidth`: Width of the position. This will decide the upper bin id of the position, which represents the highest price of the position. UpperBinId = lowerBinId + positionWidth
* - `owner`: Owner of the position.
* - `operator`: Operator of the position. Operator able to manage the position on behalf of the position owner. However, liquidity withdrawal issue by the operator can only send to the position owner.
* - `base`: Base key
* - `feeOwner`: Owner of the fees earned by the position.
* - `payer`: Payer for the position account rental.
* - `lockReleasePoint`: The lock release point of the position.
* @returns
*/
async initializePositionByOperator({
lowerBinId,
positionWidth,
owner,
feeOwner,
base,
operator,
payer,
lockReleasePoint
}) {
const [positionPda, _bump] = derivePosition(
this.pubkey,
base,
lowerBinId,
positionWidth,
this.program.programId
);
const operatorTokenX = _spltoken.getAssociatedTokenAddressSync.call(void 0,
this.lbPair.tokenXMint,
operator,
true,
this.tokenX.owner
);
const ownerTokenX = _spltoken.getAssociatedTokenAddressSync.call(void 0,
this.lbPair.tokenXMint,
owner,
true,
this.tokenY.owner
);
const initializePositionByOperatorTx = await this.program.methods.initializePositionByOperator(
lowerBinId.toNumber(),
DEFAULT_BIN_PER_POSITION.toNumber(),
feeOwner,
lockReleasePoint
).accountsPartial({
lbPair: this.pubkey,
position: positionPda,
base,
operator,
owner,
ownerTokenX,
operatorTokenX,
payer
}).transaction();
const { blockhash, lastValidBlockHeight } = await this.program.provider.connection.getLatestBlockhash("confirmed");
return new (0, _web3js.Transaction)({
feePayer: operator,
blockhash,
lastValidBlockHeight
}).add(initializePositionByOperatorTx);
}
/**
* The `claimAllRewards` function to claim swap fees and LM rewards for multiple positions owned by a specific owner.
* @param
* - `owner`: The public key of the owner of the positions.
* - `positions`: An array of objects of type `PositionData` that represents the positions to claim swap fees and LM rewards from.
* @returns {Promise<Transaction[]>} Array of claim swap fee and LM reward transactions.
*/
async claimAllRewards({
owner,
positions
}) {
positions = positions.filter(
({ positionData: { feeX, feeY, rewardOne, rewardTwo } }) => !feeX.isZero() || !feeY.isZero() || !rewardOne.isZero() || !rewardTwo.isZero()
);
const claimAllSwapFeeTxs = (await Promise.all(
positions.map(async (position) => {
return await this.createClaimSwapFeeMethod({
owner,
position
});
})
)).flat();
const claimAllLMTxs = (await Promise.all(
positions.map(async (position) => {
return await this.createClaimBuildMethod({
owner,
position
});
})
)).flat();
const transactions = chunks(
[...claimAllSwapFeeTxs, ...claimAllLMTxs],
MAX_CLAIM_ALL_ALLOWED
);
const { blockhash, lastValidBlockHeight } = await this.program.provider.connection.getLatestBlockhash("confirmed");
return Promise.all(
transactions.map(async (txs) => {
const instructions = txs.flatMap((i) => i.instructions);
const setCUIx = await getEstimatedComputeUnitIxWithBuffer(
this.program.provider.connection,
instructions,
owner
);
const transaction = new (0, _web3js.Transaction)({
feePayer: owner,
blockhash,
lastValidBlockHeight
}).add(setCUIx, ...instructions);
return transaction;
})
);
}
canSyncWithMarketPrice(marketPrice, activeBinId) {
const marketPriceBinId = this.getBinIdFromPrice(
Number(
DLMM.getPricePerLamport(
this.tokenX.mint.decimals,
this.tokenY.mint.decimals,
marketPrice
)
),
false
);
const marketPriceBinArrayIndex = binIdToBinArrayIndex(
new (0, _anchor.BN)(marketPriceBinId)
);
const swapForY = marketPriceBinId < activeBinId;
const toBinArrayIndex = findNextBinArrayIndexWithLiquidity(
swapForY,
new (0, _anchor.BN)(activeBinId),
this.lbPair,
_nullishCoalesce(_optionalChain([this, 'access', _166 => _166.binArrayBitmapExtension, 'optionalAccess', _167 => _167.account]), () => ( null))
);
if (toBinArrayIndex === null)
return true;
return swapForY ? marketPriceBinArrayIndex.gt(toBinArrayIndex) : marketPriceBinArrayIndex.lt(toBinArrayIndex);
}
/**
* The `syncWithMarketPrice` function is used to sync the liquidity pool with the market price.
* @param
* - `marketPrice`: The market price to sync with.
* - `owner`: The public key of the owner of the liquidity pool.
* @returns {Promise<Transaction>}
*/
async syncWithMarketPrice(marketPrice, owner) {
const marketPriceBinId = this.getBinIdFromPrice(
Number(
DLMM.getPricePerLamport(
this.tokenX.mint.decimals,
this.tokenY.mint.decimals,
marketPrice
)
),
false
);
const activeBin = await this.getActiveBin();
const activeBinId = activeBin.binId;
if (!this.canSyncWithMarketPrice(marketPrice, activeBinId)) {
throw new Error(
"Unable to sync with market price due to bin with liquidity between current and market price bin"
);
}
const fromBinArrayIndex = binIdToBinArrayIndex(new (0, _anchor.BN)(activeBinId));
const swapForY = marketPriceBinId < activeBinId;
const toBinArrayIndex = findNextBinArrayIndexWithLiquidity(
swapForY,
new (0, _anchor.BN)(activeBinId),
this.lbPair,
_nullishCoalesce(_optionalChain([this, 'access', _168 => _168.binArrayBitmapExtension, 'optionalAccess', _169 => _169.account]), () => ( null))
);
const marketPriceBinArrayIndex = binIdToBinArrayIndex(
new (0, _anchor.BN)(marketPriceBinId)
);
const accountsToFetch = [];
const binArrayBitMapExtensionPubkey = isOverflowDefaultBinArrayBitmap(
new (0, _anchor.BN)(marketPriceBinArrayIndex)
) ? deriveBinArrayBitmapExtension(this.pubkey, this.program.programId)[0] : null;
binArrayBitMapExtensionPubkey && accountsToFetch.push(binArrayBitMapExtensionPubkey);
const [fromBinArrayPubkey] = deriveBinArray(
this.pubkey,
fromBinArrayIndex,
this.program.programId
);
accountsToFetch.push(fromBinArrayPubkey);
const toBinArrayPubkey = (() => {
if (!toBinArrayIndex)
return null;
const [toBinArrayPubkey2] = deriveBinArray(
this.pubkey,
toBinArrayIndex,
this.program.programId
);
accountsToFetch.push(toBinArrayPubkey2);
return toBinArrayPubkey2;
})();
const binArrayAccounts = await this.program.provider.connection.getMultipleAccountsInfo(
accountsToFetch
);
const preInstructions = [];
let fromBinArray = null;
let toBinArray = null;
let binArrayBitmapExtension = null;
if (binArrayBitMapExtensionPubkey) {
binArrayBitmapExtension = binArrayBitMapExtensionPubkey;
if (!_optionalChain([binArrayAccounts, 'optionalAccess', _170 => _170[0]])) {
const initializeBitmapExtensionIx = await this.program.methods.initializeBinArrayBitmapExtension().accountsPartial({
binArrayBitmapExtension: binArrayBitMapExtensionPubkey,
funder: owner,
lbPair: this.pubkey,
rent: _web3js.SYSVAR_RENT_PUBKEY
}).instruction();
preInstructions.push(initializeBitmapExtensionIx);
}
}
if (!!_optionalChain([binArrayAccounts, 'optionalAccess', _171 => _171[1]])) {
fromBinArray = fromBinArrayPubkey;
}
if (!!_optionalChain([binArrayAccounts, 'optionalAccess', _172 => _172[2]]) && !!toBinArrayIndex) {
toBinArray = toBinArrayPubkey;
}
const { blockhash, lastValidBlockHeight } = await this.program.provider.connection.getLatestBlockhash("confirmed");
const syncWithMarketPriceTx = await this.program.methods.goToABin(marketPriceBinId).accountsPartial({
lbPair: this.pubkey,
binArrayBitmapExtension,
fromBinArray,
toBinArray
}).preInstructions(preInstructions).transaction();
return new (0, _web3js.Transaction)({
feePayer: owner,
blockhash,
lastValidBlockHeight
}).add(syncWithMarketPriceTx);
}
async getMaxPriceInBinArrays(binArrayAccounts) {
const sortedBinArrays = [...binArrayAccounts].sort(
({ account: { index: indexA } }, { account: { index: indexB } }) => indexA.toNumber() - indexB.toNumber()
);
let count = sortedBinArrays.length - 1;
let binPriceWithLastLiquidity;
while (count >= 0) {
const binArray = sortedBinArrays[count];
if (binArray) {
const bins = binArray.account.bins;
if (bins.every(({ amountX }) => amountX.isZero())) {
count--;
} else {
const lastBinWithLiquidityIndex = bins.findLastIndex(
({ amountX }) => !amountX.isZero()
);
binPriceWithLastLiquidity = bins[lastBinWithLiquidityIndex].price.toString();
count = -1;
}
}
}
return this.fromPricePerLamport(
Number(binPriceWithLastLiquidity) / (2 ** 64 - 1)
);
}
/**
*
* @param swapInitiator Address of the swap initiator
* @returns
*/
isSwapDisabled(swapInitiator) {
if (this.lbPair.status == 1 /* Disabled */) {
return true;
}
if (this.lbPair.pairType == 1 /* Permissioned */ || this.lbPair.pairType == 2 /* CustomizablePermissionless */) {
const currentPoint = this.lbPair.activationType == 0 /* Slot */ ? this.clock.slot : this.clock.unixTimestamp;
const preActivationSwapPoint = this.lbPair.activationPoint.sub(
this.lbPair.preActivationDuration
);
const activationPoint = !this.lbPair.preActivationSwapAddress.equals(_web3js.PublicKey.default) && this.lbPair.preActivationSwapAddress.equals(swapInitiator) ? preActivationSwapPoint : this.lbPair.activationPoint;
if (currentPoint < activationPoint) {
return true;
}
}
return false;
}
/**
* Decrease the length of a position. The segment of the position to be decreased must be empty.
*
* @param position The public key of the position to decrease.
* @param side The side of the position to decrease.
* @param length The amount of length to decrease.
* @param allowParallelExecution If true, the instructions will be grouped to allow parallel execution. Otherwise, the instructions will be executed sequentially.
* @returns An array of transactions if allowParallelExecution is true. Otherwise, an empty array.
*/
async decreasePositionLength(position, side, length, allowParallelExecution = true) {
const positionAccount = await this.program.provider.connection.getAccountInfo(position);
const positionState = wrapPosition(this.program, position, positionAccount);
const newWidth = positionState.width().sub(length);
if (newWidth.lte(new (0, _anchor.BN)(0))) {
length = length.sub(newWidth.abs()).subn(1);
}
const groupedIxs = [];
const promises = [];
for (let i = length.toNumber(); i > 0; i -= MAX_RESIZE_LENGTH.toNumber()) {
const lengthToReduce = Math.min(i, MAX_RESIZE_LENGTH.toNumber());
const setCuIx = _web3js.ComputeBudgetProgram.setComputeUnitLimit({
units: getDefaultExtendPositionCU(side)
});
const ixPromise = this.program.methods.decreasePositionLength(lengthToReduce, Number(side)).accountsPartial({
position,
owner: positionState.owner(),
rentReceiver: positionState.owner()
}).instruction().then((decreasePositionLengthIx) => {
if (allowParallelExecution) {
decreasePositionLengthIx.keys.push({
isSigner: false,
isWritable: false,
pubkey: _web3js.PublicKey.unique()
});
}
const ixs = [setCuIx, decreasePositionLengthIx];
groupedIxs.push(ixs);
});
promises.push(ixPromise);
}
await Promise.all(promises);
if (groupedIxs.length > 0) {
const { blockhash, lastValidBlockHeight } = await this.program.provider.connection.getLatestBlockhash("confirmed");
return groupedIxs.map((ixs) => {
return new (0, _web3js.Transaction)({
feePayer: positionState.owner(),
blockhash,
lastValidBlockHeight
}).add(...ixs);
});
}
}
/**
* Expand the position bin range to the left or right (lower or upper).
*
* @param position The address of the position to increase the length of.
* @param side The side of the position to increase the length of. Must be either
* ResizeSide.Lower or ResizeSide.Upper.
* @param length The number of bins to increase the length of. Position length after increase must be <= 1400.
* @param funder The address to account rental and transaction fee.
* @param allowParallelExecution Whether to allow parallel execution of the transaction.
* @returns The transaction to execute this instruction.
*/
async increasePositionLength(position, side, length, funder, allowParallelExecution = true) {
const positionAccount = await this.program.provider.connection.getAccountInfo(position);
const positionState = wrapPosition(this.program, position, positionAccount);
const newWidth = positionState.width().add(length);
if (newWidth.gt(POSITION_MAX_LENGTH)) {
length = newWidth.sub(POSITION_MAX_LENGTH);
}
const groupedIxs = await this.increasePositionLengthIxs(
position,
side,
length,
funder,
positionState.owner(),
true,
allowParallelExecution
);
if (groupedIxs.length > 0) {
const { blockhash, lastValidBlockHeight } = await this.program.provider.connection.getLatestBlockhash("confirmed");
return groupedIxs.map((ixs) => {
return new (0, _web3js.Transaction)({
feePayer: funder,
blockhash,
lastValidBlockHeight
}).add(...ixs);
});
}
}
async simulateRebalancePositionWithBalancedStrategy(positionAddress, positionData, strategy, topUpAmountX, topUpAmountY, xWithdrawBps, yWithdrawBps) {
const rebalancePosition = await RebalancePosition.create({
program: this.program,
positionAddress,
positionData,
shouldClaimFee: true,
shouldClaimReward: true,
pairAddress: this.pubkey
});
const rebalanceStrategyBuilder = new BalancedStrategyBuilder(
new (0, _anchor.BN)(rebalancePosition.lbPair.activeId),
new (0, _anchor.BN)(rebalancePosition.lbPair.binStep),
positionData,
topUpAmountX,
topUpAmountY,
xWithdrawBps,
yWithdrawBps,
strategy
);
return this.simulateRebalancePositionWithStrategy(
rebalancePosition,
rebalanceStrategyBuilder
);
}
async simulateRebalancePositionWithStrategy(rebalancePosition, rebalanceStrategy) {
const { deposits, withdraws } = rebalanceStrategy.buildRebalanceStrategyParameters();
const simulationResult = await rebalancePosition.simulateRebalance(
this.program.provider.connection,
new (0, _anchor.BN)(this.lbPair.binStep),
new (0, _anchor.BN)(this.tokenX.mint.decimals),
new (0, _anchor.BN)(this.tokenY.mint.decimals),
withdraws,
deposits
);
const binArrayQuoteResult = await this.quoteBinArrayAccountsRentalCost(
simulationResult.depositParams,
simulationResult.withdrawParams,
new (0, _anchor.BN)(rebalancePosition.lbPair.activeId)
);
return {
rebalancePosition,
simulationResult,
...binArrayQuoteResult
};
}
async quoteBinArrayAccountsRentalCost(deposits, withdraws, activeId) {
const { binArrayBitmap, binArrayIndexes } = getRebalanceBinArrayIndexesAndBitmapCoverage(
deposits,
withdraws,
activeId.toNumber(),
this.pubkey,
this.program.programId
);
const binArrayPublicKeys = binArrayIndexes.map((index) => {
const [binArrayPubkey] = deriveBinArray(
this.pubkey,
index,
this.program.programId
);
return binArrayPubkey;
});
const accountPublicKeys = [...binArrayPublicKeys];
if (!binArrayBitmap.equals(_web3js.PublicKey.default)) {
accountPublicKeys.push(binArrayBitmap);
}
const accounts = await chunkedGetMultipleAccountInfos(
this.program.provider.connection,
binArrayPublicKeys
);
const binArrayAccounts = accounts.splice(0, binArrayPublicKeys.length);
let binArrayCount = 0;
let bitmapExtensionCost = 0;
const binArraySet = /* @__PURE__ */ new Set();
for (let i = 0; i < binArrayAccounts.length; i++) {
const binArrayAccount = binArrayAccounts[i];
const binArrayPubkey = binArrayPublicKeys[i];
if (!binArrayAccount) {
binArrayCount++;
} else {
binArraySet.add(binArrayPubkey.toBase58());
}
}
if (!binArrayBitmap.equals(_web3js.PublicKey.default)) {
const bitmapAccount = accounts.pop();
if (!bitmapAccount) {
bitmapExtensionCost = BIN_ARRAY_BITMAP_FEE;
}
}
return {
binArrayCost: binArrayCount * BIN_ARRAY_FEE,
binArrayCount,
binArrayExistence: binArraySet,
bitmapExtensionCost
};
}
/**
* Simulates a rebalance operation on a position without actually executing it. It's recommended to use simulateRebalancePositionWithXStrategy instead unless you know what you're doing.
*
* @param positionAddress The address of the position to simulate rebalancing.
* @param positionData The PositionData object associated with the position.
* @param shouldClaimFee True if the fee should be claimed during rebalancing.
* @param shouldClaimReward True if the reward should be claimed during rebalancing.
* @param deposits An array of RebalanceWithDeposit objects representing the deposits to simulate.
* @param withdraws An array of RebalanceWithWithdraw objects representing the withdraws to simulate.
*/
async simulateRebalancePosition(positionAddress, positionData, shouldClaimFee, shouldClaimReward, deposits, withdraws) {
const rebalancePosition = await RebalancePosition.create({
program: this.program,
positionAddress,
positionData,
shouldClaimFee,
shouldClaimReward,
pairAddress: this.pubkey
});
const simulationResult = await rebalancePosition.simulateRebalance(
this.program.provider.connection,
new (0, _anchor.BN)(this.lbPair.binStep),
new (0, _anchor.BN)(this.tokenX.mint.decimals),
new (0, _anchor.BN)(this.tokenY.mint.decimals),
withdraws,
deposits
);
const binArrayQuoteResult = await this.quoteBinArrayAccountsRentalCost(
simulationResult.depositParams,
simulationResult.withdrawParams,
new (0, _anchor.BN)(rebalancePosition.lbPair.activeId)
);
return {
rebalancePosition,
simulationResult,
...binArrayQuoteResult
};
}
/**
* Rebalances a position and claim rewards if specified.
*
* @param rebalancePositionResponse The result of `simulateRebalancePosition`.
* @param maxActiveBinSlippage The maximum slippage allowed for active bin selection.
* @param slippage The slippage tolerance percentage for rebalncing.
*
* @returns An object containing the instructions to initialize new bin arrays and the instruction to rebalance the position.
*/
async rebalancePosition(rebalancePositionResponse, maxActiveBinSlippage, rentPayer, slippage = 100) {
const { rebalancePosition, simulationResult } = rebalancePositionResponse;
const { lbPair, shouldClaimFee, shouldClaimReward, owner, address } = rebalancePosition;
const { depositParams, withdrawParams } = simulationResult;
const activeId = new (0, _anchor.BN)(lbPair.activeId);
const { slices, accounts: transferHookAccounts } = this.getPotentialToken2022IxDataAndAccounts(0 /* Liquidity */);
const preInstructions = [];
const harvestRewardRemainingAccountMetas = [];
if (shouldClaimReward) {
for (const [idx, reward] of this.lbPair.rewardInfos.entries()) {
if (!reward.mint.equals(_web3js.PublicKey.default)) {
const rewardTokenInfo = this.rewards[idx];
slices.push({
accountsType: {
transferHookMultiReward: {
0: idx
}
},
length: rewardTokenInfo.transferHookAccountMetas.length
});
transferHookAccounts.push(
...rewardTokenInfo.transferHookAccountMetas
);
const userTokenRewardAddress = _spltoken.getAssociatedTokenAddressSync.call(void 0,
reward.mint,
owner,
true,
rewardTokenInfo.owner
);
preInstructions.push(
_spltoken.createAssociatedTokenAccountIdempotentInstruction.call(void 0,
owner,
userTokenRewardAddress,
owner,
reward.mint,
rewardTokenInfo.owner
)
);
const rewardVault = {
pubkey: reward.vault,
isSigner: false,
isWritable: true
};
const userTokenReward = {
pubkey: userTokenRewardAddress,
isSigner: false,
isWritable: true
};
const rewardMint = {
pubkey: reward.mint,
isSigner: false,
isWritable: false
};
const rewardTokenProgram = {
pubkey: rewardTokenInfo.owner,
isSigner: false,
isWritable: false
};
harvestRewardRemainingAccountMetas.push(
rewardVault,
userTokenReward,
rewardMint,
rewardTokenProgram
);
}
}
}
const initBinArrayInstructions = [];
const { binArrayBitmap, binArrayIndexes } = getRebalanceBinArrayIndexesAndBitmapCoverage(
depositParams,
withdrawParams,
activeId.toNumber(),
this.pubkey,
this.program.programId
);
const binArrayPublicKeys = binArrayIndexes.map((index) => {
const [binArrayPubkey] = deriveBinArray(
this.pubkey,
index,
this.program.programId
);
return binArrayPubkey;
});
const binArrayAccounts = await chunkedGetMultipleAccountInfos(
this.program.provider.connection,
binArrayPublicKeys
);
for (let i = 0; i < binArrayAccounts.length; i++) {
const binArrayAccount = binArrayAccounts[i];
if (!binArrayAccount) {
const binArrayPubkey = binArrayPublicKeys[i];
const binArrayIndex = binArrayIndexes[i];
const initBinArrayIx = await this.program.methods.initializeBinArray(binArrayIndex).accountsPartial({
binArray: binArrayPubkey,
funder: owner,
lbPair: this.pubkey
}).instruction();
initBinArrayInstructions.push(initBinArrayIx);
}
}
if (!binArrayBitmap.equals(_web3js.PublicKey.default)) {
const bitmapAccount = await this.program.provider.connection.getAccountInfo(binArrayBitmap);
if (!bitmapAccount) {
const initBitmapExtensionIx = await this.program.methods.initializeBinArrayBitmapExtension().accountsPartial({
binArrayBitmapExtension: binArrayBitmap,
funder: owner,
lbPair: this.pubkey,
rent: _web3js.SYSVAR_RENT_PUBKEY
}).preInstructions([
_web3js.ComputeBudgetProgram.setComputeUnitLimit({
units: DEFAULT_INIT_BIN_ARRAY_CU
})
]).instruction();
preInstructions.push(initBitmapExtensionIx);
}
}
const [
{ ataPubKey: userTokenX, ix: createUserTokenXIx },
{ ataPubKey: userTokenY, ix: createUserTokenYIx }
] = await Promise.all([
getOrCreateATAInstruction(
this.program.provider.connection,
this.tokenX.publicKey,
owner,
this.tokenX.owner
),
getOrCreateATAInstruction(
this.program.provider.connection,
this.tokenY.publicKey,
owner,
this.tokenY.owner
)
]);
createUserTokenXIx && preInstructions.push(createUserTokenXIx);
createUserTokenYIx && preInstructions.push(createUserTokenYIx);
slippage = capSlippagePercentage(slippage);
const maxDepositXAmount = getSlippageMaxAmount(
simulationResult.actualAmountXDeposited,
slippage
);
const maxDepositYAmount = getSlippageMaxAmount(
simulationResult.actualAmountYDeposited,
slippage
);
const minWithdrawXAmount = getSlippageMinAmount(
simulationResult.actualAmountXWithdrawn,
slippage
);
const minWithdrawYAmount = getSlippageMinAmount(
simulationResult.actualAmountYWithdrawn,
slippage
);
const postInstructions = [];
if (this.tokenX.publicKey.equals(_spltoken.NATIVE_MINT) && simulationResult.actualAmountXDeposited.gtn(0) && !_optionalChain([this, 'access', _173 => _173.opt, 'optionalAccess', _174 => _174.skipSolWrappingOperation])) {
const wrapSOLIx = wrapSOLInstruction(
owner,
userTokenX,
BigInt(simulationResult.actualAmountXDeposited.toString())
);
preInstructions.push(...wrapSOLIx);
}
if (this.tokenY.publicKey.equals(_spltoken.NATIVE_MINT) && simulationResult.actualAmountYDeposited.gtn(0) && !_optionalChain([this, 'access', _175 => _175.opt, 'optionalAccess', _176 => _176.skipSolWrappingOperation])) {
const wrapSOLIx = wrapSOLInstruction(
owner,
userTokenY,
BigInt(simulationResult.actualAmountYDeposited.toString())
);
preInstructions.push(...wrapSOLIx);
}
if ((this.tokenX.publicKey.equals(_spltoken.NATIVE_MINT) || this.tokenY.publicKey.equals(_spltoken.NATIVE_MINT)) && !_optionalChain([this, 'access', _177 => _177.opt, 'optionalAccess', _178 => _178.skipSolWrappingOperation])) {
const closeWrappedSOLIx = await unwrapSOLInstruction(owner);
closeWrappedSOLIx && postInstructions.push(closeWrappedSOLIx);
}
const instruction = await this.program.methods.rebalanceLiquidity(
{
adds: depositParams,
removes: withdrawParams,
activeId: activeId.toNumber(),
shouldClaimFee,
shouldClaimReward,
maxActiveBinSlippage: maxActiveBinSlippage.toNumber(),
maxDepositXAmount,
maxDepositYAmount,
minWithdrawXAmount,
minWithdrawYAmount,
shrinkMode: 0 /* ShrinkBoth */,
padding: REBALANCE_POSITION_PADDING
},
{
slices
}
).accountsPartial({
lbPair: this.pubkey,
binArrayBitmapExtension: binArrayBitmap,
position: address,
owner,
userTokenX,
userTokenY,
reserveX: this.lbPair.reserveX,
reserveY: this.lbPair.reserveY,
tokenXMint: this.tokenX.publicKey,
tokenYMint: this.tokenY.publicKey,
tokenXProgram: this.tokenX.owner,
tokenYProgram: this.tokenY.owner,
memoProgram: MEMO_PROGRAM_ID,
rentPayer: _nullishCoalesce(rentPayer, () => ( owner))
}).remainingAccounts(transferHookAccounts).remainingAccounts(
binArrayPublicKeys.map((pubkey) => {
return {
pubkey,
isSigner: false,
isWritable: true
};
})
).instruction();
const setCUIX = await getEstimatedComputeUnitIxWithBuffer(
this.program.provider.connection,
[instruction],
owner
);
const rebalancePositionInstruction = [
setCUIX,
...preInstructions,
instruction,
...postInstructions
];
return {
initBinArrayInstructions,
rebalancePositionInstruction
};
}
/**
* Create an extended empty position.
*
* @param lowerBinid The lowest bin of the position.
* @param upperBinId The highest bin of the position.
* @param position The public key of the position.
* @param owner The owner of the position.
* @returns The instructions to create the extended empty position.
*/
async createExtendedEmptyPosition(lowerBinid, upperBinId, position, owner) {
const positionWidth = upperBinId - lowerBinid + 1;
const basePositionWidth = Math.min(
positionWidth,
DEFAULT_BIN_PER_POSITION.toNumber()
);
const ixs = await this.createInitAndExtendPositionIx(
lowerBinid,
upperBinId,
basePositionWidth,
owner,
position
);
const latestBlockhashInfo = await this.program.provider.connection.getLatestBlockhash();
const tx = new (0, _web3js.Transaction)({
...latestBlockhashInfo,
feePayer: owner
}).add(...ixs);
return tx;
}
/**
* Enables permissionless fee claiming for a position.
* @param
* - `position`: The public key of the position account.
* - `owner`: The public key of the position owner.
* @returns {Promise<Transaction>} A transaction that sets the position permission bit for fee claiming.
*/
async enablePositionPermissionlessClaimFee({
position,
owner
}) {
const enablePositionPermissionlessClaimFeeIx = await this.program.methods.setPermissionlessOperationBits(
encodePositionPermissions([0 /* ClaimFee */])
).accountsPartial({
position,
owner
}).instruction();
const latestBlockhashInfo = await this.program.provider.connection.getLatestBlockhash();
const tx = new (0, _web3js.Transaction)({
...latestBlockhashInfo,
feePayer: owner
}).add(enablePositionPermissionlessClaimFeeIx);
return tx;
}
/**
* Creates a limit-order transaction for this LB pair.
* When `relativeBin` is provided, the `bin.id` in `params.bins` will be treated as relative to the current active bin, which mean bin.id = bin.id + activeId. Otherwise, it will be absolute bin id.
*
*
* @param params Input parameters for placing a limit order.
* @param params.owner Owner of the token account used by the order.
* @param params.payer Account paying rent for any newly created accounts.
* @param params.sender Transaction signer that submits the order.
* @param params.limitOrder PDA/public key of the limit-order account.
* @param params.params Limit-order configuration. `padding` is injected by the SDK.
* @returns A transaction that places the limit order.
*/
async placeLimitOrder({
owner,
payer,
sender,
limitOrder,
params
}) {
const isAskSide = Boolean(params.isAskSide);
const resolvedBinIds = params.bins.map(
(bin) => params.relativeBin == null ? bin.id : bin.id + this.lbPair.activeId
);
const { binArrayIndexes, binArrayAccountMetas, binArrayBitmapExtension } = getBinArrayInfoForNonContiguousBinIds(
resolvedBinIds,
this.program.programId,
this.pubkey
);
const createBinArrayIxs = await this.createBinArraysIfNeeded(
binArrayIndexes,
payer
);
const preInstructions = [...createBinArrayIxs];
const postInstructions = [];
if (!binArrayBitmapExtension.equals(this.program.programId) && !this.binArrayBitmapExtension) {
const initializeBitmapExtensionIx = await this.program.methods.initializeBinArrayBitmapExtension().accountsPartial({
binArrayBitmapExtension,
funder: owner,
lbPair: this.pubkey,
rent: _web3js.SYSVAR_RENT_PUBKEY
}).instruction();
preInstructions.push(initializeBitmapExtensionIx);
}
const [reserve, tokenMint, tokenProgram, slices, transferHookAccounts] = isAskSide ? [
this.lbPair.reserveX,
this.tokenX.mint.address,
this.tokenX.owner,
[
{
accountsType: {
transferHookX: {}
},
length: this.tokenX.transferHookAccountMetas.length
}
],
this.tokenX.transferHookAccountMetas
] : [
this.lbPair.reserveY,
this.tokenY.mint.address,
this.tokenY.owner,
[
{
accountsType: {
transferHookY: {}
},
length: this.tokenY.transferHookAccountMetas.length
}
],
this.tokenY.transferHookAccountMetas
];
const userTokenAddress = _spltoken.getAssociatedTokenAddressSync.call(void 0,
tokenMint,
owner,
true,
tokenProgram
);
if (tokenMint.equals(_spltoken.NATIVE_MINT) && !_optionalChain([this, 'access', _179 => _179.opt, 'optionalAccess', _180 => _180.skipSolWrappingOperation])) {
const totalAmount = params.bins.reduce(
(acc, { amount }) => acc.add(amount),
new (0, _anchor.BN)(0)
);
preInstructions.push(
_spltoken.createAssociatedTokenAccountIdempotentInstruction.call(void 0,
owner,
userTokenAddress,
owner,
_spltoken.NATIVE_MINT
)
);
const wrapSOLIxX = wrapSOLInstruction(
sender,
userTokenAddress,
BigInt(totalAmount.toString())
);
preInstructions.push(...wrapSOLIxX);
const unwrapSOLIX = unwrapSOLInstruction(sender, true);
postInstructions.push(unwrapSOLIX);
}
const placeLimitOrderIx = await this.program.methods.placeLimitOrder(
{
...params,
padding: new Array(16).fill(0)
},
{
slices
}
).accountsPartial({
lbPair: this.pubkey,
binArrayBitmapExtension,
reserve,
tokenMint,
tokenProgram,
limitOrder,
userToken: userTokenAddress,
sender,
payer,
owner
}).remainingAccounts([...transferHookAccounts, ...binArrayAccountMetas]).preInstructions(preInstructions).postInstructions(postInstructions).instruction();
const latestBlockhashInfo = await this.program.provider.connection.getLatestBlockhash();
const tx = new (0, _web3js.Transaction)({
...latestBlockhashInfo,
feePayer: sender
}).add(...preInstructions, placeLimitOrderIx, ...postInstructions);
return tx;
}
/**
* Cancels a limit order
* @param
* - `limitOrderPubkey`: The public key of the limit-order account to cancel.
* - `owner`: The owner of the limit-order account and transaction fee payer.
* - `binIds`: Bin IDs to cancel from the limit order.
* @returns {Promise<Transaction>} A transaction that cancels the limit order, ensures owner ATAs for both pool
* mints (including idempotent creates for non-SOL legs), and unwraps SOL when applicable.
*/
async cancelLimitOrder({
limitOrderPubkey,
owner,
rentReceiver,
binIds
}) {
const { slices, accounts: transferHookAccounts } = this.getPotentialToken2022IxDataAndAccounts(0 /* Liquidity */);
const { binArrayAccountMetas, binArrayBitmapExtension } = getBinArrayInfoForNonContiguousBinIds(
binIds,
this.program.programId,
this.pubkey
);
const preInstructions = [];
const postInstructions = [];
const userTokenX = _spltoken.getAssociatedTokenAddressSync.call(void 0,
this.tokenX.mint.address,
owner,
true,
this.tokenX.owner
);
const userTokenY = _spltoken.getAssociatedTokenAddressSync.call(void 0,
this.tokenY.mint.address,
owner,
true,
this.tokenY.owner
);
if (this.tokenX.mint.address.equals(_spltoken.NATIVE_MINT)) {
if (!_optionalChain([this, 'access', _181 => _181.opt, 'optionalAccess', _182 => _182.skipSolWrappingOperation])) {
preInstructions.push(
_spltoken.createAssociatedTokenAccountIdempotentInstruction.call(void 0,
owner,
userTokenX,
owner,
this.tokenX.mint.address,
this.tokenX.owner
)
);
postInstructions.push(unwrapSOLInstruction(owner));
}
} else {
preInstructions.push(
_spltoken.createAssociatedTokenAccountIdempotentInstruction.call(void 0,
owner,
userTokenX,
owner,
this.tokenX.mint.address,
this.tokenX.owner
)
);
}
if (this.tokenY.mint.address.equals(_spltoken.NATIVE_MINT)) {
if (!_optionalChain([this, 'access', _183 => _183.opt, 'optionalAccess', _184 => _184.skipSolWrappingOperation])) {
preInstructions.push(
_spltoken.createAssociatedTokenAccountIdempotentInstruction.call(void 0,
owner,
userTokenY,
owner,
this.tokenY.mint.address,
this.tokenY.owner
)
);
postInstructions.push(unwrapSOLInstruction(owner));
}
} else {
preInstructions.push(
_spltoken.createAssociatedTokenAccountIdempotentInstruction.call(void 0,
owner,
userTokenY,
owner,
this.tokenY.mint.address,
this.tokenY.owner
)
);
}
const closeLimitOrderIx = await this.program.methods.closeLimitOrderIfEmpty().accountsPartial({
limitOrder: limitOrderPubkey,
owner,
rentReceiver
}).instruction();
postInstructions.push(closeLimitOrderIx);
const cancelLimitOrderIx = await this.program.methods.cancelLimitOrder(binIds, {
slices
}).accountsPartial({
lbPair: this.pubkey,
reserveX: this.lbPair.reserveX,
reserveY: this.lbPair.reserveY,
binArrayBitmapExtension,
tokenXMint: this.tokenX.mint.address,
tokenYMint: this.tokenY.mint.address,
limitOrder: limitOrderPubkey,
ownerTokenX: userTokenX,
ownerTokenY: userTokenY,
owner,
tokenXProgram: this.tokenX.owner,
tokenYProgram: this.tokenY.owner,
memoProgram: MEMO_PROGRAM_ID
}).remainingAccounts([...transferHookAccounts, ...binArrayAccountMetas]).instruction();
const latestBlockhashInfo = await this.program.provider.connection.getLatestBlockhash();
const tx = new (0, _web3js.Transaction)({
...latestBlockhashInfo,
feePayer: owner
}).add(...preInstructions, cancelLimitOrderIx, ...postInstructions);
return tx;
}
/**
* Closes a limit-order account if it has no remaining open bins.
* @param
* - `limitOrder`: The public key of the limit-order account to close.
* - `owner`: The owner of the limit-order account and transaction fee payer.
* - `rentReceiver`: The account that receives reclaimed rent from the closed limit-order account.
* @returns {Promise<Transaction>} A transaction that closes the limit-order account when it is empty.
*/
async closeLimitOrderIfEmpty({
limitOrder,
owner,
rentReceiver
}) {
const closeLimitOrderIx = await this.program.methods.closeLimitOrderIfEmpty().accountsPartial({
limitOrder,
owner,
rentReceiver
}).instruction();
const latestBlockhashInfo = await this.program.provider.connection.getLatestBlockhash();
const tx = new (0, _web3js.Transaction)({
...latestBlockhashInfo,
feePayer: owner
}).add(closeLimitOrderIx);
return tx;
}
async createInitAndExtendPositionIx(lowerBinId, upperBinId, basePositionWidth, user, position) {
const createPositionIx = await this.program.methods.initializePosition(lowerBinId, basePositionWidth).accountsPartial({
payer: user,
position,
lbPair: this.pubkey,
owner: user,
rent: _web3js.SYSVAR_RENT_PUBKEY
}).instruction();
const extendedBinCount = getExtendedPositionBinCount(
new (0, _anchor.BN)(lowerBinId),
new (0, _anchor.BN)(upperBinId)
);
if (extendedBinCount.gt(new (0, _anchor.BN)(0))) {
const extendPositionIxs = await this.increasePositionLengthIxs(
position,
1 /* Upper */,
extendedBinCount,
user,
user,
false,
false
);
const extendPositionDefaultCU = getDefaultExtendPositionCU(1 /* Upper */) * extendedBinCount.toNumber();
return [
_web3js.ComputeBudgetProgram.setComputeUnitLimit({
units: Math.min(
DEFAULT_INIT_POSITION_CU + extendPositionDefaultCU,
14e5
)
}),
createPositionIx,
...extendPositionIxs.flat()
];
} else {
return [
_web3js.ComputeBudgetProgram.setComputeUnitLimit({
units: DEFAULT_INIT_POSITION_CU
}),
createPositionIx
];
}
}
async increasePositionLengthIxs(position, side, length, funder, positionOwner, includeSetCuIx = true, allowParallelExecution = true) {
const groupedIxs = [];
const promises = [];
for (let i = 0; i < length.toNumber(); i += MAX_RESIZE_LENGTH.toNumber()) {
const lengthToAdd = Math.min(
length.toNumber() - i,
MAX_RESIZE_LENGTH.toNumber()
);
const setCuIx = _web3js.ComputeBudgetProgram.setComputeUnitLimit({
units: getDefaultExtendPositionCU(side)
});
const ixPromise = this.program.methods.increasePositionLength(lengthToAdd, Number(side)).accountsPartial({
lbPair: this.pubkey,
position,
owner: positionOwner,
funder
}).instruction().then((increasePositionLengthIx) => {
if (allowParallelExecution) {
increasePositionLengthIx.keys.push({
isSigner: false,
isWritable: false,
pubkey: _web3js.PublicKey.unique()
});
}
const ixs = [increasePositionLengthIx];
if (includeSetCuIx) {
ixs.unshift(setCuIx);
}
groupedIxs.push(ixs);
});
promises.push(ixPromise);
}
await Promise.all(promises);
return groupedIxs;
}
/** Private static method */
static async getBinArrays(program, lbPairPubkey) {
return program.account.binArray.all([binArrayLbPairFilter(lbPairPubkey)]);
}
static async processPosition(program, lbPair, clock, position, baseMint, quoteMint, rewardMint0, rewardMint1, binArrayMap) {
const lbPairKey = position.lbPair();
const lowerBinId = position.lowerBinId();
const upperBinId = position.upperBinId();
const posShares = position.liquidityShares();
const lastUpdatedAt = position.lastUpdatedAt();
const feeInfos = position.feeInfos();
const totalClaimedFeeXAmount = position.totalClaimedFeeXAmount();
const totalClaimedFeeYAmount = position.totalClaimedFeeYAmount();
const positionRewardInfos = position.rewardInfos();
const feeOwner = position.feeOwner();
const bins = this.getBinsBetweenLowerAndUpperBound(
lbPairKey,
lbPair,
lowerBinId.toNumber(),
upperBinId.toNumber(),
baseMint.decimals,
quoteMint.decimals,
binArrayMap,
program.programId
);
if (!bins.length)
return null;
const positionData = [];
let totalXAmount = new (0, _decimaljs2.default)(0);
let totalYAmount = new (0, _decimaljs2.default)(0);
const ZERO = new (0, _anchor.BN)(0);
let feeX = ZERO;
let feeY = ZERO;
let rewards = [ZERO, ZERO];
bins.forEach((bin, idx) => {
const binSupply = bin.supply;
const posShare = posShares[idx];
const posBinRewardInfo = positionRewardInfos[idx];
const positionXAmount = binSupply.eq(ZERO) ? ZERO : posShare.mul(bin.xAmount).div(binSupply);
const positionYAmount = binSupply.eq(ZERO) ? ZERO : posShare.mul(bin.yAmount).div(binSupply);
totalXAmount = totalXAmount.add(new (0, _decimaljs2.default)(positionXAmount.toString()));
totalYAmount = totalYAmount.add(new (0, _decimaljs2.default)(positionYAmount.toString()));
const feeInfo = feeInfos[idx];
const newFeeX = posShare.isZero() ? new (0, _anchor.BN)(0) : mulShr(
posShares[idx].shrn(SCALE_OFFSET),
bin.feeAmountXPerTokenStored.sub(feeInfo.feeXPerTokenComplete),
SCALE_OFFSET,
1 /* Down */
);
const newFeeY = posShare.isZero() ? new (0, _anchor.BN)(0) : mulShr(
posShares[idx].shrn(SCALE_OFFSET),
bin.feeAmountYPerTokenStored.sub(feeInfo.feeYPerTokenComplete),
SCALE_OFFSET,
1 /* Down */
);
const claimableFeeX = newFeeX.add(feeInfo.feeXPending);
const claimableFeeY = newFeeY.add(feeInfo.feeYPending);
feeX = feeX.add(claimableFeeX);
feeY = feeY.add(claimableFeeY);
const claimableRewardsInBin = [new (0, _anchor.BN)(0), new (0, _anchor.BN)(0)];
if (!isSupportLimitOrder(lbPair)) {
for (let j = 0; j < claimableRewardsInBin.length; j++) {
const pairRewardInfo = lbPair.rewardInfos[j];
if (!pairRewardInfo.mint.equals(_web3js.PublicKey.default)) {
let rewardPerTokenStored = bin.rewardPerTokenStored[j];
if (bin.binId == lbPair.activeId && !bin.supply.isZero()) {
const currentTime = new (0, _anchor.BN)(
Math.min(
clock.unixTimestamp.toNumber(),
pairRewardInfo.rewardDurationEnd.toNumber()
)
);
const delta2 = currentTime.sub(pairRewardInfo.lastUpdateTime);
const liquiditySupply = bin.supply.shrn(SCALE_OFFSET);
const rewardPerTokenStoredDelta = pairRewardInfo.rewardRate.mul(delta2).div(new (0, _anchor.BN)(15)).div(liquiditySupply);
rewardPerTokenStored = rewardPerTokenStored.add(
rewardPerTokenStoredDelta
);
}
const delta = rewardPerTokenStored.sub(
posBinRewardInfo.rewardPerTokenCompletes[j]
);
const newReward = posShares[idx].isZero() ? new (0, _anchor.BN)(0) : mulShr(
delta,
posShares[idx].shrn(SCALE_OFFSET),
SCALE_OFFSET,
1 /* Down */
);
const claimableReward = newReward.add(
posBinRewardInfo.rewardPendings[j]
);
claimableRewardsInBin[j] = claimableRewardsInBin[j].add(claimableReward);
rewards[j] = rewards[j].add(claimableReward);
}
}
}
positionData.push({
binId: bin.binId,
price: bin.price,
pricePerToken: bin.pricePerToken,
binXAmount: bin.xAmount.toString(),
binYAmount: bin.yAmount.toString(),
binLiquidity: binSupply.toString(),
positionLiquidity: posShare.toString(),
positionXAmount: positionXAmount.toString(),
positionYAmount: positionYAmount.toString(),
positionFeeXAmount: claimableFeeX.toString(),
positionFeeYAmount: claimableFeeY.toString(),
positionRewardAmount: claimableRewardsInBin.map(
(amount) => amount.toString()
)
});
});
const currentEpoch = clock.epoch.toNumber();
const feeXExcludeTransferFee = calculateTransferFeeExcludedAmount(
feeX,
baseMint,
currentEpoch
).amount;
const feeYExcludeTransferFee = calculateTransferFeeExcludedAmount(
feeY,
quoteMint,
currentEpoch
).amount;
const rewardOne = rewards[0];
const rewardTwo = rewards[1];
let rewardOneExcludeTransferFee = new (0, _anchor.BN)(0);
let rewardTwoExcludeTransferFee = new (0, _anchor.BN)(0);
if (rewardMint0) {
rewardOneExcludeTransferFee = calculateTransferFeeExcludedAmount(
rewardOne,
rewardMint0,
currentEpoch
).amount;
}
if (rewardMint1) {
rewardTwoExcludeTransferFee = calculateTransferFeeExcludedAmount(
rewardTwo,
rewardMint1,
currentEpoch
).amount;
}
const totalXAmountExcludeTransferFee = calculateTransferFeeExcludedAmount(
new (0, _anchor.BN)(totalXAmount.floor().toString()),
baseMint,
currentEpoch
).amount;
const totalYAmountExcludeTransferFee = calculateTransferFeeExcludedAmount(
new (0, _anchor.BN)(totalYAmount.floor().toString()),
quoteMint,
currentEpoch
).amount;
return {
totalXAmount: totalXAmount.toString(),
totalYAmount: totalYAmount.toString(),
positionBinData: positionData,
lastUpdatedAt,
lowerBinId: lowerBinId.toNumber(),
upperBinId: upperBinId.toNumber(),
feeX,
feeY,
rewardOne,
rewardTwo,
feeOwner,
totalClaimedFeeXAmount,
totalClaimedFeeYAmount,
totalXAmountExcludeTransferFee,
totalYAmountExcludeTransferFee,
rewardOneExcludeTransferFee,
rewardTwoExcludeTransferFee,
feeXExcludeTransferFee,
feeYExcludeTransferFee,
owner: position.owner()
};
}
static getBinsBetweenLowerAndUpperBound(lbPairKey, lbPair, lowerBinId, upperBinId, baseTokenDecimal, quoteTokenDecimal, binArrayMap, programId) {
const lowerBinArrayIndex = binIdToBinArrayIndex(new (0, _anchor.BN)(lowerBinId));
const upperBinArrayIndex = binIdToBinArrayIndex(new (0, _anchor.BN)(upperBinId));
let bins = [];
for (let binArrayIndex = lowerBinArrayIndex.toNumber(); binArrayIndex <= upperBinArrayIndex.toNumber(); binArrayIndex++) {
const binArrayIndexBN = new (0, _anchor.BN)(binArrayIndex);
const binArrayKey = deriveBinArray(
lbPairKey,
binArrayIndexBN,
programId
)[0];
const [lowerBinIdForBinArray] = getBinArrayLowerUpperBinId(binArrayIndexBN);
const binArray = binArrayMap.get(binArrayKey.toBase58());
for (let i = 0; i < MAX_BIN_ARRAY_SIZE.toNumber(); i++) {
const binId = lowerBinIdForBinArray.toNumber() + i;
if (binId >= lowerBinId && binId <= upperBinId) {
if (!binArray) {
bins.push(
BinLiquidity.empty(
binId,
lbPair.binStep,
baseTokenDecimal,
quoteTokenDecimal,
BIN_ARRAY_DEFAULT_VERSION
)
);
} else {
const bin = binArray.bins[i];
bins.push(
BinLiquidity.fromBin(
bin,
binId,
lbPair.binStep,
baseTokenDecimal,
quoteTokenDecimal,
binArray.version,
lbPair
)
);
}
}
}
}
return bins;
}
/** Private method */
processXYAmountDistribution(xYAmountDistribution) {
let currentBinId = null;
const xAmountDistribution = [];
const yAmountDistribution = [];
const binIds = [];
xYAmountDistribution.forEach((binAndAmount) => {
xAmountDistribution.push(binAndAmount.xAmountBpsOfTotal);
yAmountDistribution.push(binAndAmount.yAmountBpsOfTotal);
binIds.push(binAndAmount.binId);
if (currentBinId && binAndAmount.binId !== currentBinId + 1) {
throw new Error("Discontinuous Bin ID");
} else {
currentBinId = binAndAmount.binId;
}
});
return {
lowerBinId: xYAmountDistribution[0].binId,
upperBinId: xYAmountDistribution[xYAmountDistribution.length - 1].binId,
xAmountDistribution,
yAmountDistribution,
binIds
};
}
async getBins(lbPairPubKey, lowerBinId, upperBinId, baseTokenDecimal, quoteTokenDecimal, lowerBinArray, upperBinArray) {
const lowerBinArrayIndex = binIdToBinArrayIndex(new (0, _anchor.BN)(lowerBinId));
const upperBinArrayIndex = binIdToBinArrayIndex(new (0, _anchor.BN)(upperBinId));
const hasCachedLowerBinArray = lowerBinArray != null;
const hasCachedUpperBinArray = upperBinArray != null;
const isSingleBinArray = lowerBinArrayIndex.eq(upperBinArrayIndex);
const lowerBinArrayIndexOffset = hasCachedLowerBinArray ? 1 : 0;
const upperBinArrayIndexOffset = hasCachedUpperBinArray ? -1 : 0;
const binArrayPubkeys = range(
lowerBinArrayIndex.toNumber() + lowerBinArrayIndexOffset,
upperBinArrayIndex.toNumber() + upperBinArrayIndexOffset,
(i) => deriveBinArray(lbPairPubKey, new (0, _anchor.BN)(i), this.program.programId)[0]
);
const fetchedBinArrays = binArrayPubkeys.length !== 0 ? await this.program.account.binArray.fetchMultiple(binArrayPubkeys) : [];
const binArrays = [
...hasCachedLowerBinArray ? [lowerBinArray] : [],
...fetchedBinArrays,
...hasCachedUpperBinArray && !isSingleBinArray ? [upperBinArray] : []
];
const binsById = new Map(
binArrays.filter((x) => x != null).flatMap(({ bins, index }) => {
const [lowerBinId2] = getBinArrayLowerUpperBinId(index);
return bins.map(
(b, i) => [lowerBinId2.toNumber() + i, b]
);
})
);
const version = _nullishCoalesce(_optionalChain([binArrays, 'access', _185 => _185.find, 'call', _186 => _186((binArray) => binArray != null), 'optionalAccess', _187 => _187.version]), () => ( 1));
return Array.from(
enumerateBins(
binsById,
lowerBinId,
upperBinId,
this.lbPair.binStep,
baseTokenDecimal,
quoteTokenDecimal,
version,
this.lbPair
)
);
}
async binArraysToBeCreate(lowerBinArrayIndex, upperBinArrayIndex) {
const binArrayIndexes = Array.from(
{ length: upperBinArrayIndex.sub(lowerBinArrayIndex).toNumber() + 1 },
(_, index) => index + lowerBinArrayIndex.toNumber()
).map((idx) => new (0, _anchor.BN)(idx));
const binArrays = [];
for (const idx of binArrayIndexes) {
const [binArrayPubKey] = deriveBinArray(
this.pubkey,
idx,
this.program.programId
);
binArrays.push(binArrayPubKey);
}
const binArrayAccounts = await this.program.provider.connection.getMultipleAccountsInfo(binArrays);
return binArrayAccounts.filter((binArray) => binArray === null).map((_, index) => binArrays[index]);
}
async createBinArraysIfNeeded(binArrayIndexes, funder) {
const ixs = [];
for (const idx of binArrayIndexes) {
const [binArrayKey] = deriveBinArray(
this.pubkey,
idx,
this.program.programId
);
const binArrayAccount = await this.program.provider.connection.getAccountInfo(binArrayKey);
if (binArrayAccount === null) {
ixs.push(
await this.program.methods.initializeBinArray(idx).accountsPartial({
binArray: binArrayKey,
funder,
lbPair: this.pubkey
}).instruction()
);
}
}
return ixs;
}
static updateVolatilityAccumulator(vParameter, sParameter, activeId) {
const deltaId = Math.abs(vParameter.indexReference - activeId);
const newVolatilityAccumulator = vParameter.volatilityReference + deltaId * BASIS_POINT_MAX;
vParameter.volatilityAccumulator = Math.min(
newVolatilityAccumulator,
sParameter.maxVolatilityAccumulator
);
}
static updateReference(activeId, vParameter, sParameter, currentTimestamp) {
const elapsed = currentTimestamp - vParameter.lastUpdateTimestamp.toNumber();
if (elapsed >= sParameter.filterPeriod) {
vParameter.indexReference = activeId;
if (elapsed < sParameter.decayPeriod) {
const decayedVolatilityReference = Math.floor(
vParameter.volatilityAccumulator * sParameter.reductionFactor / BASIS_POINT_MAX
);
vParameter.volatilityReference = decayedVolatilityReference;
} else {
vParameter.volatilityReference = 0;
}
}
}
async createClaimBuildMethod({
owner,
position
}) {
const maybeClaimableBinRange = getPositionLowerUpperBinIdWithLiquidity(
position.positionData
);
if (!maybeClaimableBinRange)
return [];
const { lowerBinId, upperBinId } = maybeClaimableBinRange;
const chunkedBinRange = chunkBinRange(
lowerBinId.toNumber(),
upperBinId.toNumber()
);
const claimTransactions = [];
for (const {
lowerBinId: chunkedLowerBinId,
upperBinId: chunkedUpperBinId
} of chunkedBinRange) {
const binArrayAccountsMeta = getBinArrayAccountMetasCoverage(
new (0, _anchor.BN)(chunkedLowerBinId),
new (0, _anchor.BN)(chunkedUpperBinId),
this.pubkey,
this.program.programId
);
for (let i = 0; i < 2; i++) {
const rewardInfo = this.lbPair.rewardInfos[i];
if (!rewardInfo || rewardInfo.mint.equals(_web3js.PublicKey.default))
continue;
const preInstructions = [];
const userRewardToken = _spltoken.getAssociatedTokenAddressSync.call(void 0,
rewardInfo.mint,
owner,
true,
this.rewards[i].owner
);
const createUserTokenIx = _spltoken.createAssociatedTokenAccountIdempotentInstruction.call(void 0,
owner,
userRewardToken,
owner,
rewardInfo.mint,
this.rewards[i].owner
);
preInstructions.push(createUserTokenIx);
const { slices, accounts: transferHookAccounts } = this.getPotentialToken2022IxDataAndAccounts(1 /* Reward */, i);
const claimTransaction = await this.program.methods.claimReward2(new (0, _anchor.BN)(i), chunkedLowerBinId, chunkedUpperBinId, {
slices
}).accountsPartial({
lbPair: this.pubkey,
sender: owner,
position: position.publicKey,
rewardVault: rewardInfo.vault,
rewardMint: rewardInfo.mint,
tokenProgram: this.rewards[i].owner,
userTokenAccount: userRewardToken,
memoProgram: MEMO_PROGRAM_ID
}).remainingAccounts(transferHookAccounts).remainingAccounts(binArrayAccountsMeta).preInstructions(preInstructions).transaction();
claimTransactions.push(claimTransaction);
}
}
return claimTransactions;
}
async createClaimSwapFeeMethod({
owner,
position
}) {
const maybeClaimableBinRange = getPositionLowerUpperBinIdWithLiquidity(
position.positionData
);
if (!maybeClaimableBinRange)
return [];
const { lowerBinId, upperBinId } = maybeClaimableBinRange;
const chunkedBinRange = chunkBinRange(
lowerBinId.toNumber(),
upperBinId.toNumber()
);
const claimFeeTxs = [];
for (const {
lowerBinId: chunkedLowerBinId,
upperBinId: chunkedUpperBinId
} of chunkedBinRange) {
const binArrayAccountsMeta = getBinArrayAccountMetasCoverage(
new (0, _anchor.BN)(chunkedLowerBinId),
new (0, _anchor.BN)(chunkedUpperBinId),
this.pubkey,
this.program.programId
);
const { feeOwner } = position.positionData;
const walletToReceiveFee = feeOwner.equals(_web3js.PublicKey.default) ? owner : feeOwner;
const preInstructions = [];
const userTokenX = _spltoken.getAssociatedTokenAddressSync.call(void 0,
this.lbPair.tokenXMint,
walletToReceiveFee,
true,
this.tokenX.owner
);
const userTokenY = _spltoken.getAssociatedTokenAddressSync.call(void 0,
this.lbPair.tokenYMint,
walletToReceiveFee,
true,
this.tokenY.owner
);
const createUserTokenXIx = _spltoken.createAssociatedTokenAccountIdempotentInstruction.call(void 0,
owner,
userTokenX,
walletToReceiveFee,
this.lbPair.tokenXMint,
this.tokenX.owner
);
const createUserTokenYIx = _spltoken.createAssociatedTokenAccountIdempotentInstruction.call(void 0,
owner,
userTokenY,
walletToReceiveFee,
this.lbPair.tokenYMint,
this.tokenY.owner
);
preInstructions.push(createUserTokenXIx);
preInstructions.push(createUserTokenYIx);
const postInstructions = [];
if ([
this.tokenX.publicKey.toBase58(),
this.tokenY.publicKey.toBase58()
].includes(_spltoken.NATIVE_MINT.toBase58()) && !_optionalChain([this, 'access', _188 => _188.opt, 'optionalAccess', _189 => _189.skipSolWrappingOperation])) {
const closeWrappedSOLIx = await unwrapSOLInstruction(owner);
closeWrappedSOLIx && postInstructions.push(closeWrappedSOLIx);
}
const { slices, accounts: transferHookAccounts } = this.getPotentialToken2022IxDataAndAccounts(0 /* Liquidity */);
const claimFeeTx = await this.program.methods.claimFee2(chunkedLowerBinId, chunkedUpperBinId, {
slices
}).accountsPartial({
lbPair: this.pubkey,
sender: owner,
position: position.publicKey,
reserveX: this.lbPair.reserveX,
reserveY: this.lbPair.reserveY,
tokenProgramX: this.tokenX.owner,
tokenProgramY: this.tokenY.owner,
tokenXMint: this.tokenX.publicKey,
tokenYMint: this.tokenY.publicKey,
userTokenX,
userTokenY,
memoProgram: MEMO_PROGRAM_ID
}).remainingAccounts(transferHookAccounts).remainingAccounts(binArrayAccountsMeta).preInstructions(preInstructions).postInstructions(postInstructions).transaction();
claimFeeTxs.push(claimFeeTx);
}
return claimFeeTxs;
}
getPotentialToken2022IxDataAndAccounts(actionType, rewardIndex) {
if (actionType == 0 /* Liquidity */) {
return {
slices: [
{
accountsType: {
transferHookX: {}
},
length: this.tokenX.transferHookAccountMetas.length
},
{
accountsType: {
transferHookY: {}
},
length: this.tokenY.transferHookAccountMetas.length
}
],
accounts: this.tokenX.transferHookAccountMetas.concat(
this.tokenY.transferHookAccountMetas
)
};
}
return {
slices: [
{
accountsType: {
transferHookReward: {}
},
length: this.rewards[rewardIndex].transferHookAccountMetas.length
}
],
accounts: this.rewards[rewardIndex].transferHookAccountMetas
};
}
/**
* Fetches the oracle account and returns an IDynamicOracle instance that can be
* used to query TWAP (Time-Weighted Average Price) data.
*
* @returns An IDynamicOracle instance with methods like getActiveIdByTime,
* getPriceByTime, getUiPriceByTime, etc.
*/
async getOracle() {
const oracleAddress = this.lbPair.oracle;
const [oracleAccountInfo, lbPairAccountInfo] = await this.program.provider.connection.getMultipleAccountsInfo([
oracleAddress,
this.pubkey
]);
const lbPairState = decodeAccount(
this.program,
"lbPair",
lbPairAccountInfo.data
);
return wrapOracle(
oracleAddress,
oracleAccountInfo.data,
this.lbPair.binStep,
new (0, _anchor.BN)(lbPairState.activeId),
this.tokenX.mint.decimals,
this.tokenY.mint.decimals,
this.program
);
}
/**
* Returns a transaction to increase the oracle observation storage length.
* A longer oracle stores more historical data, enabling TWAP queries over
* longer time ranges.
*
* @param lengthToAdd - Number of observation slots to add.
* @param funder - The public key of the account funding the reallocation.
* @returns A Transaction that can be signed and sent.
*/
async increaseOracleLength(lengthToAdd, funder) {
const oracleAddress = this.lbPair.oracle;
const increaseOracleLengthIx = await this.program.methods.increaseOracleLength(lengthToAdd).accountsPartial({
oracle: oracleAddress,
funder
}).instruction();
const { blockhash, lastValidBlockHeight } = await this.program.provider.connection.getLatestBlockhash("confirmed");
return new (0, _web3js.Transaction)({
blockhash,
lastValidBlockHeight,
feePayer: funder
}).add(increaseOracleLengthIx);
}
};
// src/index.ts
var src_default = DLMM;
exports.ADMIN = ADMIN; exports.ALT_ADDRESS = ALT_ADDRESS; exports.ActionType = ActionType; exports.ActivationType = ActivationType; exports.BASIS_POINT_MAX = BASIS_POINT_MAX; exports.BIN_ARRAY_BITMAP_FEE = BIN_ARRAY_BITMAP_FEE; exports.BIN_ARRAY_BITMAP_FEE_BN = BIN_ARRAY_BITMAP_FEE_BN; exports.BIN_ARRAY_BITMAP_SIZE = BIN_ARRAY_BITMAP_SIZE; exports.BIN_ARRAY_DEFAULT_VERSION = BIN_ARRAY_DEFAULT_VERSION; exports.BIN_ARRAY_FEE = BIN_ARRAY_FEE; exports.BIN_ARRAY_FEE_BN = BIN_ARRAY_FEE_BN; exports.BinLiquidity = BinLiquidity; exports.BitmapType = BitmapType; exports.ClockLayout = ClockLayout; exports.CollectFeeMode = CollectFeeMode; exports.ConcreteFunctionType = ConcreteFunctionType; exports.DEFAULT_BIN_PER_POSITION = DEFAULT_BIN_PER_POSITION; exports.DLMMError = DLMMError; exports.DlmmSdkError = DlmmSdkError; exports.DynamicOracle = DynamicOracle; exports.EXTENSION_BINARRAY_BITMAP_SIZE = EXTENSION_BINARRAY_BITMAP_SIZE; exports.FEE_PRECISION = FEE_PRECISION; exports.FunctionType = FunctionType; exports.IDL = idl_default; exports.ILM_BASE = ILM_BASE; exports.LBCLMM_PROGRAM_IDS = LBCLMM_PROGRAM_IDS; exports.LIMIT_ORDER_BIN_DATA_SIZE = LIMIT_ORDER_BIN_DATA_SIZE; exports.LIMIT_ORDER_FEE_SHARE = LIMIT_ORDER_FEE_SHARE; exports.LIMIT_ORDER_MIN_SIZE = LIMIT_ORDER_MIN_SIZE; exports.LimitOrderStatus = LimitOrderStatus; exports.MAX_ACTIVE_BIN_SLIPPAGE = MAX_ACTIVE_BIN_SLIPPAGE; exports.MAX_BINS_PER_POSITION = MAX_BINS_PER_POSITION; exports.MAX_BIN_ARRAY_SIZE = MAX_BIN_ARRAY_SIZE; exports.MAX_BIN_ID_PER_BIN_STEP = MAX_BIN_ID_PER_BIN_STEP; exports.MAX_BIN_LENGTH_ALLOWED_IN_ONE_TX = MAX_BIN_LENGTH_ALLOWED_IN_ONE_TX; exports.MAX_BIN_PER_LIMIT_ORDER = MAX_BIN_PER_LIMIT_ORDER; exports.MAX_CLAIM_ALL_ALLOWED = MAX_CLAIM_ALL_ALLOWED; exports.MAX_EXTRA_BIN_ARRAYS = MAX_EXTRA_BIN_ARRAYS; exports.MAX_FEE_RATE = MAX_FEE_RATE; exports.MAX_RESIZE_LENGTH = MAX_RESIZE_LENGTH; exports.MEMO_PROGRAM_ID = MEMO_PROGRAM_ID; exports.Network = Network; exports.Observation = Observation; exports.POOL_FEE = POOL_FEE; exports.POOL_FEE_BN = POOL_FEE_BN; exports.POSITION_BIN_DATA_SIZE = POSITION_BIN_DATA_SIZE; exports.POSITION_FEE = POSITION_FEE; exports.POSITION_FEE_BN = POSITION_FEE_BN; exports.POSITION_MAX_LENGTH = POSITION_MAX_LENGTH; exports.POSITION_MIN_SIZE = POSITION_MIN_SIZE; exports.PRECISION = PRECISION; exports.PairStatus = PairStatus; exports.PairType = PairType; exports.PositionPermission = PositionPermission; exports.PositionV2Wrapper = PositionV2Wrapper; exports.PositionVersion = PositionVersion; exports.REBALANCE_POSITION_PADDING = REBALANCE_POSITION_PADDING; exports.RebalancePosition = RebalancePosition; exports.ResizeSide = ResizeSide; exports.Rounding = Rounding; exports.SCALE = SCALE; exports.SCALE_OFFSET = SCALE_OFFSET; exports.SIMULATION_USER = SIMULATION_USER; exports.ShrinkMode = ShrinkMode; exports.Strategy = Strategy; exports.StrategyType = StrategyType; exports.TOKEN_ACCOUNT_FEE = TOKEN_ACCOUNT_FEE; exports.TOKEN_ACCOUNT_FEE_BN = TOKEN_ACCOUNT_FEE_BN; exports.U64_MAX = U64_MAX; exports.autoFillXByStrategy = autoFillXByStrategy; exports.autoFillXByWeight = autoFillXByWeight; exports.autoFillYByStrategy = autoFillYByStrategy; exports.autoFillYByWeight = autoFillYByWeight; exports.binArrayLbPairFilter = binArrayLbPairFilter; exports.binDeltaToMinMaxBinId = binDeltaToMinMaxBinId; exports.binIdToBinArrayIndex = binIdToBinArrayIndex; exports.buildBitFlagAndNegateStrategyParameters = buildBitFlagAndNegateStrategyParameters; exports.buildLiquidityStrategyParameters = buildLiquidityStrategyParameters; exports.calculateBidAskDistribution = calculateBidAskDistribution; exports.calculateNormalDistribution = calculateNormalDistribution; exports.calculatePositionSize = calculatePositionSize; exports.calculateSpotDistribution = calculateSpotDistribution; exports.calculateTransferFeeExcludedAmount = calculateTransferFeeExcludedAmount; exports.calculateTransferFeeIncludedAmount = calculateTransferFeeIncludedAmount; exports.capSlippagePercentage = capSlippagePercentage; exports.chunkBinRange = chunkBinRange; exports.chunkBinRangeIntoExtendedPositions = chunkBinRangeIntoExtendedPositions; exports.chunkDepositWithRebalanceEndpoint = chunkDepositWithRebalanceEndpoint; exports.chunkPositionBinRange = chunkPositionBinRange; exports.chunkedFetchMultipleBinArrayBitmapExtensionAccount = chunkedFetchMultipleBinArrayBitmapExtensionAccount; exports.chunkedFetchMultiplePoolAccount = chunkedFetchMultiplePoolAccount; exports.chunkedGetMultipleAccountInfos = chunkedGetMultipleAccountInfos; exports.chunkedGetProgramAccounts = chunkedGetProgramAccounts; exports.chunks = chunks; exports.compressBinAmount = compressBinAmount; exports.computeBaseFactorFromFeeBps = computeBaseFactorFromFeeBps; exports.computeFee = computeFee; exports.computeFeeFromAmount = computeFeeFromAmount; exports.computeProtocolFee = computeProtocolFee; exports.createProgram = createProgram; exports.decodeAccount = decodeAccount; exports.decodeExtendedPosition = decodeExtendedPosition; exports.decodeRewardPerTokenStored = decodeRewardPerTokenStored; exports.default = src_default; exports.deriveBinArray = deriveBinArray; exports.deriveBinArrayBitmapExtension = deriveBinArrayBitmapExtension; exports.deriveCustomizablePermissionlessLbPair = deriveCustomizablePermissionlessLbPair; exports.deriveEventAuthority = deriveEventAuthority; exports.deriveLbPair = deriveLbPair; exports.deriveLbPair2 = deriveLbPair2; exports.deriveLbPairWithPresetParamWithIndexKey = deriveLbPairWithPresetParamWithIndexKey; exports.deriveOperator = deriveOperator; exports.deriveOracle = deriveOracle; exports.derivePermissionLbPair = derivePermissionLbPair; exports.derivePlaceHolderAccountMeta = derivePlaceHolderAccountMeta; exports.derivePosition = derivePosition; exports.derivePresetParameter = derivePresetParameter; exports.derivePresetParameter2 = derivePresetParameter2; exports.derivePresetParameterWithIndex = derivePresetParameterWithIndex; exports.deriveReserve = deriveReserve; exports.deriveRewardVault = deriveRewardVault; exports.deriveTokenBadge = deriveTokenBadge; exports.distributeAmountToCompressedBinsByRatio = distributeAmountToCompressedBinsByRatio; exports.encodePositionPermissions = encodePositionPermissions; exports.enumerateBins = enumerateBins; exports.findNextBinArrayIndexWithLiquidity = findNextBinArrayIndexWithLiquidity; exports.findNextBinArrayWithLiquidity = findNextBinArrayWithLiquidity; exports.findOptimumDecompressMultiplier = findOptimumDecompressMultiplier; exports.fromWeightDistributionToAmount = fromWeightDistributionToAmount; exports.fromWeightDistributionToAmountOneSide = fromWeightDistributionToAmountOneSide; exports.generateAmountForBinRange = generateAmountForBinRange; exports.generateBinAmount = generateBinAmount; exports.getAccountDiscriminator = getAccountDiscriminator; exports.getAmountIn = getAmountIn; exports.getAmountInBinsAskSide = getAmountInBinsAskSide; exports.getAmountInBinsBidSide = getAmountInBinsBidSide; exports.getAmountOut = getAmountOut; exports.getAndCapMaxActiveBinSlippage = getAndCapMaxActiveBinSlippage; exports.getAutoFillAmountByRebalancedPosition = getAutoFillAmountByRebalancedPosition; exports.getBaseFee = getBaseFee; exports.getBinArrayAccountMetasCoverage = getBinArrayAccountMetasCoverage; exports.getBinArrayIndexesCoverage = getBinArrayIndexesCoverage; exports.getBinArrayInfoForNonContiguousBinIds = getBinArrayInfoForNonContiguousBinIds; exports.getBinArrayKeysCoverage = getBinArrayKeysCoverage; exports.getBinArrayLowerUpperBinId = getBinArrayLowerUpperBinId; exports.getBinArraysRequiredByPositionRange = getBinArraysRequiredByPositionRange; exports.getBinArraysRequiredByPositionRange2 = getBinArraysRequiredByPositionRange2; exports.getBinCount = getBinCount; exports.getBinFromBinArray = getBinFromBinArray; exports.getBinIdIndexInBinArray = getBinIdIndexInBinArray; exports.getBinMaxAmountOut = getBinMaxAmountOut; exports.getC = getC; exports.getEstimatedComputeUnitIxWithBuffer = getEstimatedComputeUnitIxWithBuffer; exports.getEstimatedComputeUnitUsageWithBuffer = getEstimatedComputeUnitUsageWithBuffer; exports.getExcludedFeeAmount = getExcludedFeeAmount; exports.getExtendedPositionBinCount = getExtendedPositionBinCount; exports.getExtraAccountMetasForTransferHook = getExtraAccountMetasForTransferHook; exports.getFeeMode = getFeeMode; exports.getIncludedFeeAmount = getIncludedFeeAmount; exports.getLimitOrderLiquidity = getLimitOrderLiquidity; exports.getLiquidityStrategyParameterBuilder = getLiquidityStrategyParameterBuilder; exports.getMultipleMintsExtraAccountMetasForTransferHook = getMultipleMintsExtraAccountMetasForTransferHook; exports.getOrCreateATAInstruction = getOrCreateATAInstruction; exports.getPositionCount = getPositionCount; exports.getPositionCountByBinCount = getPositionCountByBinCount; exports.getPositionExpandRentExemption = getPositionExpandRentExemption; exports.getPositionLowerUpperBinIdWithLiquidity = getPositionLowerUpperBinIdWithLiquidity; exports.getPositionRentExemption = getPositionRentExemption; exports.getPriceOfBinByBinId = getPriceOfBinByBinId; exports.getQPriceBaseFactor = getQPriceBaseFactor; exports.getQPriceFromId = getQPriceFromId; exports.getRebalanceBinArrayIndexesAndBitmapCoverage = getRebalanceBinArrayIndexesAndBitmapCoverage; exports.getSlippageMaxAmount = getSlippageMaxAmount; exports.getSlippageMinAmount = getSlippageMinAmount; exports.getTokenBalance = getTokenBalance; exports.getTokenDecimals = getTokenDecimals; exports.getTokenProgramId = getTokenProgramId; exports.getTokensMintFromPoolAddress = getTokensMintFromPoolAddress; exports.getTotalFee = getTotalFee; exports.getVariableFee = getVariableFee; exports.isBinIdWithinBinArray = isBinIdWithinBinArray; exports.isOverflowDefaultBinArrayBitmap = isOverflowDefaultBinArrayBitmap; exports.isPositionNoFee = isPositionNoFee; exports.isPositionNoReward = isPositionNoReward; exports.isSupportLimitOrder = isSupportLimitOrder; exports.limitOrderFilter = limitOrderFilter; exports.limitOrderLbPairFilter = limitOrderLbPairFilter; exports.limitOrderOwnerFilter = limitOrderOwnerFilter; exports.mulDiv = mulDiv; exports.mulShr = mulShr; exports.parseLogs = parseLogs; exports.positionLbPairFilter = positionLbPairFilter; exports.positionOwnerFilter = positionOwnerFilter; exports.positionV2Filter = positionV2Filter; exports.presetParameter2BaseFactorFilter = presetParameter2BaseFactorFilter; exports.presetParameter2BaseFeePowerFactor = presetParameter2BaseFeePowerFactor; exports.presetParameter2BinStepFilter = presetParameter2BinStepFilter; exports.range = range; exports.resetUninvolvedLiquidityParams = resetUninvolvedLiquidityParams; exports.shlDiv = shlDiv; exports.splitFee = splitFee; exports.suggestBalancedXParametersFromY = suggestBalancedXParametersFromY; exports.suggestBalancedYParametersFromX = suggestBalancedYParametersFromX; exports.swapExactInQuoteAtBin = swapExactInQuoteAtBin; exports.swapExactOutQuoteAtBin = swapExactOutQuoteAtBin; exports.toAmountAskSide = toAmountAskSide; exports.toAmountBidSide = toAmountBidSide; exports.toAmountBothSide = toAmountBothSide; exports.toAmountIntoBins = toAmountIntoBins; exports.toAmountsBothSideByStrategy = toAmountsBothSideByStrategy; exports.toStrategyParameters = toStrategyParameters; exports.toWeightDistribution = toWeightDistribution; exports.unwrapSOLInstruction = unwrapSOLInstruction; exports.wrapOracle = wrapOracle; exports.wrapPosition = wrapPosition; exports.wrapSOLInstruction = wrapSOLInstruction;
//# sourceMappingURL=index.js.map
// CJS interop: Make default export primary for require() compatibility
if (exports.default) {
module.exports = exports.default;
for (const key in exports) {
if (key !== "default") {
module.exports[key] = exports[key];
}
}
}