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

82 lines
2.6 KiB
TypeScript

import { DLMMBot } from "../../src/bot";
import { MeteoraWrapper } from "../../src/meteora";
import logger from "../../src/utils/logger";
import { BN } from "@coral-xyz/anchor";
jest.mock("../../src/utils/config", () => ({
connection: { getActiveBin: jest.fn() },
wallet: { publicKey: { toBase58: () => "wallet1" } },
REBALANCE_THRESHOLD_PERCENT: 0.15,
poolAddress: { toBase58: () => "pool1" },
DRY_RUN: false,
SLIPPAGE_BPS: 100,
MAX_RETRIES: 3,
JLP_USD_ESTIMATE: 3.0,
SOL_USD_ESTIMATE: 100.0,
COMPOUND_THRESHOLD_USD: 1.0,
}));
jest.mock("../../src/utils/logger", () => ({
info: jest.fn(),
error: jest.fn(),
debug: jest.fn(),
warn: jest.fn(),
}));
jest.mock("../../src/meteora");
describe("DLMMBot Rebalance Logic", () => {
let bot: DLMMBot;
let mockMeteora: jest.Mocked<MeteoraWrapper>;
beforeEach(() => {
jest.clearAllMocks();
bot = new DLMMBot();
mockMeteora = (bot as any).meteora;
mockMeteora.getBalances.mockResolvedValue({ balanceX: new BN(0), balanceY: new BN(0) });
mockMeteora.getTokenPrice.mockResolvedValue(1.0);
mockMeteora.dlmmPool = {
tokenX: { mint: { decimals: 9, address: { toBase58: () => "So11111111111111111111111111111111111111112" } } },
tokenY: { mint: { decimals: 6, address: { toBase58: () => "JLP" } } }
} as any;
});
it("should not rebalance if within range", async () => {
mockMeteora.getActiveBin.mockResolvedValue({ binId: 100 } as any);
mockMeteora.getPositions.mockResolvedValue([
{
publicKey: { toBase58: () => "pos1" },
positionData: { lowerBinId: 90, upperBinId: 110 },
},
] as any);
await bot.rebalance();
expect(logger.info).toHaveBeenCalledWith(
expect.stringContaining("Portfolio healthy")
);
expect(mockMeteora.withdrawAll).not.toHaveBeenCalled();
});
it("should trigger rebalance if out of range", async () => {
mockMeteora.getActiveBin.mockResolvedValue({ binId: 120 } as any);
mockMeteora.getPositions.mockResolvedValue([
{
publicKey: { toBase58: () => "pos1" },
positionData: { lowerBinId: 90, upperBinId: 110 },
},
] as any);
mockMeteora.getBalances.mockResolvedValue({ balanceX: new BN(100), balanceY: new BN(100) });
mockMeteora.getTokenPrice.mockResolvedValue(1.0);
// dlmmPool already mocked in beforeEach
await bot.rebalance();
expect(mockMeteora.withdrawAll).toHaveBeenCalled();
expect(mockMeteora.getBalances).toHaveBeenCalled();
expect(mockMeteora.deposit).toHaveBeenCalledWith(
new BN(100),
new BN(100),
120
);
});
});