fix: txnBot has zero test coverage after deleting recenterAccess.test.ts (#919)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
80f6d94247
commit
3d957bfb76
1 changed files with 134 additions and 0 deletions
134
services/txnBot/src/service.test.ts
Normal file
134
services/txnBot/src/service.test.ts
Normal file
|
|
@ -0,0 +1,134 @@
|
|||
import { describe, it } from 'node:test';
|
||||
import assert from 'node:assert/strict';
|
||||
import { createTxnBot, type TxnBotDependencies } from './service.js';
|
||||
import type { BotConfigService } from './services/BotConfigService.js';
|
||||
import type { BlockchainService } from './services/BlockchainService.js';
|
||||
import type { GraphQLService } from './services/GraphQLService.js';
|
||||
|
||||
const BASE_CONFIG = {
|
||||
PROVIDER_URL: 'http://localhost:8545',
|
||||
PRIVATE_KEY: '0xdeadbeef000000000000000000000000000000000000000000000000deadbeef',
|
||||
LM_CONTRACT_ADDRESS: '0x0000000000000000000000000000000000000001',
|
||||
STAKE_CONTRACT_ADDRESS: '0x0000000000000000000000000000000000000002',
|
||||
GRAPHQL_ENDPOINT: 'http://localhost:42069/graphql',
|
||||
ENVIRONMENT: 'test',
|
||||
PORT: '3000',
|
||||
};
|
||||
|
||||
function makeTx(hash: string) {
|
||||
return { hash, wait: (): Promise<null> => Promise.resolve(null) };
|
||||
}
|
||||
|
||||
function makeDeps(
|
||||
blockchain?: Partial<{
|
||||
estimateRecenterGas: () => Promise<void>;
|
||||
recenter: () => Promise<ReturnType<typeof makeTx>>;
|
||||
}>,
|
||||
): TxnBotDependencies {
|
||||
return {
|
||||
configService: {
|
||||
getConfig: () => ({ ...BASE_CONFIG }),
|
||||
getPort: () => '3000',
|
||||
} as unknown as BotConfigService,
|
||||
|
||||
blockchainService: {
|
||||
estimateRecenterGas: blockchain?.estimateRecenterGas ?? (() => Promise.resolve()),
|
||||
recenter: blockchain?.recenter ?? (() => Promise.resolve(makeTx('0xabc'))),
|
||||
checkFunds: () => Promise.resolve('1.0'),
|
||||
payTax: () => Promise.resolve(makeTx('0xpay')),
|
||||
} as unknown as BlockchainService,
|
||||
|
||||
graphQLService: {
|
||||
fetchActivePositions: () => Promise.resolve([]),
|
||||
} as unknown as GraphQLService,
|
||||
};
|
||||
}
|
||||
|
||||
describe('evaluateRecenterOpportunity', () => {
|
||||
it('returns canRecenter: true when gas estimation succeeds', async () => {
|
||||
const bot = createTxnBot(makeDeps());
|
||||
const result = await bot.evaluateRecenterOpportunity();
|
||||
|
||||
assert.equal(result.canRecenter, true);
|
||||
assert.equal(result.reason, null);
|
||||
assert.equal(result.error, null);
|
||||
assert.ok(result.checkedAtMs > 0);
|
||||
});
|
||||
|
||||
it('returns canRecenter: false with extracted revert reason', async () => {
|
||||
const bot = createTxnBot(
|
||||
makeDeps({
|
||||
estimateRecenterGas: () =>
|
||||
Promise.reject({
|
||||
shortMessage: 'execution reverted: recenter not needed',
|
||||
message: 'execution reverted: recenter not needed',
|
||||
}),
|
||||
}),
|
||||
);
|
||||
const result = await bot.evaluateRecenterOpportunity();
|
||||
|
||||
assert.equal(result.canRecenter, false);
|
||||
assert.equal(result.reason, 'recenter not needed');
|
||||
assert.equal(result.error, 'execution reverted: recenter not needed');
|
||||
});
|
||||
|
||||
it('returns canRecenter: false with generic message when no revert prefix', async () => {
|
||||
const bot = createTxnBot(
|
||||
makeDeps({
|
||||
estimateRecenterGas: () => Promise.reject({ message: 'connection refused' }),
|
||||
}),
|
||||
);
|
||||
const result = await bot.evaluateRecenterOpportunity();
|
||||
|
||||
assert.equal(result.canRecenter, false);
|
||||
assert.equal(result.reason, 'connection refused');
|
||||
assert.ok(result.checkedAtMs > 0);
|
||||
});
|
||||
});
|
||||
|
||||
describe('attemptRecenter', () => {
|
||||
it('calls recenter() and returns executed: true when eligible', async () => {
|
||||
let recenterCalled = false;
|
||||
const bot = createTxnBot(
|
||||
makeDeps({
|
||||
recenter: () => {
|
||||
recenterCalled = true;
|
||||
return Promise.resolve(makeTx('0xdeadbeef'));
|
||||
},
|
||||
}),
|
||||
);
|
||||
const result = await bot.attemptRecenter();
|
||||
|
||||
assert.equal(result.executed, true);
|
||||
assert.equal(result.txHash, '0xdeadbeef');
|
||||
assert.ok(recenterCalled, 'recenter() should have been called');
|
||||
});
|
||||
|
||||
it('skips recenter() and returns executed: false when not eligible', async () => {
|
||||
let recenterCalled = false;
|
||||
const bot = createTxnBot(
|
||||
makeDeps({
|
||||
estimateRecenterGas: () => Promise.reject({ message: 'recenter not needed' }),
|
||||
recenter: () => {
|
||||
recenterCalled = true;
|
||||
return Promise.resolve(makeTx('0xabc'));
|
||||
},
|
||||
}),
|
||||
);
|
||||
const result = await bot.attemptRecenter();
|
||||
|
||||
assert.equal(result.executed, false);
|
||||
assert.equal(recenterCalled, false, 'recenter() must not be called when not eligible');
|
||||
assert.ok(result.message);
|
||||
});
|
||||
|
||||
it('propagates error thrown by recenter() — caught by liquidityLoop', async () => {
|
||||
const bot = createTxnBot(
|
||||
makeDeps({
|
||||
recenter: () => Promise.reject(new Error('tx submission failed')),
|
||||
}),
|
||||
);
|
||||
|
||||
await assert.rejects(bot.attemptRecenter(), /tx submission failed/);
|
||||
});
|
||||
});
|
||||
Loading…
Add table
Add a link
Reference in a new issue