Files
meteora-dlmm-bot/tests/unit/meteora.test.ts
Louis-Sinan c9daaddb77 first commit
2025-12-21 12:22:16 +01:00

133 lines
4.6 KiB
TypeScript

import { PublicKey } from "@solana/web3.js";
import { BN } from "@coral-xyz/anchor";
// Objects prefixed with 'mock' are hoisted and allowed in jest.mock factory
const mockInternalConfig = {
connection: {},
wallet: { publicKey: new PublicKey("LbVRzDTvBDEcrthxfZ4RL6yiq3uZw8bS6MwtdY6UhFQ") },
poolAddress: new PublicKey("LbVRzDTvBDEcrthxfZ4RL6yiq3uZw8bS6MwtdY6UhFQ"),
DRY_RUN: false,
SLIPPAGE_BPS: 100,
MAX_RETRIES: 3,
MIN_SOL_FOR_GAS: 0.1,
};
jest.mock("../../src/utils/config", () => mockInternalConfig);
jest.mock("@meteora-ag/dlmm");
jest.mock("@solana/web3.js", () => ({
...jest.requireActual("@solana/web3.js"),
sendAndConfirmTransaction: jest.fn(),
}));
jest.mock("../../src/utils/logger", () => ({
info: jest.fn(),
error: jest.fn(),
debug: jest.fn(),
warn: jest.fn(),
}));
import { MeteoraWrapper } from "../../src/meteora";
import DLMM from "@meteora-ag/dlmm";
import { sendAndConfirmTransaction } from "@solana/web3.js";
import logger from "../../src/utils/logger";
describe("MeteoraWrapper", () => {
let wrapper: MeteoraWrapper;
let mockDlmm: any;
beforeEach(async () => {
jest.clearAllMocks();
wrapper = new MeteoraWrapper();
mockDlmm = {
getActiveBin: jest.fn(),
getPositionsByUserAndLbPair: jest.fn(),
removeLiquidity: jest.fn(),
initializePositionAndAddLiquidityByStrategy: jest.fn(),
claimAllRewardsByPosition: jest.fn(),
tokenX: { mint: { address: new PublicKey("LbVRzDTvBDEcrthxfZ4RL6yiq3uZw8bS6MwtdY6UhFQ") } },
tokenY: { mint: { address: new PublicKey("LbVRzDTvBDEcrthxfZ4RL6yiq3uZw8bS6MwtdY6UhFQ") } },
};
(DLMM.create as jest.Mock).mockResolvedValue(mockDlmm);
await wrapper.init();
});
it("should get active bin", async () => {
mockDlmm.getActiveBin.mockResolvedValue({ binId: 100 });
const bin = await wrapper.getActiveBin();
expect(bin.binId).toBe(100);
});
it("should withdraw all liquidity from positions", async () => {
const mockPosition = {
publicKey: new PublicKey("LbVRzDTvBDEcrthxfZ4RL6yiq3uZw8bS6MwtdY6UhFQ"),
positionData: { lowerBinId: 90, upperBinId: 110 },
};
mockDlmm.getPositionsByUserAndLbPair.mockResolvedValue({
userPositions: [mockPosition],
});
mockDlmm.removeLiquidity.mockResolvedValue([{}]);
(sendAndConfirmTransaction as jest.Mock).mockResolvedValue("txHash");
await wrapper.withdrawAll();
expect(mockDlmm.removeLiquidity).toHaveBeenCalled();
expect(sendAndConfirmTransaction).toHaveBeenCalled();
});
it("should deposit liquidity", async () => {
mockDlmm.initializePositionAndAddLiquidityByStrategy.mockResolvedValue({});
(sendAndConfirmTransaction as jest.Mock).mockResolvedValue("txHash");
await wrapper.deposit(
new BN(100),
new BN(100),
100
);
expect(
mockDlmm.initializePositionAndAddLiquidityByStrategy
).toHaveBeenCalled();
expect(sendAndConfirmTransaction).toHaveBeenCalled();
});
it("should skip transactions in DRY_RUN mode", async () => {
mockInternalConfig.DRY_RUN = true;
mockDlmm.initializePositionAndAddLiquidityByStrategy.mockResolvedValue({});
await wrapper.deposit(
new BN(100),
new BN(100),
100
);
expect(sendAndConfirmTransaction).not.toHaveBeenCalled();
expect(logger.info).toHaveBeenCalledWith(
expect.stringContaining("[DRY RUN]")
);
mockInternalConfig.DRY_RUN = false; // Reset
});
it("should get token balances", async () => {
mockDlmm.tokenX = { mint: { address: new PublicKey("LbVRzDTvBDEcrthxfZ4RL6yiq3uZw8bS6MwtdY6UhFQ") } };
mockDlmm.tokenY = { mint: { address: new PublicKey("LbVRzDTvBDEcrthxfZ4RL6yiq3uZw8bS6MwtdY6UhFQ") } };
const balances = await wrapper.getBalances();
expect(balances).toBeDefined();
});
it("should log deposit details", async () => {
mockDlmm.initializePositionAndAddLiquidityByStrategy.mockResolvedValue({});
mockDlmm.tokenX = { mint: { address: new PublicKey("LbVRzDTvBDEcrthxfZ4RL6yiq3uZw8bS6MwtdY6UhFQ") } };
mockDlmm.tokenY = { mint: { address: new PublicKey("LbVRzDTvBDEcrthxfZ4RL6yiq3uZw8bS6MwtdY6UhFQ") } };
(sendAndConfirmTransaction as jest.Mock).mockResolvedValue("txHash");
await wrapper.deposit(new BN(100), new BN(100), 100);
expect(logger.info).toHaveBeenCalledWith(
expect.stringContaining("Depositing liquidity")
);
});
});