Skip to content

Commit

Permalink
Add FusionX dex for Mantle (#453)
Browse files Browse the repository at this point in the history
  • Loading branch information
Doctor-Cyclone authored Sep 8, 2023
2 parents c76f599 + 5e2d6d9 commit 3f4040d
Show file tree
Hide file tree
Showing 11 changed files with 665 additions and 3 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.26.0",
"version": "4.27.0",
"description": "Simplify dApp creation",
"main": "lib/index.js",
"types": "lib/index.d.ts",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { UniSwapV3ArbitrumProvider } from 'src/features/on-chain/calculation-man
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 { FusionXProvider } from 'src/features/on-chain/calculation-manager/providers/dexes/mantle/fusionx/fusionx-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';
import { UniSwapV3ScrollSepoliaProvider } from 'src/features/on-chain/calculation-manager/providers/dexes/scroll-sepolia/uni-swap-v3-scroll-sepolia/uni-swap-v3-scroll-sepolia-provider';
Expand All @@ -13,5 +14,6 @@ export const UniswapV3TradeProviders = [
UniSwapV3EthereumPowProvider,
UniSwapV3PulsechainProvider,
HorizondexProvider,
FusionXProvider,
UniSwapV3ScrollSepoliaProvider
] as const;
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ export const ON_CHAIN_TRADE_TYPE = {

ELK: 'ELK',

FUSIONX: 'FUSIONX',

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

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,212 @@
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 {
FeeAmount,
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 { FUSIONX_UNISWAP_V3_FACTORY_CONTRACT_ADDRESS } from 'src/features/on-chain/calculation-manager/providers/dexes/mantle/fusionx/constants/router-configuration';
import {
FUSIONX_QUOTER_CONTRACT_ABI,
FUSIONX_QUOTER_CONTRACT_ADDRESS
} from 'src/features/on-chain/calculation-manager/providers/dexes/mantle/fusionx/utils/quoter-controller/constants/quoter-contract-data';

interface GetQuoterMethodsDataOptions {
routesLiquidityPools: LiquidityPool[];
from: Token;
to: Token;
exact: Exact;
weiAmount: string;
maxTransitTokens: number;
}
export class FusionXUniswapV3QuoterController extends UniswapV3QuoterController {
protected readonly feeAmounts: FeeAmount[] = [100, 500, 10000];

constructor(
blockchain: EvmBlockchainName,
routerConfiguration: UniswapV3RouterConfiguration<string>
) {
super(
blockchain,
routerConfiguration,
FUSIONX_QUOTER_CONTRACT_ADDRESS,
FUSIONX_QUOTER_CONTRACT_ABI,
FUSIONX_UNISWAP_V3_FACTORY_CONTRACT_ADDRESS
);
}

/**
* 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 =>
FusionXUniswapV3QuoterController.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 = 8 | 40 | 300 | 500 | 1000 | 3000 | 10000;
export type FeeAmount = 8 | 40 | 100 | 300 | 500 | 1000 | 3000 | 10000;

/**
* Represents liquidity pool in uni v3.
Expand Down
Original file line number Diff line number Diff line change
@@ -1 +1 @@
export type UnwrapWethMethodName = 'unwrapWETH9' | 'unwrapWNativeToken' | 'unwrapWeth';
export type UnwrapWethMethodName = 'unwrapWETH9' | 'unwrapWNativeToken' | 'unwrapWeth' | 'WETH9';
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { wrappedNativeTokensList } from 'src/common/tokens';
import { BLOCKCHAIN_NAME } from 'src/core/blockchain/models/blockchain-name';
import { UniswapV3AlgebraProviderConfiguration } from 'src/features/on-chain/calculation-manager/providers/dexes/common/uniswap-v3-algebra-abstract/models/uniswap-v3-algebra-provider-configuration';

export const FUSIONX_PROVIDER_CONFIGURATION: UniswapV3AlgebraProviderConfiguration = {
wethAddress: wrappedNativeTokensList[BLOCKCHAIN_NAME.MANTLE]!.address,
maxTransitTokens: 2
};
Loading

0 comments on commit 3f4040d

Please sign in to comment.