Skip to content

Commit

Permalink
Merge pull request #65 from VenusProtocol/develop
Browse files Browse the repository at this point in the history
Publish release funds updates
  • Loading branch information
coreyar authored Sep 30, 2024
2 parents 1f82efa + ef27162 commit 9a13c90
Show file tree
Hide file tree
Showing 13 changed files with 1,471 additions and 704 deletions.
2 changes: 1 addition & 1 deletion packages/cli/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@venusprotocol/cli",
"version": "1.6.0",
"version": "1.6.1-dev.2",
"license": "MIT",
"bin": {
"venus": "dist/venus.js"
Expand Down
10 changes: 10 additions & 0 deletions packages/cli/source/commands/convert.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,16 @@ export default function Convert({ options }: Props) {
} else if (trade) {
await tokenConverter.arbitrage(t.tokenConverter, trade, amount, minIncome);
}
} else {
dispatch({
error: `Swap amount too low (${assetOutUsdValue} USD)`,
type: "GetBestTrade",
context: {
converter: t.tokenConverter,
tokenToReceiveFromConverter: t.assetOut.address,
tokenToSendToConverter: t.assetIn.address,
},
});
}
}
} while (loop);
Expand Down
2 changes: 1 addition & 1 deletion packages/cli/source/commands/releaseFunds.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ function ReleaseFunds({ options = {} }: Props) {
const withBalances = allPools.reduce((acc, curr) => {
const tokensWithBalance = curr[1].filter(t => tokensWithBalances.has(t.underlyingAddress));
if (tokensWithBalance.length) {
acc[curr[0]] = tokensWithBalance.map(t => t.vTokenAddress);
acc[curr[0]] = tokensWithBalance.map(t => t.underlyingAddress);
}
return acc;
}, {} as Record<Address, readonly Address[]>);
Expand Down
2 changes: 1 addition & 1 deletion packages/keeper-bots/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@venusprotocol/keeper-bots",
"version": "1.1.0",
"version": "1.1.1-dev.2",
"description": "",
"scripts": {
"dev": "tsc --watch",
Expand Down
18 changes: 15 additions & 3 deletions packages/keeper-bots/src/converter-bot/TokenConverter.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,7 @@ describe("Token Converter", () => {
});

test("should call getBestTrade again if price impact is high with lower amount", async () => {
const { subscriberMock, pancakeSwapProvider } = createTokenConverterInstance();
const { subscriberMock, pancakeSwapProvider, tokenConverter } = createTokenConverterInstance();

const pancakeSwapProviderMock = jest
.spyOn(PancakeSwapProvider.prototype, "getBestTrade")
Expand All @@ -180,7 +180,20 @@ describe("Token Converter", () => {
return new Percent(9n, 1000n);
});

const [trade] = await pancakeSwapProvider.getBestTrade(
(publicClient.simulateContract as unknown as jest.Mock).mockImplementation(
jest.fn(() => {
if (called) {
return {
result: [1000000000000000000n, 750000000000000000n],
};
}
return {
result: [1000000000000000000n, 1000000000000000000n],
};
}),
);

const [trade] = await tokenConverter.getBestTrade(
addresses.USDCPrimeConverter,
addresses.WBNB,
addresses.USDC,
Expand Down Expand Up @@ -231,7 +244,6 @@ describe("Token Converter", () => {

expect(pancakeSwapProviderMock).toHaveBeenNthCalledWith(
3,
addresses.USDCPrimeConverter,
addresses.WBNB,
addresses.USDC,
750000000000000000n,
Expand Down
29 changes: 27 additions & 2 deletions packages/keeper-bots/src/converter-bot/TokenConverter.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Fraction } from "@pancakeswap/sdk";
import { Fraction, Percent } from "@pancakeswap/sdk";
import { Address, BaseError, ContractFunctionRevertedError, erc20Abi, formatUnits } from "viem";

import BotBase from "../bot-base";
Expand All @@ -10,6 +10,7 @@ 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 @@ -63,7 +64,31 @@ export class TokenConverter extends BotBase {
amount: bigint,
fixedPairs?: boolean,
): Promise<[TradeRoute, bigint]> {
return this.swapProvider.getBestTrade(tokenConverter, swapFrom, swapTo, amount, fixedPairs);
// [amount transferred out of converter, amount transferred in]
const { result: updatedAmountIn } = await this.publicClient.simulateContract({
address: tokenConverter,
abi: tokenConverterAbi,
functionName: "getUpdatedAmountIn",
args: [amount, swapTo, swapFrom],
});

const [trade, priceImpact] = await this.swapProvider.getBestTrade(swapFrom, swapTo, updatedAmountIn[1], fixedPairs);

if (priceImpact && priceImpact.greaterThan(new Percent(5n, 1000n))) {
this.sendMessage({
type: "GetBestTrade",
error: "High price impact",
context: {
converter: tokenConverter,
tokenToReceiveFromConverter: swapFrom,
tokenToSendToConverter: swapTo,
priceImpact: priceImpact.toFixed(),
},
});

return this.getBestTrade(tokenConverter, swapFrom, swapTo, (updatedAmountIn[1] * 75n) / 100n, fixedPairs);
}
return [trade, updatedAmountIn[0]];
}

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Address } from "viem";

import getConfig from "../../config";
import { coreComptrollerAbi, vBep20InterfaceAbi } from "../../config/abis/generated";
import { coreComptrollerAbi, coreVTokenAbi } from "../../config/abis/generated";
import getAddresses from "../../config/addresses";
import publicClient from "../../config/clients/publicClient";
import type { PoolAddressArray } from "../types";
Expand All @@ -16,10 +16,11 @@ export const getCoreMarkets = async (): Promise<PoolAddressArray[]> => {
functionName: "getAllMarkets",
});

// @ts-expect-error not infinte
const underlyingAddresses = await publicClient.multicall({
contracts: markets.map(m => ({
address: m,
abi: vBep20InterfaceAbi,
abi: coreVTokenAbi,
functionName: "underlying",
args: [],
})),
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { Address } from "viem";

import { vBep20InterfaceAbi } from "../../config/abis/generated";
import { poolLensAbi } from "../../config/abis/generated";
import { ilVTokenAbi, poolLensAbi } from "../../config/abis/generated";
import getAddresses from "../../config/addresses";
import publicClient from "../../config/clients/publicClient";
import type { PoolAddressArray } from "../types";
Expand All @@ -16,11 +15,12 @@ export const getIsolatedMarkets = async (): Promise<PoolAddressArray[]> => {
});

const underlyingAddressesByPool = await Promise.all(
// @ts-expect-error not infinte
pools.map(async p => {
return await publicClient.multicall({
contracts: p.vTokens.map(m => ({
address: m.vToken,
abi: vBep20InterfaceAbi,
abi: ilVTokenAbi,
functionName: "underlying",
args: [],
})),
Expand Down
33 changes: 5 additions & 28 deletions packages/keeper-bots/src/providers/pancake-swap.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import { Client as UrqlClient, createClient } from "urql/core";
import { Address, Hex, encodePacked, erc20Abi } from "viem";

import getConfig from "../config";
import { tokenConverterAbi } from "../config/abis/generated";
import type { SUPPORTED_CHAINS } from "../config/chains";
import { chains } from "../config/chains";
import { ConverterBotMessage } from "../converter-bot/types";
Expand Down Expand Up @@ -107,32 +106,23 @@ class PancakeSwapProvider extends SwapProvider {
};

async getBestTrade(
tokenConverter: Address,
swapFrom: Address,
swapTo: Address,
amount: bigint,
fixedPairs: boolean = false,
): Promise<[TradeRoute, bigint]> {
): Promise<[TradeRoute, Percent | null]> {
const swapFromToken = await this.getToken(swapFrom);
const swapToToken = await this.getToken(swapTo);

let trade;
let error;
let priceImpact;

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

try {
const candidatePools = await this.getCandidatePools(swapFromToken, swapToToken, fixedPairs);

const response = await SmartRouter.getBestTrade(
CurrencyAmount.fromRawAmount(swapToToken, updatedAmountIn[1]),
CurrencyAmount.fromRawAmount(swapToToken, amount),
swapFromToken,
TradeType.EXACT_OUTPUT,
{
Expand All @@ -145,6 +135,8 @@ class PancakeSwapProvider extends SwapProvider {
},
);

priceImpact = SmartRouter.getPriceImpact(response);

if (response) {
trade = {
inputToken: {
Expand All @@ -158,7 +150,6 @@ class PancakeSwapProvider extends SwapProvider {
path: this.encodeExactInputPath(response.routes[0]),
};
}
priceImpact = SmartRouter.getPriceImpact(response);
} catch (e) {
const message = (e as Error).message;
error = `Error getting best trade - ${message}`;
Expand All @@ -174,21 +165,7 @@ class PancakeSwapProvider extends SwapProvider {
throw new Error("No trade found");
}

if (priceImpact.greaterThan(new Percent(5n, 1000n))) {
this.sendMessage({
type: "GetBestTrade",
error: "High price impact",
context: {
converter: tokenConverter,
tokenToReceiveFromConverter: swapFromToken.address!,
tokenToSendToConverter: swapToToken.address!,
priceImpact: priceImpact.toFixed(),
},
});

return this.getBestTrade(tokenConverter, swapFrom, swapTo, (updatedAmountIn[1] * 75n) / 100n, fixedPairs);
}
return [trade, updatedAmountIn[0]];
return [trade, priceImpact];
}

/**
Expand Down
5 changes: 2 additions & 3 deletions packages/keeper-bots/src/providers/swap-provider.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { Percent } from "@pancakeswap/sdk";
import { Token } from "@uniswap/sdk-core";
import { Pool } from "@uniswap/v3-sdk";
import { Address } from "viem";
Expand Down Expand Up @@ -45,8 +46,6 @@ class SwapProvider {
}

async getBestTrade(
// eslint-disable-next-line
tokenConverter: Address,
// eslint-disable-next-line
swapFrom: Address,
// eslint-disable-next-line
Expand All @@ -55,7 +54,7 @@ class SwapProvider {
amount: bigint,
// eslint-disable-next-line
fixedPairs?: boolean,
): Promise<[TradeRoute, bigint]> {
): Promise<[TradeRoute, Percent | null]> {
throw new Error("Not Implemented Error");
}
}
Expand Down
24 changes: 5 additions & 19 deletions packages/keeper-bots/src/providers/uniswap.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Fraction } from "@pancakeswap/sdk";
import { Fraction, Percent as PancakePercent } from "@pancakeswap/sdk";
import { IRoute } from "@uniswap/router-sdk";
import { ChainId, Currency, CurrencyAmount, Percent, Token, TradeType } from "@uniswap/sdk-core";
import { AlphaRouter, SwapOptionsSwapRouter02, SwapType } from "@uniswap/smart-order-router";
Expand All @@ -8,7 +8,6 @@ import JSBI from "jsbi";
import { Address, Hex, encodePacked, erc20Abi } from "viem";

import getConfig from "../config";
import { tokenConverterAbi } from "../config/abis/generated";
import type { SUPPORTED_CHAINS } from "../config/chains";
import { chains } from "../config/chains";
import { ConverterBotMessage } from "../converter-bot/types";
Expand Down Expand Up @@ -61,23 +60,10 @@ class UniswapProvider extends SwapProvider {
throw new Error(`Unable to fetch token details for ${address}`);
}

async getBestTrade(
tokenConverter: Address,
swapFrom: Address,
swapTo: Address,
amount: bigint,
): Promise<[TradeRoute, bigint]> {
async getBestTrade(swapFrom: Address, swapTo: Address, amount: bigint): Promise<[TradeRoute, PancakePercent | null]> {
const swapFromToken = await this.getToken(swapFrom);
const swapToToken = await this.getToken(swapTo);

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

const provider = new ethers.providers.JsonRpcProvider(config.rpcUrl);
const router = new AlphaRouter({
chainId: config.network.id as ChainId,
Expand All @@ -91,14 +77,14 @@ class UniswapProvider extends SwapProvider {
};
let error;
let trade;

try {
const response = await router.route(
CurrencyAmount.fromRawAmount(swapToToken, JSBI.BigInt(updatedAmountIn[1].toString())),
CurrencyAmount.fromRawAmount(swapToToken, JSBI.BigInt(amount.toString())),
swapFromToken,
TradeType.EXACT_OUTPUT,
options,
);

if (response) {
const inputCurrency = response.trade.swaps[0].inputAmount;
const outputCurrency = response.trade.swaps[response.trade.swaps.length - 1].outputAmount;
Expand Down Expand Up @@ -134,7 +120,7 @@ class UniswapProvider extends SwapProvider {
throw new Error("No trade found");
}

return [trade, updatedAmountIn[0]];
return [trade, null];
}

/**
Expand Down
20 changes: 15 additions & 5 deletions packages/keeper-bots/wagmi.config.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,19 @@
import ilComptrollerArtifact from "@venusprotocol/isolated-pools/artifacts/contracts/Comptroller.sol/Comptroller.json" assert { type: "json" };
import poolLensArtifact from "@venusprotocol/isolated-pools/artifacts/contracts/Lens/PoolLens.sol/PoolLens.json" assert { type: "json" };
import ilVTokenArtifact from "@venusprotocol/isolated-pools/artifacts/contracts/VToken.sol/VToken.json" assert { type: "json" };
import liquidationOperatorArtifact from "@venusprotocol/keeper-bot-contracts/artifacts/contracts/operators/LiquidationOperator.sol/LiquidationOperator.json" assert { type: "json" };
import tokenConverterOperatorArtifact from "@venusprotocol/keeper-bot-contracts/artifacts/contracts/operators/TokenConverterOperator.sol/TokenConverterOperator.json" assert { type: "json" };
import resilientOracleArtifact from "@venusprotocol/oracle/artifacts/contracts/ResilientOracle.sol/ResilientOracle.json" assert { type: "json" };
import protocolShareReserveArtifact from "@venusprotocol/protocol-reserve/artifacts/contracts/ProtocolReserve/ProtocolShareReserve.sol/ProtocolShareReserve.json" assert { type: "json" };
import tokenConverterArtifact from "@venusprotocol/protocol-reserve/artifacts/contracts/TokenConverter/AbstractTokenConverter.sol/AbstractTokenConverter.json" assert { type: "json" };
import vBnbAdminArtifact from "@venusprotocol/venus-protocol/artifacts/contracts/Admin/VBNBAdmin.sol/VBNBAdmin.json" assert { type: "json" };
import diamondComptrollerArtifact from "@venusprotocol/venus-protocol/artifacts/contracts/Comptroller/Diamond/DiamondConsolidated.sol/DiamondConsolidated.json" assert { type: "json" };
import venusLensArtifact from "@venusprotocol/venus-protocol/artifacts/contracts/Lens/VenusLens.sol/VenusLens.json" assert { type: "json" };
import coreVTokenArtifact from "@venusprotocol/venus-protocol/artifacts/contracts/Tokens/VTokens/VBep20Delegate.sol/VBep20Delegate.json" assert { type: "json" };
import vBep20InterfaceArtifact from "@venusprotocol/venus-protocol/artifacts/contracts/Tokens/VTokens/VTokenInterfaces.sol/VBep20Interface.json" assert { type: "json" };
import { defineConfig } from "@wagmi/cli";
import { Abi } from "abitype";

const getExternalContracts = async (): Promise<{ name: string; abi: Abi }[]> => [
{
abi: vBep20InterfaceArtifact.abi as Abi,
name: "VBep20Interface",
},
{
abi: poolLensArtifact.abi as Abi,
name: "PoolLens",
Expand All @@ -28,6 +26,18 @@ const getExternalContracts = async (): Promise<{ name: string; abi: Abi }[]> =>
abi: ilComptrollerArtifact.abi as Abi,
name: "IlComptroller",
},
{
abi: ilVTokenArtifact.abi as Abi,
name: "ilVToken",
},
{
abi: resilientOracleArtifact.abi as Abi,
name: "resilientOracle",
},
{
abi: liquidationOperatorArtifact.abi as Abi,
name: "liquidationOperator",
},
{
abi: coreVTokenArtifact.abi as Abi,
name: "CoreVToken",
Expand Down
Loading

0 comments on commit 9a13c90

Please sign in to comment.