Skip to content

Commit

Permalink
feat: support isolated markets
Browse files Browse the repository at this point in the history
  • Loading branch information
coreyar committed Feb 1, 2024
1 parent 0c12a99 commit 72577ed
Show file tree
Hide file tree
Showing 13 changed files with 272 additions and 201 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
"docgen": "hardhat docgen",
"prepare": "husky install",
"generate-abis": "yarn wagmi generate",
"postinstall": "yarn generate-abis",
"postinstall": "yarn generate-abis && yarn generate-subgraph-types",
"generate-subgraph-types": "rm -rf /subgraph-client/.graphclient && npx graphclient build --dir ./subgraph-client"
},
"keywords": [],
Expand Down
32 changes: 0 additions & 32 deletions src/config/clients.ts

This file was deleted.

14 changes: 14 additions & 0 deletions src/config/clients/publicClient.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { HttpTransport, PublicClient, createPublicClient, http } from "viem";

import { chains } from "../chains";
import type { SUPPORTED_CHAINS } from "../chains";

export const getPublicClient = (): PublicClient<HttpTransport, typeof chains[SUPPORTED_CHAINS]> => {
const chainName = process.env.FORKED_NETWORK as SUPPORTED_CHAINS;
return createPublicClient({
chain: chains[chainName],
transport: http(process.env[`LIVE_NETWORK_${chainName}`]),
});
};

export default getPublicClient();
24 changes: 24 additions & 0 deletions src/config/clients/walletClient.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { HttpTransport, WalletClient, createWalletClient, http } from "viem";
import { PrivateKeyAccount, privateKeyToAccount } from "viem/accounts";

import { chains } from "../chains";
import type { SUPPORTED_CHAINS } from "../chains";

const readPrivateKeyFromEnv = (chainName: string): PrivateKeyAccount => {
const key = process.env[`PRIVATE_KEY_${chainName}`];
if (key?.startsWith("0x")) {
return privateKeyToAccount(key as `0x${string}`);
}
throw new Error(`Invalid private key for ${chainName}. Please specify PRIVATE_KEY_${chainName} env variable.`);
};

export const getWalletClient = (): WalletClient<HttpTransport, typeof chains[SUPPORTED_CHAINS], PrivateKeyAccount> => {
const chainName = process.env.FORKED_NETWORK as SUPPORTED_CHAINS;
return createWalletClient({
chain: chains[chainName],
transport: http(process.env[`LIVE_NETWORK_${chainName}`]),
account: readPrivateKeyFromEnv(chainName),
});
};

export default getWalletClient();
Original file line number Diff line number Diff line change
@@ -1,34 +1,30 @@
import { Currency, CurrencyAmount, Token, TradeType } from "@pancakeswap/sdk";
import { BaseRoute, Pool, QuoteProvider, SmartRouter, SmartRouterTrade, V3Pool } from "@pancakeswap/smart-router/evm";
import { Client as UrqlClient, createClient } from "urql/core";
import { Address, parseAbi } from "viem";
import { Hex, encodePacked } from "viem";
import { Hex, encodePacked, Address, parseAbi, erc20Abi} from "viem";

import { tokenConverterOperatorAbi } from "../config/abis/generated";
import addresses from "../config/addresses";
import type { SUPPORTED_CHAINS } from "../config/chains";
import { chains } from "../config/chains";
import { getPublicClient, getWalletClient } from "../config/clients";
import publicClient from "../config/clients/publicClient";
import walletClient from "../config/clients/walletClient";
import { Path } from "./path";

Check failure on line 12 in src/converter-bot/TokenConverter.ts

View workflow job for this annotation

GitHub Actions / Lint

'Path' is defined but never used. Allowed unused vars must match /_/u

const REVERT_IF_NOT_MINED_AFTER = 60n; // seconds

export const NETWORK_IDS: Record<SUPPORTED_CHAINS, number> = {
bsctestnet: 97,
bscmainnet: 56,
};
const MAX_HOPS = 5;

