Skip to content

Commit

Permalink
(feat) add AVAX support for Uniswap
Browse files Browse the repository at this point in the history
  • Loading branch information
fengtality committed Jul 25, 2024
2 parents 1f2795c + a48fe56 commit 68e7797
Show file tree
Hide file tree
Showing 9 changed files with 102 additions and 71 deletions.
10 changes: 9 additions & 1 deletion src/chains/avalanche/avalanche.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { TraderjoeConfig } from '../../connectors/traderjoe/traderjoe.config';
import { PangolinConfig } from '../../connectors/pangolin/pangolin.config';
import { OpenoceanConfig } from '../../connectors/openocean/openocean.config';
import { Ethereumish } from '../../services/common-interfaces';
import { UniswapConfig } from '../../connectors/uniswap/uniswap.config';
import { SushiswapConfig } from '../../connectors/sushiswap/sushiswap.config';
import { ConfigManagerV2 } from '../../services/config-manager-v2';
import { EVMController } from '../ethereum/evm.controllers';
Expand Down Expand Up @@ -84,7 +85,14 @@ export class Avalanche extends EthereumBase implements Ethereumish {

getSpender(reqSpender: string): string {
let spender: string;
if (reqSpender === 'pangolin') {
if (reqSpender === 'uniswap') {
spender = UniswapConfig.config.uniswapV3SmartOrderRouterAddress(
'avalanche',
this._chain,
);
} else if (reqSpender === 'uniswapLP') {
spender = UniswapConfig.config.uniswapV3NftManagerAddress('avalanche', this._chain);
} else if (reqSpender === 'pangolin') {
spender = PangolinConfig.config.routerAddress(this._chain);
} else if (reqSpender === 'openocean') {
spender = OpenoceanConfig.config.routerAddress('avalanche', this._chain);
Expand Down
4 changes: 3 additions & 1 deletion src/chains/avalanche/avalanche.validators.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,9 @@ export const validateSpender: Validator = mkValidator(

(val) =>
typeof val === 'string' &&
(val === 'pangolin' ||
(val === 'uniswap' ||
val === 'uniswapLP' ||
val === 'pangolin' ||
val === 'traderjoe' ||
val === 'openocean' ||
val === 'sushiswap' ||
Expand Down
5 changes: 4 additions & 1 deletion src/connectors/uniswap/uniswap.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,12 @@ export namespace UniswapConfig {
uniswapV3SmartOrderRouterAddress: (chain: string, network: string) => string;
uniswapV3NftManagerAddress: (chain: string, network: string) => string;
uniswapV3FactoryAddress: (chain: string, network: string) => string;
quoterContractAddress: (chain: string, network: string) => string;
tradingTypes: (type: string) => Array<string>;
chainType: string;
availableNetworks: Array<AvailableNetworks>;
useRouter?: boolean;
feeTier?: string;
quoterContractAddress: (chain: string, network: string) => string;
}

export const config: NetworkConfig = {
Expand Down Expand Up @@ -73,6 +73,9 @@ export namespace UniswapConfig {
{ chain: 'binance-smart-chain',
networks: ['mainnet']
},
{ chain: 'avalanche',
networks: ['avalanche']
},
],
useRouter: ConfigManagerV2.getInstance().get(`uniswap.useRouter`),
feeTier: ConfigManagerV2.getInstance().get(`uniswap.feeTier`),
Expand Down
58 changes: 40 additions & 18 deletions src/connectors/uniswap/uniswap.lp.helper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@ import { AlphaRouter } from '@uniswap/smart-order-router';
import { providers, Wallet, Signer, utils } from 'ethers';
import { percentRegexp } from '../../services/config-manager-v2';
import { Ethereum } from '../../chains/ethereum/ethereum';
import { Avalanche } from '../../chains/avalanche/avalanche';
import { Polygon } from '../../chains/polygon/polygon';
import { BinanceSmartChain } from "../../chains/binance-smart-chain/binance-smart-chain";

import {
PoolState,
RawPosition,
Expand All @@ -21,28 +25,41 @@ import * as math from 'mathjs';
import { getAddress } from 'ethers/lib/utils';

export class UniswapLPHelper {
protected ethereum: Ethereum;
protected chain: Ethereum | Polygon | BinanceSmartChain | Avalanche;
protected chainId;
private _factory: string;
private _router: string;
private _nftManager: string;
private _ttl: number;
private _routerAbi: ContractInterface;
private _nftAbi: ContractInterface;
private _poolAbi: ContractInterface;
private _alphaRouter: AlphaRouter;
private _alphaRouter: AlphaRouter | null;
private tokenList: Record<string, Token> = {};
private _chain: string;
private _ready: boolean = false;
public abiDecoder: any;

constructor(chain: string, network: string) {
this.ethereum = Ethereum.getInstance(network);
this._chain = chain;
this.chainId = this.ethereum.chainId;
this._alphaRouter = new AlphaRouter({
chainId: this.chainId,
provider: this.ethereum.provider,
});
if (chain === 'ethereum') {
this.chain = Ethereum.getInstance(network);
} else if (chain === 'polygon') {
this.chain = Polygon.getInstance(network);
} else if (chain === 'binance-smart-chain') {
this.chain = BinanceSmartChain.getInstance(network);
} else if (chain === 'avalanche') {
this.chain = Avalanche.getInstance(network);
} else {
throw new Error('Unsupported chain');
}
this.chainId = this.chain.chainId;
this._alphaRouter = null;
if (this.chainId !== 11155111 && this.chainId !== 8453) {
this._alphaRouter = new AlphaRouter({
chainId: this.chainId,
provider: this.chain.provider,
});
}
this._factory = UniswapConfig.config.uniswapV3FactoryAddress(chain, network);
this._router =
UniswapConfig.config.uniswapV3SmartOrderRouterAddress(chain, network);
this._nftManager = UniswapConfig.config.uniswapV3NftManagerAddress(chain, network);
Expand All @@ -63,6 +80,9 @@ export class UniswapLPHelper {
}

public get alphaRouter(): AlphaRouter {
if (this._alphaRouter === null) {
throw new Error('AlphaRouter is not initialized');
}
return this._alphaRouter;
}

Expand Down Expand Up @@ -101,12 +121,13 @@ export class UniswapLPHelper {
}

public async init() {
if (this._chain == 'ethereum' && !this.ethereum.ready())
const chainName = this.chain.chainName.toString();
if (!this.chain.ready())
throw new InitializationError(
SERVICE_UNITIALIZED_ERROR_MESSAGE('ETH'),
SERVICE_UNITIALIZED_ERROR_MESSAGE(chainName),
SERVICE_UNITIALIZED_ERROR_CODE
);
for (const token of this.ethereum.storedTokenList) {
for (const token of this.chain.storedTokenList) {
this.tokenList[token.address] = new Token(
this.chainId,
token.address,
Expand Down Expand Up @@ -156,7 +177,7 @@ export class UniswapLPHelper {
): Promise<PoolState> {
const poolContract = this.getPoolContract(
poolAddress,
this.ethereum.provider
this.chain.provider
);
const minTick = uniV3.nearestUsableTick(
uniV3.TickMath.MIN_TICK,
Expand Down Expand Up @@ -221,9 +242,9 @@ export class UniswapLPHelper {
const prices = [];
const fee = uniV3.FeeAmount[tier as keyof typeof uniV3.FeeAmount];
const poolContract = new Contract(
uniV3.Pool.getAddress(token0, token1, fee),
uniV3.Pool.getAddress(token0, token1, fee, undefined, this._factory),
this.poolAbi,
this.ethereum.provider
this.chain.provider
);
for (
let x = Math.ceil(period / interval) * interval;
Expand Down Expand Up @@ -311,7 +332,7 @@ export class UniswapLPHelper {
const lowerPriceInFraction = math.fraction(lowerPrice) as math.Fraction;
const upperPriceInFraction = math.fraction(upperPrice) as math.Fraction;
const poolData = await this.getPoolState(
uniV3.Pool.getAddress(token0, token1, fee),
uniV3.Pool.getAddress(token0, token1, fee, undefined, this._factory),
fee
);
const pool = new uniV3.Pool(
Expand Down Expand Up @@ -392,13 +413,14 @@ export class UniswapLPHelper {
const positionData = await this.getRawPosition(wallet, tokenId);
const token0 = this.getTokenByAddress(positionData.token0);
const token1 = this.getTokenByAddress(positionData.token1);
const factoryAddress = this._factory
const fee = positionData.fee;
if (!token0 || !token1) {
throw new Error(
`One of the tokens in this position isn't recognized. $token0: ${token0}, $token1: ${token1}`
);
}
const poolAddress = uniV3.Pool.getAddress(token0, token1, fee);
const poolAddress = uniV3.Pool.getAddress(token0, token1, fee, undefined, factoryAddress);
const poolData = await this.getPoolState(poolAddress, fee);
const position = new uniV3.Position({
pool: new uniV3.Pool(
Expand Down
10 changes: 5 additions & 5 deletions src/connectors/uniswap/uniswap.lp.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,10 +53,10 @@ export class UniswapLP extends UniswapLPHelper implements UniswapLPish {
}

async getPosition(tokenId: number): Promise<PositionInfo> {
const contract = this.getContract('nft', this.ethereum.provider);
const contract = this.getContract('nft', this.chain.provider);
const requests = [
contract.positions(tokenId),
this.collectFees(this.ethereum.provider, tokenId), // static call to calculate earned fees
this.collectFees(this.chain.provider, tokenId), // static call to calculate earned fees
];
const positionInfoReq = await Promise.allSettled(requests);
const rejected = positionInfoReq.filter(
Expand Down Expand Up @@ -141,7 +141,7 @@ export class UniswapLP extends UniswapLPHelper implements UniswapLPish {
);

if (nonce === undefined) {
nonce = await this.ethereum.nonceManager.getNextNonce(wallet.address);
nonce = await this.chain.nonceManager.getNextNonce(wallet.address);
}

const tx = await wallet.sendTransaction({
Expand Down Expand Up @@ -179,7 +179,7 @@ export class UniswapLP extends UniswapLPHelper implements UniswapLPish {
);

if (nonce === undefined) {
nonce = await this.ethereum.nonceManager.getNextNonce(wallet.address);
nonce = await this.chain.nonceManager.getNextNonce(wallet.address);
}

const tx = await contract.multicall(
Expand Down Expand Up @@ -219,7 +219,7 @@ export class UniswapLP extends UniswapLPHelper implements UniswapLPish {
} else {
collectData.recipient = wallet.address;
if (nonce === undefined) {
nonce = await this.ethereum.nonceManager.getNextNonce(wallet.address);
nonce = await this.chain.nonceManager.getNextNonce(wallet.address);
}
return await contract.collect(
collectData,
Expand Down
10 changes: 8 additions & 2 deletions src/connectors/uniswap/uniswap.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,14 +36,15 @@ import {
import { logger } from '../../services/logger';
import { percentRegexp } from '../../services/config-manager-v2';
import { Ethereum } from '../../chains/ethereum/ethereum';
import { Avalanche } from '../../chains/avalanche/avalanche';
import { Polygon } from '../../chains/polygon/polygon';
import { BinanceSmartChain } from "../../chains/binance-smart-chain/binance-smart-chain";
import { ExpectedTrade, Uniswapish } from '../../services/common-interfaces';
import { getAddress } from 'ethers/lib/utils';

export class Uniswap implements Uniswapish {
private static _instances: { [name: string]: Uniswap };
private chain: Ethereum | Polygon | BinanceSmartChain;
private chain: Ethereum | Polygon | BinanceSmartChain | Avalanche;
private _alphaRouter: AlphaRouter | null;
private _router: string;
private _routerAbi: ContractInterface;
Expand All @@ -64,9 +65,14 @@ export class Uniswap implements Uniswapish {
this.chain = Ethereum.getInstance(network);
} else if (chain === 'polygon') {
this.chain = Polygon.getInstance(network);
} else {
} else if (chain === 'binance-smart-chain') {
this.chain = BinanceSmartChain.getInstance(network);
} else if (chain === 'avalanche') {
this.chain = Avalanche.getInstance(network);
} else {
throw new Error('Unsupported chain');
}

this.chainId = this.chain.chainId;
this._ttl = UniswapConfig.config.ttl;
this._maximumHops = UniswapConfig.config.maximumHops;
Expand Down
66 changes: 24 additions & 42 deletions src/services/connection-manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -187,68 +187,50 @@ export async function getConnector<T>(
): Promise<Connector<T>> {
let connectorInstance: ConnectorUnion;

if (
(chain === 'ethereum' || chain === 'polygon' || chain === 'binance-smart-chain') &&
connector === 'uniswap'
) {
if (connector === 'uniswap') {
connectorInstance = Uniswap.getInstance(chain, network);
} else if (chain === 'polygon' && connector === 'quickswap') {
connectorInstance = Quickswap.getInstance(chain, network);
} else if (
(chain === 'ethereum' || chain === 'polygon' || chain === 'binance-smart-chain') &&
connector === 'uniswapLP'
) {
} else if (connector === 'uniswapLP') {
connectorInstance = UniswapLP.getInstance(chain, network);
} else if (chain === 'ethereum' && connector === 'perp') {
} else if (connector === 'quickswap') {
connectorInstance = Quickswap.getInstance(chain, network);
} else if (connector === 'perp') {
connectorInstance = Perp.getInstance(chain, network, address);
} else if (chain === 'avalanche' && connector === 'pangolin') {
} else if (connector === 'pangolin') {
connectorInstance = Pangolin.getInstance(chain, network);
} else if (connector === 'openocean') {
connectorInstance = Openocean.getInstance(chain, network);
} else if (chain === 'avalanche' && connector === 'traderjoe') {
} else if (connector === 'traderjoe') {
connectorInstance = Traderjoe.getInstance(chain, network);
} else if (chain === 'cronos' && connector === 'mad_meerkat') {
} else if (connector === 'mad_meerkat') {
connectorInstance = MadMeerkat.getInstance(chain, network);
} else if (chain === 'cronos' && connector === 'vvs') {
} else if (connector === 'vvs') {
connectorInstance = VVSConnector.getInstance(chain, network);
} else if (chain === 'near' && connector === 'ref') {
} else if (connector === 'ref') {
connectorInstance = Ref.getInstance(chain, network);
} else if (
(chain === 'binance-smart-chain' || chain === 'ethereum') &&
connector === 'pancakeswap'
) {
} else if (connector === 'pancakeswap') {
connectorInstance = PancakeSwap.getInstance(chain, network);
} else if (
(chain === 'binance-smart-chain' || chain === 'ethereum') &&
connector === 'pancakeswapLP'
) {
} else if (connector === 'pancakeswapLP') {
connectorInstance = PancakeswapLP.getInstance(chain, network);
} else if (connector === 'sushiswap') {
connectorInstance = Sushiswap.getInstance(chain, network);
} else if (chain === 'xdc' && connector === 'xsswap') {
} else if (connector === 'xsswap') {
connectorInstance = Xsswap.getInstance(chain, network);
} else if (chain === 'avalanche' && connector === 'dexalot') {
connectorInstance = DexalotCLOB.getInstance(network);
} else if (chain == 'algorand' && connector == 'tinyman') {
connectorInstance = Tinyman.getInstance(network);
} else if (chain === 'tezos' && connector === 'plenty') {
connectorInstance = Plenty.getInstance(network);
} else if (chain === 'xrpl' && connector === 'xrpl') {
} else if (connector === 'xrpl') {
connectorInstance = XRPLCLOB.getInstance(chain, network);
} else if (chain === 'kujira' && connector === 'kujira') {
} else if (connector === 'kujira') {
connectorInstance = KujiraCLOB.getInstance(chain, network);
} else if (
(chain === 'ethereum' || chain === 'polygon') &&
connector === 'curve'
) {
} else if (connector === 'curve') {
connectorInstance = Curve.getInstance(chain, network);
} else if (
(chain === 'ethereum' || chain === 'polygon' || chain === 'avalanche') &&
connector === 'balancer'
) {
} else if (connector === 'balancer') {
connectorInstance = Balancer.getInstance(chain, network);
} else if (chain === 'ethereum' && connector === 'carbonamm') {
} else if (connector === 'carbonamm') {
connectorInstance = Carbonamm.getInstance(chain, network);
} else if (connector === 'dexalot') {
connectorInstance = DexalotCLOB.getInstance(network);
} else if (connector == 'tinyman') {
connectorInstance = Tinyman.getInstance(network);
} else if (connector === 'plenty') {
connectorInstance = Plenty.getInstance(network);
} else {
throw new Error('unsupported chain or connector');
}
Expand Down
4 changes: 3 additions & 1 deletion src/services/schema/uniswap-schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,9 @@
},
"required": [
"uniswapV3SmartOrderRouterAddress",
"uniswapV3NftManagerAddress"
"uniswapV3NftManagerAddress",
"uniswapV3QuoterV2ContractAddress",
"uniswapV3FactoryAddress"
],
"additionalProperties": false
}
Expand Down
6 changes: 6 additions & 0 deletions src/templates/uniswap.yml
Original file line number Diff line number Diff line change
Expand Up @@ -72,3 +72,9 @@ contractAddresses:
uniswapV3NftManagerAddress: '0x7b8A01B39D58278b5DE7e48c8449c9f4F5170613'
uniswapV3QuoterV2ContractAddress: '0x78D78E420Da98ad378D7799bE8f4AF69033EB077'
uniswapV3FactoryAddress: '0xdB1d10011AD0Ff90774D0C6Bb92e5C5c8b4461F7'
avalanche:
avalanche:
uniswapV3FactoryAddress: '0x740b1c1de25031C31FF4fC9A62f554A55cdC1baD'
uniswapV3SmartOrderRouterAddress: '0xbb00FF08d01D300023C629E8fFfFcb65A5a578cE'
uniswapV3NftManagerAddress: '0x655C406EBFa14EE2006250925e54ec43AD184f8B'
uniswapV3QuoterV2ContractAddress: '0xbe0F5544EC67e9B3b2D979aaA43f18Fd87E6257F'

0 comments on commit 68e7797

Please sign in to comment.