Skip to content

Commit

Permalink
Rinkeby support. Min splits support
Browse files Browse the repository at this point in the history
  • Loading branch information
willpote committed Sep 15, 2021
1 parent a30f23a commit 25b08fe
Show file tree
Hide file tree
Showing 20 changed files with 160 additions and 59 deletions.
29 changes: 19 additions & 10 deletions scripts/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,10 @@ export class UniswapSORCLI extends Command {
required: false,
default: 3,
}),
minSplits: flags.integer({
required: false,
default: 1,
}),
maxSplits: flags.integer({
required: false,
default: 3,
Expand Down Expand Up @@ -126,6 +130,7 @@ export class UniswapSORCLI extends Command {
topNWithBaseToken,
topNWithBaseTokenInSet,
maxSwapsPerPath,
minSplits,
maxSplits,
distributionPercent,
} = flags;
Expand Down Expand Up @@ -168,7 +173,7 @@ export class UniswapSORCLI extends Command {
const chainName = ID_TO_NETWORK_NAME(chainIdNumb);

const provider = new ethers.providers.JsonRpcProvider(
process.env.JSON_RPC_PROVIDER!,
chainId == ChainId.MAINNET ? process.env.JSON_RPC_PROVIDER! : process.env.JSON_RPC_PROVIDER_RINKEBY!,
chainName
);

Expand All @@ -184,10 +189,11 @@ export class UniswapSORCLI extends Command {
DEFAULT_TOKEN_LIST
);
}
const multicall2Provider = new UniswapMulticallProvider(provider);
const multicall2Provider = new UniswapMulticallProvider(chainId, provider);

const tokenProviderOnChain = new TokenProvider(chainId, multicall2Provider);
const tokenProvider = new TokenProviderWithFallback(
chainId,
tokenListProvider,
tokenProviderOnChain
);
Expand All @@ -206,29 +212,30 @@ export class UniswapSORCLI extends Command {
? Ether.onChain(chainId)
: tokenAccessor.getTokenByAddress(tokenOutStr)!;

const multicall = new UniswapMulticallProvider(provider);
const multicall = new UniswapMulticallProvider(chainId, provider);

let router: IRouter<any>;
if (routerStr == 'legacy') {
router = new LegacyRouter({
chainId,
multicall2Provider,
poolProvider: new PoolProvider(multicall2Provider),
quoteProvider: new QuoteProvider(provider, multicall2Provider),
poolProvider: new PoolProvider(chainId, multicall2Provider),
quoteProvider: new QuoteProvider(chainId, provider, multicall2Provider),
tokenProvider,
});
} else {
router = new AlphaRouter({
provider,
chainId,
subgraphProvider: new CachingSubgraphProvider(
new SubgraphProvider(undefined, 10000)
subgraphProvider: new CachingSubgraphProvider(chainId,
new SubgraphProvider(chainId, undefined, 10000)
),
multicall2Provider: multicall,
poolProvider: new CachingPoolProvider(
new PoolProvider(multicall2Provider)
poolProvider: new CachingPoolProvider(chainId,
new PoolProvider(chainId, multicall2Provider)
),
quoteProvider: new QuoteProvider(
chainId,
provider,
multicall,
{
Expand All @@ -242,7 +249,7 @@ export class UniswapSORCLI extends Command {
quoteMinSuccessRate: 0.7,
}
),
gasPriceProvider: new CachingGasStationProvider(
gasPriceProvider: new CachingGasStationProvider(chainId,
new EIP1559GasPriceProvider(provider)
),
gasModelFactory: new HeuristicGasModelFactory(),
Expand Down Expand Up @@ -271,6 +278,7 @@ export class UniswapSORCLI extends Command {
topNWithBaseToken,
topNWithBaseTokenInSet,
maxSwapsPerPath,
minSplits,
maxSplits,
distributionPercent,
}
Expand All @@ -294,6 +302,7 @@ export class UniswapSORCLI extends Command {
topNWithBaseToken,
topNWithBaseTokenInSet,
maxSwapsPerPath,
minSplits,
maxSplits,
distributionPercent,
}
Expand Down
9 changes: 5 additions & 4 deletions src/providers/caching-gas-provider.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,18 @@
import NodeCache from 'node-cache';
import { ChainId } from '../util/chains';
import { log } from '../util/log';
import { GasPrice, IGasPriceProvider } from './gas-price-provider';

const GAS_CACHE = new NodeCache({ useClones: true });
const GAS_KEY = 'gas';
const GAS_KEY = (chainId: ChainId) => `gas${chainId}`;

export class CachingGasStationProvider extends IGasPriceProvider {
constructor(private gasPriceProvider: IGasPriceProvider, private ttlSeconds: number = 300) {
constructor(protected chainId: ChainId, private gasPriceProvider: IGasPriceProvider, private ttlSeconds: number = 300) {
super();
}

public async getGasPrice(): Promise<GasPrice> {
const cachedGasPrice = GAS_CACHE.get<GasPrice>(GAS_KEY);
const cachedGasPrice = GAS_CACHE.get<GasPrice>(GAS_KEY(this.chainId));

if (cachedGasPrice) {
log.info(
Expand All @@ -24,7 +25,7 @@ export class CachingGasStationProvider extends IGasPriceProvider {

log.info('Gas station price local cache miss.');
const gasPrice = await this.gasPriceProvider.getGasPrice();
GAS_CACHE.set<GasPrice>(GAS_KEY, gasPrice, this.ttlSeconds);
GAS_CACHE.set<GasPrice>(GAS_KEY(this.chainId), gasPrice, this.ttlSeconds);

return gasPrice;
}
Expand Down
8 changes: 5 additions & 3 deletions src/providers/caching-pool-provider.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
import { Token } from '@uniswap/sdk-core';
import { FeeAmount, Pool } from '@uniswap/v3-sdk';
import NodeCache from 'node-cache';
import { ChainId } from '../util/chains';
import { log } from '../util/log';
import { IPoolProvider, PoolAccessor } from './pool-provider';
import { ProviderConfig } from './provider';

const POOL_CACHE = new NodeCache({ stdTTL: 900, useClones: false });
const POOL_KEY = (chainId: ChainId, address: string) => `${chainId}-${address}`;

export class CachingPoolProvider implements IPoolProvider {
constructor(protected poolProvider: IPoolProvider) {}
constructor(protected chainId: ChainId, protected poolProvider: IPoolProvider) {}

public async getPools(
tokenPairs: [Token, Token, FeeAmount][], providerConfig: ProviderConfig
Expand All @@ -33,7 +35,7 @@ export class CachingPoolProvider implements IPoolProvider {

poolAddressSet.add(poolAddress);

const cachedPool = POOL_CACHE.get<Pool>(poolAddress);
const cachedPool = POOL_CACHE.get<Pool>(POOL_KEY(this.chainId, poolAddress));
if (cachedPool) {
poolAddressToPool[poolAddress] = cachedPool;
continue;
Expand All @@ -60,7 +62,7 @@ export class CachingPoolProvider implements IPoolProvider {
const pool = poolAccessor.getPoolByAddress(address);
if (pool) {
poolAddressToPool[address] = pool;
POOL_CACHE.set<Pool>(address, pool);
POOL_CACHE.set<Pool>(POOL_KEY(this.chainId, address), pool);
}
}
}
Expand Down
9 changes: 5 additions & 4 deletions src/providers/caching-subgraph-provider.ts
Original file line number Diff line number Diff line change
@@ -1,22 +1,23 @@
import NodeCache from 'node-cache';
import { ChainId } from '../util/chains';
import { ISubgraphProvider, SubgraphPool } from './subgraph-provider';

const SUBGRAPH_POOL_CACHE = new NodeCache({ stdTTL: 900, useClones: true });
const SUBGRAPH_KEY = 'pools';
const SUBGRAPH_KEY = (chainId: ChainId) => `${chainId}pools`;

export class CachingSubgraphProvider implements ISubgraphProvider {
constructor(protected subgraphProvider: ISubgraphProvider) {}
constructor(private chainId: ChainId, protected subgraphProvider: ISubgraphProvider) {}

public async getPools(): Promise<SubgraphPool[]> {
const cachedPools = SUBGRAPH_POOL_CACHE.get<SubgraphPool[]>(SUBGRAPH_KEY);
const cachedPools = SUBGRAPH_POOL_CACHE.get<SubgraphPool[]>(SUBGRAPH_KEY(this.chainId));

if (cachedPools) {
return cachedPools;
}

const pools = await this.subgraphProvider.getPools();

SUBGRAPH_POOL_CACHE.set<SubgraphPool[]>(SUBGRAPH_KEY, pools);
SUBGRAPH_POOL_CACHE.set<SubgraphPool[]>(SUBGRAPH_KEY(this.chainId), pools);

return pools;
}
Expand Down
20 changes: 18 additions & 2 deletions src/providers/multicall-uniswap-provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import _ from 'lodash';
import stats from 'stats-lite';
import { UniswapInterfaceMulticall__factory } from '../types/v3/factories/UniswapInterfaceMulticall__factory';
import { UniswapInterfaceMulticall } from '../types/v3/UniswapInterfaceMulticall';
import { ChainId } from '../util';
import { UNISWAP_MULTICALL_ADDRESS } from '../util/addresses';
import { log } from '../util/log';
import {
Expand All @@ -16,17 +17,32 @@ export type UniswapMulticallConfig = {
gasLimitPerCallOverride?: number;
};

const contractAddressByChain: { [chainId in ChainId]?: string } = {
[ChainId.MAINNET]: UNISWAP_MULTICALL_ADDRESS,
[ChainId.RINKEBY]: UNISWAP_MULTICALL_ADDRESS,
[ChainId.KOVAN]: UNISWAP_MULTICALL_ADDRESS,
[ChainId.ROPSTEN]: UNISWAP_MULTICALL_ADDRESS,
[ChainId.GÖRLI]: UNISWAP_MULTICALL_ADDRESS
}

export class UniswapMulticallProvider extends IMulticallProvider<UniswapMulticallConfig> {
private multicallContract: UniswapInterfaceMulticall;

constructor(
protected chainId: ChainId,
protected provider: providers.BaseProvider,
protected gasLimitPerCall = 1_000_000,
protected multicallAddress = UNISWAP_MULTICALL_ADDRESS
protected multicallAddressOverride = UNISWAP_MULTICALL_ADDRESS
) {
super();
const multicallAddress = multicallAddressOverride ? multicallAddressOverride : contractAddressByChain[this.chainId];

if (!multicallAddress) {
throw new Error(`No address for Uniswap Multicall Contract on chain id: ${chainId}`);
}

this.multicallContract = UniswapInterfaceMulticall__factory.connect(
this.multicallAddress,
multicallAddress,
this.provider
);
}
Expand Down
4 changes: 3 additions & 1 deletion src/providers/pool-provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { BigNumber } from 'ethers';
import _ from 'lodash';
import NodeCache from 'node-cache';
import { IUniswapV3PoolState__factory } from '../types/v3';
import { ChainId } from '../util';
import { V3_CORE_FACTORY_ADDRESS } from '../util/addresses';
import { log } from '../util/log';
import { poolToString } from '../util/routes';
Expand Down Expand Up @@ -52,6 +53,7 @@ export type PoolRetryOptions = AsyncRetry.Options;
const POOL_ADDRESS_CACHE = new NodeCache({ stdTTL: 3600, useClones: false });
export class PoolProvider implements IPoolProvider {
constructor(
protected chainId: ChainId,
protected multicall2Provider: IMulticallProvider,
protected retryOptions: PoolRetryOptions = {
retries: 2,
Expand Down Expand Up @@ -184,7 +186,7 @@ export class PoolProvider implements IPoolProvider {
? [tokenA, tokenB]
: [tokenB, tokenA];

const cacheKey = `${token0.address}/${token1.address}/${feeAmount}`;
const cacheKey = `${this.chainId}/${token0.address}/${token1.address}/${feeAmount}`;

const cachedAddress = POOL_ADDRESS_CACHE.get<string>(cacheKey);

Expand Down
21 changes: 18 additions & 3 deletions src/providers/quote-provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import _ from 'lodash';
import stats from 'stats-lite';
import { RouteSOR } from '../routers/router';
import { IQuoterV2__factory } from '../types/v3/factories/IQuoterV2__factory';
import { metric, MetricLoggerUnit } from '../util';
import { ChainId, metric, MetricLoggerUnit } from '../util';
import { QUOTER_V2_ADDRESS } from '../util/addresses';
import { CurrencyAmount } from '../util/amounts';
import { log } from '../util/log';
Expand Down Expand Up @@ -87,8 +87,15 @@ export interface IQuoteProvider {
): Promise<{ routesWithQuotes: RouteWithQuotes[]; blockNumber: BigNumber }>;
}

const chainToQuoterAddress: { [chainId in ChainId]?: string } = {
[ChainId.MAINNET]: QUOTER_V2_ADDRESS,
[ChainId.RINKEBY]: '0xbec7965F684FFdb309b9189BDc10C31337C37CBf'
}

export class QuoteProvider implements IQuoteProvider {
protected quoterAddress: string;
constructor(
protected chainId: ChainId,
protected provider: providers.BaseProvider,
// Only supports Uniswap Multicall as it needs the gas limitting functionality.
protected multicall2Provider: UniswapMulticallProvider,
Expand All @@ -107,8 +114,16 @@ export class QuoteProvider implements IQuoteProvider {
multicallChunk: 110,
},
protected rollback: boolean = false,
protected quoterAddress: string = QUOTER_V2_ADDRESS
) {}
protected quoterAddressOverride?: string,
) {
const quoterAddress = quoterAddressOverride ? quoterAddressOverride : chainToQuoterAddress[this.chainId];

if (!quoterAddress) {
throw new Error(`No address for Uniswap Multicall Contract on chain id: ${chainId}`);
}

this.quoterAddress = quoterAddress;
}

public async getQuotesManyExactIn(
amountIns: CurrencyAmount[],
Expand Down
15 changes: 11 additions & 4 deletions src/providers/subgraph-provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import _ from 'lodash';
import { log } from '../util/log';
import { ProviderConfig } from './provider';
import Timeout from 'await-timeout';
import { ChainId } from '../util/chains';

export interface SubgraphPool {
id: string;
Expand Down Expand Up @@ -42,8 +43,10 @@ export type RawSubgraphPool = {
export const printSubgraphPool = (s: SubgraphPool) =>
`${s.token0.symbol}/${s.token1.symbol}/${s.feeTier}`;

const SUBGRAPH_URL =
'https://api.thegraph.com/subgraphs/name/uniswap/uniswap-v3';
const SUBGRAPH_URL_BY_CHAIN: { [chainId in ChainId]?: string } = {
[ChainId.MAINNET]: 'https://api.thegraph.com/subgraphs/name/uniswap/uniswap-v3',
[ChainId.RINKEBY]: 'https://api.thegraph.com/subgraphs/name/ianlapham/uniswap-v3-rinkeby',
}

const PAGE_SIZE = 1000; // 1k is max possible query size from subgraph.
export interface ISubgraphProvider {
Expand All @@ -52,8 +55,12 @@ export interface ISubgraphProvider {
export class SubgraphProvider implements ISubgraphProvider {
private client: GraphQLClient;

constructor(private retries = 2, private timeout = 7000) {
this.client = new GraphQLClient(SUBGRAPH_URL);
constructor(private chainId: ChainId, private retries = 2, private timeout = 7000) {
const subgraphUrl = SUBGRAPH_URL_BY_CHAIN[this.chainId];
if (!subgraphUrl) {
throw new Error(`No subgraph url for chain id: ${this.chainId}`);
}
this.client = new GraphQLClient(subgraphUrl);
}

public async getPools(
Expand Down
2 changes: 1 addition & 1 deletion src/providers/token-list-provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,7 @@ export class TokenListProvider implements ITokenProvider, ITokenListProvider {
}

private buildToken(tokenInfo: TokenInfo): Token {
const cacheKey = `${this.tokenList.name}/${this.tokenList.timestamp}/${
const cacheKey = `${this.chainId}/${this.tokenList.name}/${this.tokenList.timestamp}/${
this.tokenList.version
}/${tokenInfo.address.toLowerCase()}/${tokenInfo.decimals}/${
tokenInfo.symbol
Expand Down
Loading

0 comments on commit 25b08fe

Please sign in to comment.