export const getOutputCurrency = (pool: V3Pool, inputToken: Token): Currency => {
const { token0, token1 } = pool;
return token0.equals(inputToken) ? token1 : token0;
};

export class TokenConverterBot {
export class TokenConverter {
private chainName: SUPPORTED_CHAINS;
private operator: { address: Address; abi: typeof tokenConverterOperatorAbi };
private addresses: typeof addresses;
private _walletClient?: ReturnType<typeof getWalletClient>;
private _publicClient?: ReturnType<typeof getPublicClient>;
private _walletClient?: typeof walletClient;
private _publicClient?: typeof publicClient;
private v3SubgraphClient: UrqlClient;
private quoteProvider: QuoteProvider;
private tokens: Map<Address, Currency>;
Expand All @@ -50,11 +46,11 @@ export class TokenConverterBot {
}

get publicClient() {
return (this._publicClient ||= getPublicClient(this.chainName));
return (this._publicClient ||= publicClient);
}

get walletClient() {
return (this._walletClient ||= getWalletClient(this.chainName));
return (this._walletClient ||= walletClient);
}

getToken = async (address: Address): Promise<Currency> => {
Expand All @@ -65,18 +61,18 @@ export class TokenConverterBot {
contracts: [
{
address,
abi: parseAbi(["function decimals() external pure returns (uint8)"]),
abi: erc20Abi,
functionName: "decimals",
},
{
address,
abi: parseAbi(["function symbol() external pure returns (string memory)"]),
abi: erc20Abi,
functionName: "symbol",
},
],
});
if (decimals && symbol) {
const token = new Token(NETWORK_IDS[this.chainName], address, decimals, symbol);
const token = new Token(chains[this.chainName].id, address, decimals, symbol);
this.tokens.set(address, token);
return token;
}
Expand Down Expand Up @@ -114,7 +110,7 @@ export class TokenConverterBot {
TradeType.EXACT_OUTPUT,
{
gasPriceWei: () => this.publicClient.getGasPrice(),
maxHops: 1,
maxHops: MAX_HOPS,

maxSplits: 0,
poolProvider: SmartRouter.createStaticPoolProvider(candidatePools),
Expand Down Expand Up @@ -164,19 +160,19 @@ export class TokenConverterBot {
return encodePacked(types.reverse(), path.reverse());
}

async arbitrage(converterAddress: Address, path: Path, amount: bigint, minIncome: bigint) {
async arbitrage(converterAddress: Address, trade: SmartRouterTrade<TradeType.EXACT_OUTPUT>, amount: bigint, minIncome: bigint) {
const beneficiary = this.walletClient.account.address;
const chain = chains[this.chainName];

const block = await this.publicClient.getBlock();

if (minIncome < 0n) {
await this.walletClient.writeContract({
address: path.end,
address: trade.outputAmount.address,
chain,
abi: parseAbi(["function approve(address,uint256)"]),
functionName: "approve",
args: [this.operator.address, -minIncome], // + amount
args: [this.operator.address, -minIncome],
});
}
try {
Expand All @@ -187,26 +183,25 @@ export class TokenConverterBot {
args: [
{
beneficiary,
tokenToReceiveFromConverter: path.end,
tokenToReceiveFromConverter: trade.outputAmount.address,
amount,
minIncome,
tokenToSendToConverter: path.start,
tokenToSendToConverter: trade.inputAmount.address,
converter: converterAddress,
path: path.hex,
path: this.encodeExactOutputPath(trade.route),
deadline: block.timestamp + REVERT_IF_NOT_MINED_AFTER,
},
],
});
} catch (e) {
console.error("Conversion failed", {
converterAddress,
assetIn: path.start,
assetOut: path.end,
trade,
amount,
minIncome,
});
}
}
}

export default TokenConverterBot;
export default TokenConverter;
Loading

0 comments on commit 72577ed

Please sign in to comment.