Skip to content

Commit

Permalink
Merge pull request #54 from VenusProtocol/refactor-create-base-class
Browse files Browse the repository at this point in the history
Refactor create base class
  • Loading branch information
coreyar authored Aug 26, 2024
2 parents d054cc5 + 37a5f84 commit c99a4e3
Show file tree
Hide file tree
Showing 27 changed files with 299 additions and 353 deletions.
1 change: 0 additions & 1 deletion packages/cli/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,6 @@ Usage: venus release-funds [options]
Options:
--simulate Simulate transactions (default: false)
--verbose Verbose logging (default: false)
--accrue-interest Accrue Interest (default: false)
--no-reduce-reserves Reduce BNB Reserves
-d, --debug Add debug logging (default: false)
Expand Down
132 changes: 57 additions & 75 deletions packages/cli/source/commands/convert.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { option } from "pastel";
import { Box, Spacer, Text, useApp, useStderr } from "ink";
import zod from "zod";
import { parseUnits } from "viem";
import { TokenConverter, PancakeSwapProvider, UniswapProvider, BalanceResult } from "@venusprotocol/keeper-bots";
import { TokenConverter, PancakeSwapProvider, UniswapProvider } from "@venusprotocol/keeper-bots";
import { stringifyBigInt, getConverterConfigId } from "../utils/index.js";
import { Options, Title, BorderBox } from "../components/index.js";
import { reducer, defaultState } from "../state/convert.js";
Expand Down Expand Up @@ -152,10 +152,7 @@ export default function Convert({ options }: Props) {
const tokenConverter = new TokenConverter({
subscriber: dispatch,
simulate: !!simulate,
verbose: debug,
swapProvider: network?.includes("bsc")
? new PancakeSwapProvider({ subscriber: dispatch })
: new UniswapProvider({ subscriber: dispatch }),
swapProvider: network?.includes("bsc") ? PancakeSwapProvider : UniswapProvider,
});

do {
Expand All @@ -173,84 +170,69 @@ export default function Convert({ options }: Props) {
// @todo check if we need to release funds or if there are already enough funds to make our trade
await tokenConverter.releaseFundsForConversions(potentialConversions);
}
await Promise.allSettled(
potentialConversions.map(async (t: BalanceResult) => {
let amountOut = t.assetOut.balance;

const vTokenAddress = t.assetOutVTokens.core || t.assetOutVTokens.isolated![0]![1];
const { underlyingPriceUsd, underlyingUsdValue, underlyingDecimals } = await tokenConverter.getUsdValue(
t.assetOut.address,
vTokenAddress,
amountOut,
);
for (const t of potentialConversions) {
let amountOut = t.assetOut.balance;

if (+underlyingUsdValue > minTradeUsd) {
if (+underlyingUsdValue > maxTradeUsd) {
amountOut = parseUnits((maxTradeUsd / +underlyingPriceUsd.toString()).toString(), underlyingDecimals);
}
const vTokenAddress = t.assetOutVTokens.core || t.assetOutVTokens.isolated![0]![1];
const { underlyingPriceUsd, underlyingUsdValue, underlyingDecimals } = await tokenConverter.getUsdValue(
t.assetOut.address,
vTokenAddress,
amountOut,
);

const arbitrageArgs = await tokenConverter.prepareConversion(
t.tokenConverter,
t.assetOut.address,
t.assetIn.address,
amountOut,
);
if (+underlyingUsdValue > minTradeUsd) {
if (+underlyingUsdValue > maxTradeUsd) {
amountOut = parseUnits((maxTradeUsd / +underlyingPriceUsd.toString()).toString(), underlyingDecimals);
}

const { trade, amount, minIncome } = arbitrageArgs || {
trade: undefined,
amount: 0n,
minIncome: 0n,
};
const arbitrageArgs = await tokenConverter.prepareConversion(
t.tokenConverter,
t.assetOut.address,
t.assetIn.address,
amountOut,
);

const maxMinIncome = ((amount * BigInt(10000 + minIncomeBp)) / 10000n - amount) * -1n;
const { trade, amount, minIncome } = arbitrageArgs || {
trade: undefined,
amount: 0n,
minIncome: 0n,
};

if (trade && ((profitable && minIncome > 0n) || !profitable)) {
dispatch({
type: "ExecuteTrade",
context: {
converter: t.tokenConverter,
tokenToReceiveFromConverter: t.assetOut.address,
tokenToSendToConverter: t.assetIn.address,
amount,
minIncome,
percentage: Number((minIncome * 10000000n) / amount) / 10000000,
maxMinIncome,
},
});
const maxMinIncome = ((amount * BigInt(10000 + minIncomeBp)) / 10000n - amount) * -1n;

await tokenConverter.arbitrage(t.tokenConverter, trade, amount, minIncome);
} else if (t.accountBalanceAssetOut < minIncome * -1n) {
dispatch({
type: "ExecuteTrade",
error: "Insufficient wallet balance to pay min income",
context: {
converter: t.tokenConverter,
tokenToReceiveFromConverter: t.assetOut.address,
tokenToSendToConverter: t.assetIn.address,
amount,
minIncome,
percentage: Number((minIncome * 10000000n) / amount) / 10000000,
maxMinIncome,
},
});
} else if (minIncome < 1 && minIncome * -1n > maxMinIncome * -1n) {
dispatch({
type: "ExecuteTrade",
error: "Min income too high",
context: {
converter: t.tokenConverter,
tokenToReceiveFromConverter: t.assetOut.address,
tokenToSendToConverter: t.assetIn.address,
amount,
minIncome,
percentage: Number((minIncome * 10000000n) / amount) / 10000000,
maxMinIncome,
},
});
}
const context = {
converter: t.tokenConverter,
tokenToReceiveFromConverter: t.assetOut.address,
tokenToSendToConverter: t.assetIn.address,
amount,
minIncome,
percentage: Number(minIncome) && Number(amount) && Number((minIncome * 10000000n) / amount) / 10000000,
maxMinIncome,
};
if (profitable && minIncome < 0) {
dispatch({
error: "Conversion is not profitable",
type: "ExecuteTrade",
context,
});
} else if (minIncome < 1 && minIncome * -1n > maxMinIncome * -1n) {
dispatch({
type: "ExecuteTrade",
error: "Min income too high",
context,
});
} else if (t.accountBalanceAssetOut < minIncome * -1n && !profitable) {
dispatch({
error: "Insufficient wallet balance to pay min income",
type: "ExecuteTrade",
context,
});
} else if (trade) {
await tokenConverter.arbitrage(t.tokenConverter, trade, amount, minIncome);
}
}),
);
}
}
} while (loop);
};
if (converter || assetIn || assetOut) {
Expand Down
15 changes: 1 addition & 14 deletions packages/cli/source/commands/releaseFunds.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,16 +29,6 @@ export const options = zod.object({
}),
)
.optional(),
verbose: zod
.boolean()
.default(false)
.describe(
option({
description: "Verbose logging",
alias: "v",
}),
)
.optional(),
accrueInterest: zod
.boolean()
.default(false)
Expand Down Expand Up @@ -136,10 +126,7 @@ function ReleaseFunds({ options = {} }: Props) {
const tokenConverter = new TokenConverter({
subscriber: dispatch,
simulate: !!simulate,
verbose: false,
swapProvider: network?.includes("bsc")
? new PancakeSwapProvider({ subscriber: dispatch, verbose: false })
: new UniswapProvider({ subscriber: dispatch, verbose: false }),
swapProvider: network?.includes("bsc") ? PancakeSwapProvider : UniswapProvider,
});
const corePoolMarkets = await getCoreMarkets();
const isolatedPoolsMarkets = await getIsolatedMarkets();
Expand Down
4 changes: 2 additions & 2 deletions packages/cli/source/state/convert.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Address } from "viem";
import {
Message,
ConverterBotMessage,
GetBestTradeMessage,
ArbitrageMessage,
PotentialConversionsMessage,
Expand Down Expand Up @@ -43,7 +43,7 @@ export const defaultState = {
messages: [],
};

export const reducer = (state: State, action: Message | ExecuteTradeMessage): State => {
export const reducer = (state: State, action: ConverterBotMessage | ExecuteTradeMessage): State => {
switch (action.type) {
case "PotentialConversions":
case "GetBestTrade":
Expand Down
6 changes: 3 additions & 3 deletions packages/cli/source/state/releaseFunds.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { Message } from "@venusprotocol/keeper-bots";
import { ConverterBotMessage } from "@venusprotocol/keeper-bots";

interface State {
releasedFunds: {
trx: string | undefined;
error: string | undefined;
error: string | string[] | undefined;
context: [`0x${string}`, readonly `0x${string}`[]];
}[];
}
Expand All @@ -12,7 +12,7 @@ export const defaultState = {
releasedFunds: [],
};

export const reducer = (state: State, action: Message): State => {
export const reducer = (state: State, action: ConverterBotMessage): State => {
switch (action.type) {
case "ReleaseFunds": {
const releasedFunds = [...state.releasedFunds];
Expand Down
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=
3 changes: 1 addition & 2 deletions packages/keeper-bots/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,7 @@
"hardhat": "^2.19.5",
"jsbi": "^3.2.5",
"urql": "^3.0.3",
"viem": "^2.7.1",
"winston": "^3.11.0"
"viem": "^2.7.1"
},
"devDependencies": {
"@typechain/hardhat": "^6.1.2",
Expand Down
47 changes: 47 additions & 0 deletions packages/keeper-bots/src/bot-base.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import getConfig from "./config";
import type { SUPPORTED_CHAINS } from "./config/chains";
import publicClient from "./config/clients/publicClient";
import walletClient from "./config/clients/walletClient";
import { ConverterBotMessage } from "./converter-bot/types";
import { SwapProvider } from "./providers";

const config = getConfig();

class BotBase {
protected chainName: SUPPORTED_CHAINS;
protected subscriber: undefined | ((msg: ConverterBotMessage) => void);
protected simulate: boolean;
protected swapProvider: SwapProvider;
public publicClient: typeof publicClient;
public walletClient: typeof walletClient;

constructor({
subscriber,
swapProvider,
simulate,
}: {
subscriber?: (msg: ConverterBotMessage) => void;
swapProvider: typeof SwapProvider;
simulate: boolean;
}) {
this.subscriber = subscriber;
this.swapProvider = new swapProvider({ subscriber });
this.publicClient = publicClient;
this.walletClient = walletClient;
this.simulate = simulate;
this.chainName = config.network.name;
}
protected sendMessage({
type,
trx = undefined,
error = undefined,
context = undefined,
blockNumber = undefined,
}: Partial<ConverterBotMessage>) {
if (this.subscriber) {
this.subscriber({ type, trx, error, context, blockNumber } as ConverterBotMessage);
}
}
}

export default BotBase;
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();
Loading

0 comments on commit c99a4e3

Please sign in to comment.