Skip to content

Commit

Permalink
Merge pull request #78 from yuichiroaoki/without_1INCH
Browse files Browse the repository at this point in the history
Without 1 inch
  • Loading branch information
yuichiroaoki authored May 29, 2022
2 parents f6818ef + 6bb273c commit ef65fa5
Show file tree
Hide file tree
Showing 22 changed files with 349 additions and 810 deletions.
76 changes: 9 additions & 67 deletions src/abis/Flashloan.json

Large diffs are not rendered by default.

44 changes: 9 additions & 35 deletions src/config.ts
Original file line number Diff line number Diff line change
@@ -1,39 +1,26 @@
import { ERC20Token } from "./constants/addresses";
import { ITrade } from "./interfaces/trade";
import { getBigNumber } from "./utils";

export const renderInterval = 1 * 1000;

// interval of price check (ms)
export const interval = 4 * 1000;

export const loanAmount = 10000;
export const diffAmount = 10; // Not enough amount to return loan
export const diffPercentage = 0.03;

//export const chainId = 1;// Ethereum
//export const chainId = 56;// Binance Smart Chain
export const chainId = 137; // Polygon

export const explorerURL = "https://polygonscan.com";

/**
* Token pair the bot trading
* baseToken -> tradingToken -> baseToken (ex: DAI -> WETH -> DAI)
* profits are sent in baseToken if a transaction is successful.
*/

export const baseTokens = [
// ERC20Token.DAI,
// ERC20Token.WETH,
ERC20Token.USDC,
ERC20Token.USDT,
// ERC20Token.WMATIC,
];

