Skip to content

Commit

Permalink
update: get bin array for swap
Browse files Browse the repository at this point in the history
  • Loading branch information
McSam94 committed Jan 17, 2024
1 parent f0866e7 commit c5d04c2
Show file tree
Hide file tree
Showing 3 changed files with 163 additions and 158 deletions.
7 changes: 4 additions & 3 deletions ts-client/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -166,10 +166,11 @@ try {
```ts
const swapAmount = new BN(100);
// Swap quote
const binArrays = await dlmmPool.getBinArrayAroundActiveBin();
const swapYtoX = true;
const binArrays = await dlmmPool.getBinArrayForSwap(swapYtoX);
const swapQuote = await dlmmPool.swapQuote(
swapAmount,
true,
swapYtoX,
new BN(10),
binArrays
);
Expand Down Expand Up @@ -206,7 +207,7 @@ try {
| ------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------- |
| `refetchStates` | Update onchain state of DLMM instance. It's recommend to call this before interact with the program (Deposit/ Withdraw/ Swap) | `Promise<void>` |
| `getBinArrays` | Retrieves List of Bin Arrays | `Promise<BinArrayAccount[]>` |
| `getBinArrayAroundActiveBin` | Retrieves List of Bin Arrays around Active Bin | `Promise<BinArrayAccount[]>` |
| `getBinArrayForSwap` | Retrieves List of Bin Arrays for swap purpose | `Promise<BinArrayAccount[]>` |
| `getFeeInfo` | Retrieves LbPair's fee info including `base fee`, `protocol fee` & `max fee` | `FeeInfo` |
| `getDynamicFee` | Retrieves LbPair's dynamic fee | `Decimal` |
| `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. | `Promise<{ activeBin: number; bins: BinLiquidity[] }>` |
Expand Down
53 changes: 16 additions & 37 deletions ts-client/src/dlmm/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -933,54 +933,30 @@ export class DLMM {
/**
* The function `getBinArrayAroundActiveBin` retrieves a specified number of `BinArrayAccount`
* objects from the blockchain, based on the active bin and its surrounding bin arrays.
* @param [count=2] - The `count` parameter is the number of bin arrays to retrieve on left and right respectively. By default, it
* is set to 2.
* @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.
*/
public async getBinArrayAroundActiveBin(
count = 2
public async getBinArrayForSwap(
swapForY,
count = 4
): Promise<BinArrayAccount[]> {
await this.refetchStates();

const binArraysPubkey = new Set<string>();

let shouldStopRight = false;
let shouldStop = false;
let activeIdToLoop = this.lbPair.activeId;

while (!shouldStopRight) {
const binArrayIndex = findNextBinArrayIndexWithLiquidity(
false,
new BN(activeIdToLoop),
this.lbPair,
this.binArrayBitmapExtension?.account ?? null
);
if (binArrayIndex === null) shouldStopRight = true;
else {
const [binArrayPubKey] = deriveBinArray(
this.pubkey,
binArrayIndex,
this.program.programId
);
binArraysPubkey.add(binArrayPubKey.toBase58());

const [, upperBinId] = getBinArrayLowerUpperBinId(binArrayIndex);
activeIdToLoop = upperBinId.toNumber() + 1;
}

if (binArraysPubkey.size === count) shouldStopRight = true;
}

let shouldStopLeft = false;
activeIdToLoop = this.lbPair.activeId;

while (!shouldStopLeft) {
while (!shouldStop) {
const binArrayIndex = findNextBinArrayIndexWithLiquidity(
true,
swapForY,
new BN(activeIdToLoop),
this.lbPair,
this.binArrayBitmapExtension?.account ?? null
);
if (binArrayIndex === null) shouldStopLeft = true;
if (binArrayIndex === null) shouldStop = true;
else {
const [binArrayPubKey] = deriveBinArray(
this.pubkey,
Expand All @@ -989,11 +965,14 @@ export class DLMM {
);
binArraysPubkey.add(binArrayPubKey.toBase58());

const [lowerBinId] = getBinArrayLowerUpperBinId(binArrayIndex);
activeIdToLoop = lowerBinId.toNumber() - 1;
const [lowerBinId, upperBinId] =
getBinArrayLowerUpperBinId(binArrayIndex);
activeIdToLoop = swapForY
? lowerBinId.toNumber() - 1
: upperBinId.toNumber() + 1;
}

if (binArraysPubkey.size === count * 2) shouldStopLeft = true;
if (binArraysPubkey.size === count) shouldStop = true;
}

const accountsToFetch = Array.from(binArraysPubkey).map(
Expand Down
261 changes: 143 additions & 118 deletions ts-client/src/example.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,134 +19,147 @@ const devnetPool = new PublicKey(
"3W2HKgUa96Z69zzG3LK1g8KdcRAWzAttiLiHfYnKuPw5"
);

async function main() {
const dlmmPool = await DLMM.create(connection, devnetPool, {
cluster: "devnet",
});
let activeBin;
let userPositions;
let totalXAmount;
let totalYAmount;
let spotXYAmountDistribution;

const newPosition = new Keypair();

async function getActiveBin(dlmmPool: DLMM) {
// Get pool state
const activeBin = await dlmmPool.getActiveBin();
console.log("🚀 ~ activeBin:", activeBin);
}

// const TOTAL_RANGE_INTERVAL = 10; // 10 bins on each side of the active bin
// const bins = [activeBin.binId]; // Make sure bins is less than 70, as currently only support up to 70 bins for 1 position
// for (
// let i = activeBin.binId;
// i < activeBin.binId + TOTAL_RANGE_INTERVAL / 2;
// i++
// ) {
// const rightNextBinId = i + 1;
// const leftPrevBinId = activeBin.binId - (rightNextBinId - activeBin.binId);
// bins.push(rightNextBinId);
// bins.unshift(leftPrevBinId);
// }

// const activeBinPricePerToken = dlmmPool.fromPricePerLamport(
// Number(activeBin.price)
// );
// const totalXAmount = new BN(100);
// const totalYAmount = totalXAmount.mul(new BN(Number(activeBinPricePerToken)));

// // Get spot distribution
// const spotXYAmountDistribution = calculateSpotDistribution(
// activeBin.binId,
// bins
// );

// // Create Position
// const newPosition = new Keypair();
// const createPositionTx =
// await dlmmPool.initializePositionAndAddLiquidityByWeight({
// positionPubKey: newPosition.publicKey,
// lbPairPubKey: dlmmPool.pubkey,
// user: user.publicKey,
// totalXAmount,
// totalYAmount,
// xYAmountDistribution: spotXYAmountDistribution,
// });

// try {
// for (let tx of Array.isArray(createPositionTx)
// ? createPositionTx
// : [createPositionTx]) {
// const createPositionTxHash = await sendAndConfirmTransaction(
// connection,
// tx,
// [user, newPosition]
// );
// console.log("🚀 ~ createPositionTxHash:", createPositionTxHash);
// }
// } catch (error) {
// console.log("🚀 ~ error:", JSON.parse(JSON.stringify(error)));
// }

// // Get position state
// const { userPositions } = await dlmmPool.getPositionsByUserAndLbPair(
// user.publicKey
// );
// console.log("🚀 ~ userPositions:", userPositions);

// // Add Liquidity to existing position
// const addLiquidityTx = await dlmmPool.addLiquidityByWeight({
// positionPubKey: userPositions[0].publicKey,
// lbPairPubKey: dlmmPool.pubkey,
// user: user.publicKey,
// totalXAmount,
// totalYAmount,
// xYAmountDistribution: spotXYAmountDistribution,
// });

// try {
// for (let tx of Array.isArray(addLiquidityTx)
// ? addLiquidityTx
// : [addLiquidityTx]) {
// const addLiquidityTxHash = await sendAndConfirmTransaction(
// connection,
// tx,
// [user, newPosition]
// );
// console.log("🚀 ~ addLiquidityTxHash:", addLiquidityTxHash);
// }
// } catch (error) {
// console.log("🚀 ~ error:", JSON.parse(JSON.stringify(error)));
// }

// // Remove Liquidity
// const binIdsToRemove = userPositions[0].positionData.positionBinData.map(
// (bin) => bin.binId
// );
// const removeLiquidityTx = await dlmmPool.removeLiquidity({
// position: userPositions[0].publicKey,
// user: user.publicKey,
// binIds: binIdsToRemove,
// liquiditiesBpsToRemove: new Array(binIdsToRemove.length).fill(
// new BN(100 * 100)
// ), // 100% (range from 0 to 100)
// shouldClaimAndClose: true, // should claim swap fee and close position together
// });

// try {
// for (let tx of Array.isArray(removeLiquidityTx)
// ? removeLiquidityTx
// : [removeLiquidityTx]) {
// const removeLiquidityTxHash = await sendAndConfirmTransaction(
// connection,
// tx,
// [user, newPosition],
// { skipPreflight: false, preflightCommitment: "singleGossip" }
// );
// console.log("🚀 ~ removeLiquidityTxHash:", removeLiquidityTxHash);
// }
// } catch (error) {
// console.log("🚀 ~ error:", JSON.parse(JSON.stringify(error)));
// }
async function createPosition(dlmmPool: DLMM) {
const TOTAL_RANGE_INTERVAL = 10; // 10 bins on each side of the active bin
const bins = [activeBin.binId]; // Make sure bins is less than 70, as currently only support up to 70 bins for 1 position
for (
let i = activeBin.binId;
i < activeBin.binId + TOTAL_RANGE_INTERVAL / 2;
i++
) {
const rightNextBinId = i + 1;
const leftPrevBinId = activeBin.binId - (rightNextBinId - activeBin.binId);
bins.push(rightNextBinId);
bins.unshift(leftPrevBinId);
}

const activeBinPricePerToken = dlmmPool.fromPricePerLamport(
Number(activeBin.price)
);
totalXAmount = new BN(100);
totalYAmount = totalXAmount.mul(new BN(Number(activeBinPricePerToken)));

// Get spot distribution
spotXYAmountDistribution = calculateSpotDistribution(activeBin.binId, bins);

// Create Position
const createPositionTx =
await dlmmPool.initializePositionAndAddLiquidityByWeight({
positionPubKey: newPosition.publicKey,
lbPairPubKey: dlmmPool.pubkey,
user: user.publicKey,
totalXAmount,
totalYAmount,
xYAmountDistribution: spotXYAmountDistribution,
});

try {
for (let tx of Array.isArray(createPositionTx)
? createPositionTx
: [createPositionTx]) {
const createPositionTxHash = await sendAndConfirmTransaction(
connection,
tx,
[user, newPosition]
);
console.log("🚀 ~ createPositionTxHash:", createPositionTxHash);
}
} catch (error) {
console.log("🚀 ~ error:", JSON.parse(JSON.stringify(error)));
}
}

async function getPositionsState(dlmmPool: DLMM) {
// Get position state
const positionsState = await dlmmPool.getPositionsByUserAndLbPair(
user.publicKey
);

console.log("🚀 ~ userPositions:", userPositions);
userPositions = positionsState.userPositions;
}

async function addLiquidityToExistingPosition(dlmmPool: DLMM) {
// Add Liquidity to existing position
const addLiquidityTx = await dlmmPool.addLiquidityByWeight({
positionPubKey: userPositions[0].publicKey,
lbPairPubKey: dlmmPool.pubkey,
user: user.publicKey,
totalXAmount,
totalYAmount,
xYAmountDistribution: spotXYAmountDistribution,
});

try {
for (let tx of Array.isArray(addLiquidityTx)
? addLiquidityTx
: [addLiquidityTx]) {
const addLiquidityTxHash = await sendAndConfirmTransaction(
connection,
tx,
[user, newPosition]
);
console.log("🚀 ~ addLiquidityTxHash:", addLiquidityTxHash);
}
} catch (error) {
console.log("🚀 ~ error:", JSON.parse(JSON.stringify(error)));
}
}

async function removeLiquidity(dlmmPool: DLMM) {
// Remove Liquidity
const binIdsToRemove = userPositions[0].positionData.positionBinData.map(
(bin) => bin.binId
);
const removeLiquidityTx = await dlmmPool.removeLiquidity({
position: userPositions[0].publicKey,
user: user.publicKey,
binIds: binIdsToRemove,
liquiditiesBpsToRemove: new Array(binIdsToRemove.length).fill(
new BN(100 * 100)
), // 100% (range from 0 to 100)
shouldClaimAndClose: true, // should claim swap fee and close position together
});

try {
for (let tx of Array.isArray(removeLiquidityTx)
? removeLiquidityTx
: [removeLiquidityTx]) {
const removeLiquidityTxHash = await sendAndConfirmTransaction(
connection,
tx,
[user, newPosition],
{ skipPreflight: false, preflightCommitment: "singleGossip" }
);
console.log("🚀 ~ removeLiquidityTxHash:", removeLiquidityTxHash);
}
} catch (error) {
console.log("🚀 ~ error:", JSON.parse(JSON.stringify(error)));
}
}

async function swap(dlmmPool: DLMM) {
const swapAmount = new BN(100);
// Swap quote
const binArrays = await dlmmPool.getBinArrayAroundActiveBin();
const swapYtoX = true;
const binArrays = await dlmmPool.getBinArrayForSwap(swapYtoX);
const swapQuote = await dlmmPool.swapQuote(
swapAmount,
true,
swapYtoX,
new BN(10),
binArrays
);
Expand All @@ -173,4 +186,16 @@ async function main() {
}
}

async function main() {
const dlmmPool = await DLMM.create(connection, devnetPool, {
cluster: "devnet",
});

await getActiveBin(dlmmPool);
await createPosition(dlmmPool);
await addLiquidityToExistingPosition(dlmmPool);
await removeLiquidity(dlmmPool);
await swap(dlmmPool);
}

main();

0 comments on commit c5d04c2

Please sign in to comment.