first commit
This commit is contained in:
81
tests/unit/bot.test.ts
Normal file
81
tests/unit/bot.test.ts
Normal file
@@ -0,0 +1,81 @@
|
||||
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
|
||||
);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user