Skip to content

Commit

Permalink
Add HorizonDEX for Linea blockchain (#424)
Browse files Browse the repository at this point in the history
  • Loading branch information
Doctor-Cyclone authored Aug 9, 2023
2 parents b4f607e + 8349bf4 commit 0ecf0f9
Show file tree
Hide file tree
Showing 24 changed files with 768 additions and 25 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "rubic-sdk",
"version": "4.14.3",
"version": "4.15.0",
"description": "Simplify dApp creation",
"main": "lib/index.js",
"types": "lib/index.d.ts",
Expand Down
3 changes: 2 additions & 1 deletion src/features/common/constants/proxy-supported-blockchain.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ export const proxySupportedBlockchains = [
BLOCKCHAIN_NAME.CRONOS,
BLOCKCHAIN_NAME.ZK_SYNC,
BLOCKCHAIN_NAME.PULSECHAIN,
BLOCKCHAIN_NAME.AURORA
BLOCKCHAIN_NAME.AURORA,
BLOCKCHAIN_NAME.LINEA
// BLOCKCHAIN_NAME.OKE_X_CHAIN,
// BLOCKCHAIN_NAME.GNOSIS,
// BLOCKCHAIN_NAME.FUSE,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@ export const rubicProxyContractAddress: Record<
router = '0xa63c029612ddaD00A269383Ab016D1e7c14E851D';
gateway = '0x8E70e517057e7380587Ea6990dAe81cB1Ba405ce';
}
if (blockchain === BLOCKCHAIN_NAME.LINEA) {
router = '0xAf14797CcF963B1e3d028a9d51853acE16aedBA1';
}

return { ...acc, [blockchain]: { gateway, router } };
},
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { UniSwapV3ArbitrumProvider } from 'src/features/on-chain/calculation-manager/providers/dexes/arbitrum/uni-swap-v3-arbitrum/uni-swap-v3-arbitrum-provider';
import { UniSwapV3EthereumProvider } from 'src/features/on-chain/calculation-manager/providers/dexes/ethereum/uni-swap-v3-ethereum/uni-swap-v3-ethereum-provider';
import { UniSwapV3EthereumPowProvider } from 'src/features/on-chain/calculation-manager/providers/dexes/ethereum-pow/uni-swap-v3-ethereum-pow/uni-swap-v3-ethereum-pow-provider';
import { HorizondexProvider } from 'src/features/on-chain/calculation-manager/providers/dexes/linea/horizondex/horizondex-provider';
import { UniSwapV3PolygonProvider } from 'src/features/on-chain/calculation-manager/providers/dexes/polygon/uni-swap-v3-polygon/uni-swap-v3-polygon-provider';
import { UniSwapV3PulsechainProvider } from 'src/features/on-chain/calculation-manager/providers/dexes/pulsechain/uni-swap-v3-pulsechain/uni-swap-v3-ethereum-provider';