export const tradingTokens = [
ERC20Token.DAI,
ERC20Token.WETH,
ERC20Token.USDC,
ERC20Token.USDT,
ERC20Token.WMATIC,
export const tradingRoutes: ITrade[] = [
{
path: [ERC20Token.USDC, ERC20Token.DAI, ERC20Token.USDC],
protocols: [2, 0],
amountIn: getBigNumber(20000, ERC20Token.USDC.decimals),
},
];

/**
Expand All @@ -48,18 +35,5 @@ export const flashloanAddress: string =
* The bot can trade on UniswapV2 fork dexes(ex. SushiSwap) and UniswapV3
* For UniswapV2, you can trade between any token pair, but for UniswapV3, you have to check their pool fees and list them on src/price/uniswap/v3/fee.ts.
*/
// protocols the bot will use
export const protocols =
"POLYGON_SUSHISWAP,POLYGON_QUICKSWAP,POLYGON_APESWAP,POLYGON_JETSWAP,POLYGON_WAULTSWAP,POLYGON_UNISWAP_V3";

export const gasLimit = 15000000;
export const gasPrice = 100; // gwei

export const routeParts = [
[10000],
[8000, 2000],
[5000, 4000, 1000],
[5000, 3000, 1000, 1000],
[3000, 2000, 2000, 2000, 1000],
[2000, 2000, 2000, 2000, 1000, 1000],
];
85 changes: 42 additions & 43 deletions src/consoleUI/index.ts
Original file line number Diff line number Diff line change
@@ -1,46 +1,45 @@
import { Table } from "console-table-printer";
import { baseTokens, tradingTokens } from "../config";
const readline = require("readline");

export const initPriceTable = (p: Table, idx: number) => {
baseTokens.forEach(async (baseToken) => {
tradingTokens.forEach(async (tradingToken) => {
if (baseToken.address > tradingToken.address) {
p.addRow({
index: idx,

fromToken: (baseToken === tradingToken
? ""
: baseToken.symbol
).padEnd(6),
toToken: (baseToken === tradingToken
? ""
: tradingToken.symbol
).padEnd(6),

fromAmount: "".padStart(7),
toAmount: "".padStart(7),

difference: "".padStart(7),
percentage: "".padStart(5),

time: "".padStart(6),
timestamp: "".padStart(24),
});

idx++;
}
});
});
};

export const renderTables = (p: Table, pp: Table) => {
// console.clear();
readline.cursorTo(process.stdout, 0, 0);

p.printTable();

if (pp.table.rows.length > 0) {
pp.printTable();
}
};
// export const initPriceTable = (p: Table, idx: number) => {
// baseTokens.forEach(async (baseToken) => {
// tradingTokens.forEach(async (tradingToken) => {
// if (baseToken.address > tradingToken.address) {
// p.addRow({
// index: idx,

// fromToken: (baseToken === tradingToken
// ? ""
// : baseToken.symbol
// ).padEnd(6),
// toToken: (baseToken === tradingToken
// ? ""
// : tradingToken.symbol
// ).padEnd(6),

// fromAmount: "".padStart(7),
// toAmount: "".padStart(7),

// difference: "".padStart(7),
// percentage: "".padStart(5),

// time: "".padStart(6),
// timestamp: "".padStart(24),
// });

// idx++;
// }
// });
// });
// };

// export const renderTables = (p: Table, pp: Table) => {
// // console.clear();
// readline.cursorTo(process.stdout, 0, 0);

// p.printTable();

// if (pp.table.rows.length > 0) {
// pp.printTable();
// }
// };
1 change: 0 additions & 1 deletion src/constants/addresses.ts
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,6 @@ type PoolMap = { [pair: string]: string };
export const dodoV2Pool: PoolMap = {
WETH_USDC: "0x5333Eb1E32522F1893B7C9feA3c263807A02d561",
WMATIC_USDC: "0x10Dd6d8A29D489BEDE472CC1b22dc695c144c5c7",
USDT_USDC: "0xA0020444b98f67B77a3d6dE6E66aF11c87da086e",
};

type RouterMap = { [protocol: string]: string };
Expand Down
106 changes: 53 additions & 53 deletions src/debug.ts
Original file line number Diff line number Diff line change
@@ -1,64 +1,64 @@
require("dotenv").config();
import { ethers } from "ethers";
import * as ABI from "./abis/Flashloan.json";
import { IFlashloanRoute } from "./interfaces/main";
import { findPool, findRouter, findToken } from "./utils";
// require("dotenv").config();
// import { ethers } from "ethers";
// import * as ABI from "./abis/Flashloan.json";
// import { IFlashloanRoute } from "./interfaces/main";
// import { findPool, findRouter, findToken } from "./utils";

if (process.env.ALCHEMY_POLYGON_RPC_URL === undefined) {
throw new Error("Please set ALCHEMY_POLYGON_RPC_URL environment variable.");
}
// if (process.env.ALCHEMY_POLYGON_RPC_URL === undefined) {
// throw new Error("Please set ALCHEMY_POLYGON_RPC_URL environment variable.");
// }

const maticProvider = new ethers.providers.JsonRpcProvider(
process.env.ALCHEMY_POLYGON_RPC_URL
);
// const maticProvider = new ethers.providers.JsonRpcProvider(
// process.env.ALCHEMY_POLYGON_RPC_URL
// );

const inter = new ethers.utils.Interface(ABI.abi);
// const inter = new ethers.utils.Interface(ABI.abi);

const router = (route: IFlashloanRoute) => {
const protocols = route.hops.map((hop) => {
const tokenPair = `${findToken(hop.path[0])}${findToken(hop.path[1])}`;
return `${tokenPair}: ${hop.swaps}`;
});
return protocols;
};
// const router = (route: IFlashloanRoute) => {
// const protocols = route.hops.map((hop) => {
// const tokenPair = `${findToken(hop.path[0])} → ${findToken(hop.path[1])}`;
// return `${tokenPair}: ${hop.swaps}`;
// });
// return protocols;
// };

export const main = async () => {
var args = process.argv.slice(2);
// export const main = async () => {
// var args = process.argv.slice(2);

const tx = await maticProvider.getTransaction(args[0]);
console.log({
hash: tx.hash,
from: tx.from,
to: tx.to,
// const tx = await maticProvider.getTransaction(args[0]);
// console.log({
// hash: tx.hash,
// from: tx.from,
// to: tx.to,

gasPrice: tx.gasPrice?.toNumber(),
gasLimit: tx.gasLimit?.toNumber(),
// gasPrice: tx.gasPrice?.toNumber(),
// gasLimit: tx.gasLimit?.toNumber(),

nonce: tx.nonce,
blockNumber: tx.blockNumber,
});
// nonce: tx.nonce,
// blockNumber: tx.blockNumber,
// });

const decodedInput = inter.parseTransaction({
data: tx.data,
value: tx.value,
});
console.log({
name: decodedInput.name,
// const decodedInput = inter.parseTransaction({
// data: tx.data,
// value: tx.value,
// });
// console.log({
// name: decodedInput.name,

params: {
flashLoanPool: findPool(decodedInput.args.params.flashLoanPool),
loanAmount: decodedInput.args.params.loanAmount.toNumber(),
firstRoutes: decodedInput.args.params.firstRoutes.map(
(route: IFlashloanRoute) => JSON.stringify(router(route))
),
secondRoutes: decodedInput.args.params.secondRoutes.map(
(route: IFlashloanRoute) => JSON.stringify(router(route))
),
},
});
};
// params: {
// flashLoanPool: findPool(decodedInput.args.params.flashLoanPool),
// loanAmount: decodedInput.args.params.loanAmount.toNumber(),
// firstRoutes: decodedInput.args.params.firstRoutes.map(
// (route: IFlashloanRoute) => JSON.stringify(router(route))
// ),
// secondRoutes: decodedInput.args.params.secondRoutes.map(
// (route: IFlashloanRoute) => JSON.stringify(router(route))
// ),
// },
// });
// };

main().catch((error) => {
console.error(error);
process.exit(1);
});
// main().catch((error) => {
// console.error(error);
// process.exit(1);
// });
54 changes: 2 additions & 52 deletions src/expect.ts
Original file line number Diff line number Diff line change
@@ -1,69 +1,19 @@
import { BigNumber, ethers } from "ethers";
import { Hop, IFlashloanRoute, Swap } from "./interfaces/main";
import { getPriceOnUniV2 } from "./price/uniswap/v2/getPrice";
import { getUniswapV3PoolFee } from "./price/uniswap/v3/fee";
import { getPriceOnUniV3 } from "./price/uniswap/v3/getPrice";
import { findRouterFromProtocol, getBigNumber } from "./utils";
import { splitLoanAmount } from "./utils/split";

export const expectAmountOut = async (
flashloanRoutes: IFlashloanRoute[],
totalAmountIn: BigNumber
) => {
let amountOut = getBigNumber(0);
for (const route of flashloanRoutes) {
const part = route.part;
const amountIn = splitLoanAmount(totalAmountIn, part);
const hopsAmountOut = await getHopsAmountOut(route.hops, amountIn);
if (hopsAmountOut) {
amountOut = amountOut.add(await getHopsAmountOut(route.hops, amountIn));
}
}
return amountOut;
};

const getHopsAmountOut = async (hops: Hop[], initialAmount: BigNumber) => {
let amountIn = initialAmount;
for (const hop of hops) {
const swaps = hop.swaps;
const path = hop.path;
const swapsAmountOut = await getSwapsAmountOut(swaps, amountIn, path);
amountIn = swapsAmountOut ? swapsAmountOut : getBigNumber(0);
}

return amountIn;
};

const getSwapsAmountOut = async (
swaps: Swap[],
totalAmountIn: BigNumber,
path: string[]
) => {
let amountOut = getBigNumber(0);
for (const swap of swaps) {
const protocol = swap.protocol;
const part = swap.part;
const amountIn = splitLoanAmount(totalAmountIn, part);
const price = await expectPriceOnDex(protocol, amountIn, path[0], path[1]);
if (ethers.BigNumber.isBigNumber(price)) {
amountOut = amountOut.add(price);
}
}
return amountOut;
};

export const expectPriceOnDex = async (
protocol: number,
amountIn: BigNumber,
tokenIn: string,
tokenOut: string
) => {
): Promise<BigNumber> => {
if (!amountIn || amountIn.eq(getBigNumber(0))) {
return getBigNumber(0);
}
if (protocol === 0) {
const fee = getUniswapV3PoolFee([tokenIn, tokenOut]);
return await getPriceOnUniV3(tokenIn, tokenOut, amountIn, fee);
return await getPriceOnUniV3(tokenIn, tokenOut, amountIn);
} else {
const routerAddress = findRouterFromProtocol(protocol);
return await getPriceOnUniV2(tokenIn, tokenOut, amountIn, routerAddress);
Expand Down
Loading

0 comments on commit ef65fa5

Please sign in to comment.