Skip to content

Commit

Permalink
tests: update tests
Browse files Browse the repository at this point in the history
  • Loading branch information
coreyar committed Aug 26, 2024
1 parent 756e9c5 commit 2677406
Show file tree
Hide file tree
Showing 13 changed files with 66 additions and 113 deletions.
1 change: 1 addition & 0 deletions packages/keeper-bots/.env.test
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,4 @@ PRIVATE_KEY_bscmainnet=0x0000000000000000000000000000000000000000000000000000000
RPC_bsctestnet=https://bsc-testnet.nodereal.io/v1/apiKey
RPC_bscmainnet=https://bsc-mainnet.nodereal.io/v1/apiKey
THE_GRAPH_STUDIO_API_KEY=1234567890
TESTNET_GRAPH_ID=
12 changes: 6 additions & 6 deletions packages/keeper-bots/src/bot-base.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import getConfig from "./config";
import type { SUPPORTED_CHAINS } from "./config/chains";
import getPublicClient from "./config/clients/publicClient";
import getWalletClient from "./config/clients/walletClient";
import publicClient from "./config/clients/publicClient";
import walletClient from "./config/clients/walletClient";
import { ConverterBotMessage } from "./converter-bot/types";
import { SwapProvider } from "./providers";

Expand All @@ -12,8 +12,8 @@ class BotBase {
protected subscriber: undefined | ((msg: ConverterBotMessage) => void);
protected simulate: boolean;
protected swapProvider: SwapProvider;
public publicClient: ReturnType<typeof getPublicClient>;
public walletClient: ReturnType<typeof getWalletClient>;
public publicClient: typeof publicClient;
public walletClient: typeof walletClient;

constructor({
subscriber,
Expand All @@ -26,8 +26,8 @@ class BotBase {
}) {
this.subscriber = subscriber;
this.swapProvider = new swapProvider({ subscriber });
this.publicClient = getPublicClient();
this.walletClient = getWalletClient();
this.publicClient = publicClient;
this.walletClient = walletClient;
this.simulate = simulate;
this.chainName = config.network.name;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
const getPublicClientMock = () => ({
const publicClientMock = {
simulateContract: jest.fn(),
readContract: jest.fn(),
multicall: jest.fn(),
getBlock: jest.fn(),
getBlockNumber: jest.fn(),
waitForTransactionReceipt: jest.fn(),
estimateContractGas: jest.fn(),
});
};

export default getPublicClientMock;
export default publicClientMock;
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
const getWalletClientMock = () => ({
const walletClientMock = {
account: {
address: "0x4CCeBa2d7D2B4fdcE4304d3e09a1fea9fbEb1528",
},
writeContract: jest.fn(() => "0xtransactionHash"),
});
};

export default getWalletClientMock;
export default walletClientMock;
2 changes: 1 addition & 1 deletion packages/keeper-bots/src/config/clients/publicClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,4 @@ const getPublicClient = () => {
});
};

export default getPublicClient;
export default getPublicClient();
2 changes: 1 addition & 1 deletion packages/keeper-bots/src/config/clients/walletClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,4 @@ const getWalletClient = () => {
});
};