Expand All @@ -9,5 +10,6 @@ export const UniswapV3TradeProviders = [
UniSwapV3PolygonProvider,
UniSwapV3ArbitrumProvider,
UniSwapV3EthereumPowProvider,
UniSwapV3PulsechainProvider
UniSwapV3PulsechainProvider,
HorizondexProvider
] as const;
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ export const ON_CHAIN_TRADE_TYPE = {
ELK: 'ELK',

HONEY_SWAP: 'HONEY_SWAP',
HORIZONDEX: 'HORIZONDEX',

JET_SWAP: 'JET_SWAP',
JOE: 'JOE',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { UNI_SWAP_V3_ARBITRUM_PROVIDER_CONFIGURATION } from 'src/features/on-cha
import { UNI_SWAP_V3_ARBITRUM_ROUTER_CONFIGURATION } from 'src/features/on-chain/calculation-manager/providers/dexes/arbitrum/uni-swap-v3-arbitrum/constants/router-configuration';
import { UniSwapV3ArbitrumTrade } from 'src/features/on-chain/calculation-manager/providers/dexes/arbitrum/uni-swap-v3-arbitrum/uni-swap-v3-arbitrum-trade';
import { UniswapV3AbstractProvider } from 'src/features/on-chain/calculation-manager/providers/dexes/common/uniswap-v3-abstract/uniswap-v3-abstract-provider';
import { UniswapV3QuoterController } from 'src/features/on-chain/calculation-manager/providers/dexes/common/uniswap-v3-abstract/utils/quoter-controller/uniswap-v3-quoter-controller';

export class UniSwapV3ArbitrumProvider extends UniswapV3AbstractProvider<UniSwapV3ArbitrumTrade> {
public readonly blockchain = BLOCKCHAIN_NAME.ARBITRUM;
Expand All @@ -12,4 +13,9 @@ export class UniSwapV3ArbitrumProvider extends UniswapV3AbstractProvider<UniSwap
protected readonly providerConfiguration = UNI_SWAP_V3_ARBITRUM_PROVIDER_CONFIGURATION;

protected readonly routerConfiguration = UNI_SWAP_V3_ARBITRUM_ROUTER_CONFIGURATION;

protected readonly quoterController = new UniswapV3QuoterController(
this.blockchain,
this.routerConfiguration
);
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { RubicSdkError } from 'src/common/errors';
import { Token } from 'src/common/tokens';
import { compareAddresses } from 'src/common/utils/blockchain';
import { Cache } from 'src/common/utils/decorators';
import { EvmWeb3Pure } from 'src/core/blockchain/web3-pure/typed-web3-pure/evm-web3-pure/evm-web3-pure';
import { createTokenNativeAddressProxyInPathStartAndEnd } from 'src/features/common/utils/token-native-address-proxy';
import {
Expand Down Expand Up @@ -33,10 +32,7 @@ export abstract class UniswapV3AbstractProvider<

protected readonly isRubicOptimisationEnabled: boolean = false;

@Cache
protected get quoterController(): UniswapV3QuoterController {
return new UniswapV3QuoterController(this.blockchain, this.routerConfiguration);
}
protected abstract readonly quoterController: UniswapV3QuoterController;

public get type(): OnChainTradeType {
return ON_CHAIN_TRADE_TYPE.UNI_SWAP_V3;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,15 @@ import {
import { UniswapV3Route } from 'src/features/on-chain/calculation-manager/providers/dexes/common/uniswap-v3-abstract/models/uniswap-v3-route';
import { UniswapV3TradeStruct } from 'src/features/on-chain/calculation-manager/providers/dexes/common/uniswap-v3-abstract/models/uniswap-v3-trade-struct';
import { UniswapV3QuoterController } from 'src/features/on-chain/calculation-manager/providers/dexes/common/uniswap-v3-abstract/utils/quoter-controller/uniswap-v3-quoter-controller';
import { UnwrapWethMethodName } from 'src/features/on-chain/calculation-manager/providers/dexes/common/uniswap-v3-algebra-abstract/models/unwrapWethMethodName';
import { UniswapV3AlgebraAbstractTrade } from 'src/features/on-chain/calculation-manager/providers/dexes/common/uniswap-v3-algebra-abstract/uniswap-v3-algebra-abstract-trade';

export abstract class UniswapV3AbstractTrade extends UniswapV3AlgebraAbstractTrade {
public readonly dexContractAddress = UNISWAP_V3_SWAP_ROUTER_CONTRACT_ADDRESS;
public readonly dexContractAddress: string = UNISWAP_V3_SWAP_ROUTER_CONTRACT_ADDRESS;

protected readonly contractAbi = UNISWAP_V3_SWAP_ROUTER_CONTRACT_ABI;

protected readonly unwrapWethMethodName = 'unwrapWETH9';
protected readonly unwrapWethMethodName: UnwrapWethMethodName = 'unwrapWETH9';

public readonly route: UniswapV3Route;

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,209 @@
import BigNumber from 'bignumber.js';
import { RubicSdkError } from 'src/common/errors';
import { Token } from 'src/common/tokens';
import { compareAddresses } from 'src/common/utils/blockchain';
import { Cache } from 'src/common/utils/decorators';
import { notNull } from 'src/common/utils/object';
import { EvmBlockchainName } from 'src/core/blockchain/models/blockchain-name';
import { MethodData } from 'src/core/blockchain/web3-public-service/web3-public/models/method-data';
import { Exact } from 'src/features/on-chain/calculation-manager/providers/common/on-chain-trade/evm-on-chain-trade/models/exact';
import { UniswapV3Route } from 'src/features/on-chain/calculation-manager/providers/dexes/common/uniswap-v3-abstract/models/uniswap-v3-route';
import { UniswapV3RouterConfiguration } from 'src/features/on-chain/calculation-manager/providers/dexes/common/uniswap-v3-abstract/models/uniswap-v3-router-configuration';
import {
UNISWAP_V3_QUOTER_CONTRACT_ABI,
UNISWAP_V3_QUOTER_CONTRACT_ADDRESS
} from 'src/features/on-chain/calculation-manager/providers/dexes/common/uniswap-v3-abstract/utils/quoter-controller/constants/quoter-contract-data';
import { LiquidityPool } from 'src/features/on-chain/calculation-manager/providers/dexes/common/uniswap-v3-abstract/utils/quoter-controller/models/liquidity-pool';
import { UniswapV3QuoterController } from 'src/features/on-chain/calculation-manager/providers/dexes/common/uniswap-v3-abstract/utils/quoter-controller/uniswap-v3-quoter-controller';
import { AbiItem } from 'web3-utils';

interface GetQuoterMethodsDataOptions {
routesLiquidityPools: LiquidityPool[];
from: Token;
to: Token;
exact: Exact;
weiAmount: string;
maxTransitTokens: number;
}
export class HorizondexUniswapV3QuoterController extends UniswapV3QuoterController {
constructor(
blockchain: EvmBlockchainName,
routerConfiguration: UniswapV3RouterConfiguration<string>,
quoterContractAddress: string = UNISWAP_V3_QUOTER_CONTRACT_ADDRESS,
quoterContractABI: AbiItem[] = UNISWAP_V3_QUOTER_CONTRACT_ABI
) {
super(
blockchain,
routerConfiguration,
quoterContractAddress,
quoterContractABI,
[300, 500, 1000, 3000, 10000]
);
}

/**
* Returns swap method's name and arguments to pass it to Quoter contract.
* @param poolsPath Pools, included in the route.
* @param from From token.
* @param to To token.
* @param exact Is exact input or output trade.
* @param weiAmount Amount of tokens to trade.
*/
@Cache
protected static getQuoterMethodData(
poolsPath: LiquidityPool[],
from: Token,
to: Token,
exact: Exact,
weiAmount: string
): {
poolsPath: LiquidityPool[];
methodData: MethodData;
} {
if (poolsPath.length === 1 && poolsPath?.[0]) {
const methodName =
exact === 'input' ? 'quoteExactInputSingle' : 'quoteExactOutputSingle';
const sqrtPriceLimitX96 = 0;
return {
poolsPath,
methodData: {
methodName,
methodArguments: [
from.address,
to.address,
weiAmount,
poolsPath[0].fee,
sqrtPriceLimitX96
]
}
};
}

const methodName = exact === 'input' ? 'quoteExactInput' : 'quoteExactOutput';
const tokensPath = exact === 'input' ? poolsPath : poolsPath.reverse();
const initialTokenAddress = exact === 'input' ? from.address : to.address;
return {
poolsPath,
methodData: {
methodName,
methodArguments: [
UniswapV3QuoterController.getEncodedPoolsPath(tokensPath, initialTokenAddress),
weiAmount
]
}
};
}

public async getAllRoutes(
from: Token,
to: Token,
exact: Exact,
weiAmount: string,
routeMaxTransitTokens: number
): Promise<UniswapV3Route[]> {
const routesLiquidityPools = await this.getAllLiquidityPools(from, to);
const options: Omit<GetQuoterMethodsDataOptions, 'maxTransitTokens'> = {
routesLiquidityPools,
from,
to,
exact,
weiAmount
};
const quoterMethodsData = [...Array(routeMaxTransitTokens + 1)]
.map((_, maxTransitTokens) =>
this.getQuoterMethodsData(
{
...options,
maxTransitTokens
},
[],
from.address
)
)
.flat();

const results = await this.web3Public.multicallContractMethods<
string | { returnedAmount: string }
>(
this.quoterContractAddress,
this.quoterContractABI,
quoterMethodsData.map(quoterMethodData => {
if (quoterMethodData.methodData.methodName.toLowerCase().includes('single')) {
return {
methodName: quoterMethodData.methodData.methodName,
methodArguments: [quoterMethodData.methodData.methodArguments]
};
}

return quoterMethodData.methodData;
})
);

return results
.map((result, index) => {
const pool = quoterMethodsData?.[index];
if (!pool) {
throw new RubicSdkError('Pool has to be defined');
}
if (result.success) {
return {
outputAbsoluteAmount: new BigNumber(
result?.output! instanceof Object
? result?.output?.returnedAmount
: result.output!
),
poolsPath: pool.poolsPath,
initialTokenAddress: from.address
};
}
return null;
})
.filter(notNull);
}

/**
* Returns swap methods' names and arguments, built with passed pools' addresses, to use it in Quoter contract.
*/
protected getQuoterMethodsData(
options: GetQuoterMethodsDataOptions,
path: LiquidityPool[],
lastTokenAddress: string
): { poolsPath: LiquidityPool[]; methodData: MethodData }[] {
const { routesLiquidityPools, from, to, exact, weiAmount, maxTransitTokens } = options;

if (path.length === maxTransitTokens) {
const pools = routesLiquidityPools.filter(pool =>
pool.isPoolWithTokens(lastTokenAddress, to.address)
);
return pools.map(pool =>
HorizondexUniswapV3QuoterController.getQuoterMethodData(
path.concat(pool),
from,
to,
exact,
weiAmount
)
);
}

return routesLiquidityPools
.filter(pool => !path.includes(pool))
.map(pool => {
const methodsData: { poolsPath: LiquidityPool[]; methodData: MethodData }[] = [];
if (compareAddresses(pool.token0.address, lastTokenAddress)) {
const extendedPath = path.concat(pool);
methodsData.push(
...this.getQuoterMethodsData(options, extendedPath, pool.token1.address)
);
}
if (compareAddresses(pool.token1.address, lastTokenAddress)) {
const extendedPath = path.concat(pool);
methodsData.push(
...this.getQuoterMethodsData(options, extendedPath, pool.token0.address)
);
}
return methodsData;
})
.flat();
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Token } from 'src/common/tokens';
import { compareAddresses } from 'src/common/utils/blockchain';

export type FeeAmount = 500 | 3000 | 10000;
export type FeeAmount = 300 | 500 | 1000 | 3000 | 10000;

/**
* Represents liquidity pool in uni v3.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import {
LiquidityPool
} from 'src/features/on-chain/calculation-manager/providers/dexes/common/uniswap-v3-abstract/utils/quoter-controller/models/liquidity-pool';
import { UniswapV3AlgebraQuoterController } from 'src/features/on-chain/calculation-manager/providers/dexes/common/uniswap-v3-algebra-abstract/models/uniswap-v3-algebra-quoter-controller';
import { AbiItem } from 'web3-utils';

interface GetQuoterMethodsDataOptions {
routesLiquidityPools: LiquidityPool[];
Expand Down Expand Up @@ -71,7 +72,7 @@ export class UniswapV3QuoterController implements UniswapV3AlgebraQuoterControll
* @param weiAmount Amount of tokens to trade.
*/
@Cache
private static getQuoterMethodData(
protected static getQuoterMethodData(
poolsPath: LiquidityPool[],
from: Token,
to: Token,
Expand Down Expand Up @@ -119,15 +120,16 @@ export class UniswapV3QuoterController implements UniswapV3AlgebraQuoterControll

private routerLiquidityPools: LiquidityPool[] | undefined;

private readonly feeAmounts: FeeAmount[] = [500, 3000, 10000];

private get web3Public(): EvmWeb3Public {
protected get web3Public(): EvmWeb3Public {
return Injector.web3PublicService.getWeb3Public(this.blockchain);
}

constructor(
private readonly blockchain: EvmBlockchainName,
private readonly routerConfiguration: UniswapV3RouterConfiguration<string>
protected readonly blockchain: EvmBlockchainName,
protected readonly routerConfiguration: UniswapV3RouterConfiguration<string>,
protected readonly quoterContractAddress: string = UNISWAP_V3_QUOTER_CONTRACT_ADDRESS,
protected readonly quoterContractABI: AbiItem[] = UNISWAP_V3_QUOTER_CONTRACT_ABI,
protected readonly feeAmounts: FeeAmount[] = [500, 3000, 10000]
) {}

private async getOrCreateRouterTokensAndLiquidityPools(): Promise<{
Expand Down Expand Up @@ -172,7 +174,7 @@ export class UniswapV3QuoterController implements UniswapV3AlgebraQuoterControll
@Cache({
maxAge: 1000 * 60 * 10
})
private async getAllLiquidityPools(
protected async getAllLiquidityPools(
firstToken: Token,
secondToken: Token
): Promise<LiquidityPool[]> {
Expand Down Expand Up @@ -274,8 +276,8 @@ export class UniswapV3QuoterController implements UniswapV3AlgebraQuoterControll

return this.web3Public
.multicallContractMethods<string>(
UNISWAP_V3_QUOTER_CONTRACT_ADDRESS,
UNISWAP_V3_QUOTER_CONTRACT_ABI,
this.quoterContractAddress,
this.quoterContractABI,
quoterMethodsData.map(quoterMethodData => quoterMethodData.methodData)
)
.then(results => {
Expand All @@ -301,7 +303,7 @@ export class UniswapV3QuoterController implements UniswapV3AlgebraQuoterControll
/**
* Returns swap methods' names and arguments, built with passed pools' addresses, to use it in Quoter contract.
*/
private getQuoterMethodsData(
protected getQuoterMethodsData(
options: GetQuoterMethodsDataOptions,
path: LiquidityPool[],
lastTokenAddress: string
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export type UnwrapWethMethodName = 'unwrapWETH9' | 'unwrapWNativeToken' | 'unwrapWeth';
Loading

0 comments on commit 0ecf0f9

Please sign in to comment.