export default getWalletClient;
export default getWalletClient();
117 changes: 40 additions & 77 deletions packages/keeper-bots/src/converter-bot/TokenConverter.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ import {
tokenConverterOperatorAbi,
vBnbAdminAbi,
} from "../config/abis/generated";
import publicClient from "../config/clients/publicClient";
import walletClient from "../config/clients/walletClient";
import { PancakeSwapProvider, UniswapProvider } from "../providers";
import TokenConverter from "./TokenConverter";
import readTokenConvertersTokenBalances, { BalanceResult } from "./queries/getTokenConvertersTokenBalances";
Expand Down Expand Up @@ -42,13 +44,22 @@ const addresses = {
const createTokenConverterInstance = ({ simulate = false }: { simulate: boolean } = { simulate: false }) => {
const subscriberMock = jest.fn();
const pancakeSwapProvider = new PancakeSwapProvider({ subscriber: subscriberMock });
(pancakeSwapProvider.publicClient.multicall as jest.Mock).mockImplementation(() => [
{ result: 18 },
{ result: "USDT" },
]);
(pancakeSwapProvider.publicClient.simulateContract as jest.Mock).mockImplementation(() => ({
result: [1000000000000000000n, 1000000000000000000n],
}));

(publicClient.multicall as unknown as jest.Mock).mockImplementation(
jest.fn(() => [{ result: 18 }, { result: "USDT" }]),
);

(publicClient.simulateContract as unknown as jest.Mock).mockImplementation(
jest.fn(() => ({
result: [1000000000000000000n, 1000000000000000000n],
})),
);
(publicClient.getBlock as unknown as jest.Mock).mockImplementation(jest.fn(() => ({ timestamp: 1713214109n })));
(publicClient.waitForTransactionReceipt as unknown as jest.Mock).mockImplementation(
jest.fn(() => ({ blockNumber: 23486902n })),
);
(publicClient.estimateContractGas as unknown as jest.Mock).mockImplementation(jest.fn(() => {}));

const tokenConverter = new TokenConverter({
subscriber: subscriberMock,
simulate,
Expand All @@ -63,16 +74,14 @@ describe("Token Converter", () => {
(SmartRouter.getBestTrade as jest.Mock).mockImplementation(() => mockRoute);
});

afterEach(() => {
(walletClient.writeContract as jest.Mock).mockClear();
(publicClient.simulateContract as jest.Mock).mockClear();
});

describe("getBestTrade", () => {
test("should throw error if not trade found", async () => {
const { tokenConverter } = createTokenConverterInstance();
(tokenConverter.publicClient.multicall as jest.Mock).mockImplementation(() => [
{ result: 18 },
{ result: "USDT" },
]);
(tokenConverter.publicClient.simulateContract as jest.Mock).mockImplementation(() => ({
result: [1000000000000000000n, 1000000000000000000n],
}));

(SmartRouter.getBestTrade as jest.Mock).mockImplementationOnce(() => null);

Expand All @@ -89,13 +98,6 @@ describe("Token Converter", () => {

test("should handle thrown error", async () => {
const { tokenConverter } = createTokenConverterInstance();
(tokenConverter.publicClient.multicall as jest.Mock).mockImplementation(() => [
{ result: 18 },
{ result: "USDT" },
]);
(tokenConverter.publicClient.simulateContract as jest.Mock).mockImplementation(() => ({
result: [1000000000000000000n, 1000000000000000000n],
}));

(SmartRouter.getBestTrade as jest.Mock).mockImplementationOnce(() => {
throw new Error("Cannot find a valid swap route");
Expand All @@ -113,13 +115,7 @@ describe("Token Converter", () => {

test("should return trade with low price impact", async () => {
const { tokenConverter } = createTokenConverterInstance();
(tokenConverter.publicClient.multicall as jest.Mock).mockImplementation(() => [
{ result: 18 },
{ result: "USDT" },
]);
(tokenConverter.publicClient.simulateContract as jest.Mock).mockImplementation(() => ({
result: [1000000000000000000n, 1000000000000000000n],
}));

const [trade] = await tokenConverter.getBestTrade(
addresses.USDCPrimeConverter,
addresses.WBNB,
Expand Down Expand Up @@ -169,14 +165,7 @@ describe("Token Converter", () => {
});

test("should call getBestTrade again if price impact is high with lower amount", async () => {
const { tokenConverter, subscriberMock, pancakeSwapProvider } = createTokenConverterInstance();
(tokenConverter.publicClient.multicall as jest.Mock).mockImplementation(() => [
{ result: 18 },
{ result: "USDT" },
]);
(tokenConverter.publicClient.simulateContract as jest.Mock).mockImplementation(() => ({
result: [1000000000000000000n, 1000000000000000000n],
}));
const { subscriberMock, pancakeSwapProvider } = createTokenConverterInstance();

const pancakeSwapProviderMock = jest
.spyOn(PancakeSwapProvider.prototype, "getBestTrade")
Expand Down Expand Up @@ -489,7 +478,7 @@ describe("Token Converter", () => {

test("should report error if reduce reserves is unsuccessful", async () => {
const { tokenConverter, subscriberMock } = createTokenConverterInstance();
(tokenConverter.walletClient.writeContract as jest.Mock).mockImplementation(() => {
(tokenConverter.walletClient.writeContract as jest.Mock).mockImplementationOnce(() => {
throw new Error("NETWORK ERROR");
});

Expand Down Expand Up @@ -627,6 +616,7 @@ describe("Token Converter", () => {

test("should execute the release of funds", async () => {
const { tokenConverter, subscriberMock } = createTokenConverterInstance();

await tokenConverter.releaseFunds({
[addresses.stableCoinComptroller]: [addresses.WBNB],
[addresses.coreComptroller]: [addresses.BUSD],
Expand All @@ -650,8 +640,8 @@ describe("Token Converter", () => {

test("should report error", async () => {
const { tokenConverter, subscriberMock } = createTokenConverterInstance();
(tokenConverter.walletClient.writeContract as jest.Mock).mockImplementationOnce(() => {
throw new Error("Failed Transation");
(tokenConverter.walletClient.writeContract as jest.Mock).mockImplementation(() => {
throw new Error("Failed Transaction");
});

await tokenConverter.releaseFunds({
Expand All @@ -669,7 +659,7 @@ describe("Token Converter", () => {
expect(subscriberMock).toHaveBeenCalledWith({
type: "ReleaseFunds",
trx: undefined,
error: "Failed Transation",
error: "Failed Transaction",
blockNumber: undefined,
context: [addresses.stableCoinComptroller, [addresses.WBNB]],
});
Expand All @@ -695,7 +685,8 @@ describe("Token Converter", () => {
describe("checkAndRequestAllowance", () => {
test("should request approval if needed", async () => {
const { tokenConverter } = createTokenConverterInstance();
(tokenConverter.publicClient.readContract as jest.Mock).mockImplementationOnce(() => 0n);
(tokenConverter.walletClient.writeContract as jest.Mock).mockReset();
(publicClient.readContract as jest.Mock).mockImplementationOnce(() => 0n);

await tokenConverter.checkAndRequestAllowance(
addresses.usdcHolder,
Expand All @@ -714,7 +705,8 @@ describe("Token Converter", () => {

test("should do nothing if already approved", async () => {
const { tokenConverter } = createTokenConverterInstance();
(tokenConverter.publicClient.readContract as jest.Mock).mockImplementationOnce(() => 2000000000000000000n);
(tokenConverter.walletClient.writeContract as jest.Mock).mockReset();
(publicClient.readContract as jest.Mock).mockImplementationOnce(() => 2000000000000000000n);

await tokenConverter.checkAndRequestAllowance(
addresses.usdcHolder,
Expand All @@ -730,11 +722,7 @@ describe("Token Converter", () => {
describe("arbitrage", () => {
test("should simulate arbitrage", async () => {
const { tokenConverter, subscriberMock } = createTokenConverterInstance({ simulate: true });
(tokenConverter.publicClient.getBlock as jest.Mock).mockImplementation(() => ({ timestamp: 1713214109n }));
(tokenConverter.publicClient.waitForTransactionReceipt as jest.Mock).mockImplementation(() => ({
blockNumber: 23486902n,
}));

(tokenConverter.walletClient.writeContract as jest.Mock).mockReset();
const tokenConverterMock = jest
.spyOn(TokenConverter.prototype, "checkAndRequestAllowance")
.mockImplementationOnce(jest.fn());
Expand Down Expand Up @@ -786,14 +774,10 @@ describe("Token Converter", () => {

test("should arbitrage and check approvals if minIncome is negative", async () => {
const { tokenConverter, subscriberMock } = createTokenConverterInstance();
(tokenConverter.publicClient.getBlock as jest.Mock).mockImplementation(() => ({ timestamp: 1713214109n }));
(tokenConverter.publicClient.waitForTransactionReceipt as jest.Mock).mockImplementation(() => ({
blockNumber: 23486902n,
}));
const tokenConverterMock = jest
.spyOn(TokenConverter.prototype, "checkAndRequestAllowance")
.mockImplementationOnce(jest.fn());

(walletClient.writeContract as jest.Mock).mockImplementation(() => "0xtransactionHash");
await tokenConverter.arbitrage(addresses.USDCPrimeConverter, mockTrade, 1000000000000000000000n, -10000n);

expect(tokenConverterMock).toHaveBeenNthCalledWith(
Expand Down Expand Up @@ -845,11 +829,8 @@ describe("Token Converter", () => {

test("should handle error calling arbitrage", async () => {
const { tokenConverter, subscriberMock } = createTokenConverterInstance();
(tokenConverter.publicClient.getBlock as jest.Mock).mockImplementation(() => ({ timestamp: 1713214109n }));
(tokenConverter.publicClient.waitForTransactionReceipt as jest.Mock).mockImplementation(() => ({
blockNumber: 23486902n,
}));
(tokenConverter.walletClient.writeContract as jest.Mock).mockImplementation(() => {

(tokenConverter.walletClient.writeContract as jest.Mock).mockImplementationOnce(() => {
throw new Error("NETWORK ERROR");
});

Expand Down Expand Up @@ -880,13 +861,6 @@ describe("Token Converter", () => {
describe("prepareConversion", () => {
test("should correctly return conversion arguments", async () => {
const { tokenConverter, subscriberMock } = createTokenConverterInstance();
(tokenConverter.publicClient.multicall as jest.Mock).mockImplementation(() => [
{ result: 18 },
{ result: "USDT" },
]);
(tokenConverter.publicClient.simulateContract as jest.Mock).mockImplementation(() => ({
result: [1000000000000000000n, 1000000000000000000n],
}));

const arbitrageArgs = await tokenConverter.prepareConversion(
addresses.USDCPrimeConverter,
Expand All @@ -895,7 +869,7 @@ describe("Token Converter", () => {
1000000000000000000000n,
);

expect(arbitrageArgs?.amount).toEqual(1000000000000000000n);
expect(arbitrageArgs?.amount).toEqual(8904975230019520420n);
expect(arbitrageArgs?.trade.inputToken).toEqual({
address: "0xbb4cdb9cbd36b01bd1cbaebf2de08d9173bc095c",
amount: {
Expand Down Expand Up @@ -935,7 +909,7 @@ describe("Token Converter", () => {
expect(arbitrageArgs?.trade.path).toEqual(
"0xcf6bb5389c92bdda8a3747ddb454cb7a64626c630009c4bb4cdb9cbd36b01bd1cbaebf2de08d9173bc095c",
);
expect(arbitrageArgs?.minIncome).toEqual(-7904975230019520420n);
expect(arbitrageArgs?.minIncome).toEqual(991095024769980479580n);

expect(subscriberMock).toHaveBeenCalledWith({
type: "GetBestTrade",
Expand All @@ -956,23 +930,12 @@ describe("Token Converter", () => {
},
tokenToReceiveFromConverter: "0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c",
tokenToSendToConverter: "0x8AC76a51cc950d9822D68b83fE1Ad97B32Cd580d",
tradeAmount: {
amountIn: 1000000000000000000n,
amountOut: 1000000000000000000n,
},
},
});
});

test("should handle error calling prepareConversion", async () => {
const { tokenConverter, subscriberMock } = createTokenConverterInstance();
(tokenConverter.publicClient.multicall as jest.Mock).mockImplementation(() => [
{ result: 18 },
{ result: "USDT" },
]);
(tokenConverter.publicClient.simulateContract as jest.Mock).mockImplementation(() => ({
result: [1000000000000000000n, 1000000000000000000n],
}));

(SmartRouter.getPriceImpact as jest.Mock).mockImplementation(() => new Percent(2n, 1000n));
(SmartRouter.getBestTrade as jest.Mock).mockImplementation(() => {
Expand Down
11 changes: 1 addition & 10 deletions packages/keeper-bots/src/converter-bot/TokenConverter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import {
vBnbAdminAbi,
venusLensAbi,
} from "../config/abis/generated";
import { tokenConverterAbi } from "../config/abis/generated";
import getAddresses from "../config/addresses";
import { SwapProvider } from "../providers";
import { TradeRoute } from "../types";
Expand Down Expand Up @@ -391,16 +390,8 @@ export class TokenConverter extends BotBase {
let trade;
let amount;

// [amount transferred out of converter, amount transferred in]
const { result: updatedAmountIn } = await this.publicClient.simulateContract({
address: tokenConverter,
abi: tokenConverterAbi,
functionName: "getUpdatedAmountIn",
args: [amountOut, assetIn, assetOut],
});

try {
[trade, amount] = await this.getBestTrade(tokenConverter, assetOut, assetIn, updatedAmountIn[0]);
[trade, amount] = await this.getBestTrade(tokenConverter, assetOut, assetIn, amountOut);
} catch (e) {
error = (e as Error).message;
} finally {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,13 @@ import { Address } from "viem";
import getConfig from "../../config";
import { coreComptrollerAbi, vBep20InterfaceAbi } from "../../config/abis/generated";
import getAddresses from "../../config/addresses";
import getPublicClient from "../../config/clients/publicClient";
import publicClient from "../../config/clients/publicClient";
import type { PoolAddressArray } from "../types";

export const getCoreMarkets = async (): Promise<PoolAddressArray[]> => {
const config = getConfig();
if (config.network.name === "bscmainnet" || config.network.name === "bsctestnet") {
const addresses = getAddresses();
const publicClient = getPublicClient();
const markets = await publicClient.readContract({
address: addresses.Unitroller as Address,
abi: coreComptrollerAbi,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,11 @@ import { Address } from "viem";
import { vBep20InterfaceAbi } from "../../config/abis/generated";
import { poolLensAbi } from "../../config/abis/generated";
import getAddresses from "../../config/addresses";
import getPublicClient from "../../config/clients/publicClient";
import publicClient from "../../config/clients/publicClient";
import type { PoolAddressArray } from "../types";

export const getIsolatedMarkets = async (): Promise<PoolAddressArray[]> => {
const addresses = getAddresses();
const publicClient = getPublicClient();
const pools = await publicClient.readContract({
address: addresses.PoolLens as Address,
abi: poolLensAbi,
Expand Down
Loading

0 comments on commit 2677406

Please sign in to comment.