Skip to content

Commit

Permalink
[CA] Fix error with uniswap
Browse files Browse the repository at this point in the history
  • Loading branch information
S2kael committed Oct 14, 2024
1 parent 8ac56ac commit b90250f
Show file tree
Hide file tree
Showing 6 changed files with 243 additions and 75 deletions.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@
"@polkadot/types-support": "^12.0.2",
"@polkadot/util": "^12.6.2",
"@polkadot/util-crypto": "^12.6.2",
"@uniswap/v3-periphery": "1.4.4",
"@subwallet/chain-list": "0.2.89-beta.5",
"@subwallet/keyring": "^0.1.6",
"@subwallet/react-ui": "5.1.2-b79",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ import { calculateSwapRate, handleUniswapQuote, SWAP_QUOTE_TIMEOUT_MAP } from '@
import { BaseStepDetail, CommonOptimalPath, CommonStepFeeInfo, CommonStepType, DEFAULT_FIRST_STEP, MOCK_STEP_FEE } from '@subwallet/extension-base/types/service-base';
import { OptimalSwapPathParams, SwapEarlyValidation, SwapFeeType, SwapProviderId, SwapQuote, SwapRequest, SwapStepType, SwapSubmitParams, SwapSubmitStepData, ValidateSwapProcessParams } from '@subwallet/extension-base/types/swap';
import { getEthereumSmartAccountOwner } from '@subwallet/extension-base/utils';
import { SWAP_ROUTER_02_ADDRESSES } from '@uniswap/sdk-core';
import { batchTx, encodeApproveTx, QuoteResponse, rawTx } from 'klaster-sdk';
import { TransactionConfig } from 'web3-core';

Expand Down Expand Up @@ -89,7 +88,7 @@ export class UniswapHandler implements SwapBaseInterface {
const toToken = this.swapBaseHandler.chainService.getAssetBySlug(to);
const fromChain = this.swapBaseHandler.chainService.getChainInfoByKey(fromToken.originChain);

const [availQuote] = await handleUniswapQuote(request, this.swapBaseHandler.chainService.getEvmApi(fromChain.slug), this.swapBaseHandler.chainService);
const { quote: availQuote } = await handleUniswapQuote(request, this.swapBaseHandler.chainService.getEvmApi(fromChain.slug), this.swapBaseHandler.chainService);
const result: SwapQuote = {
pair: request.pair,
fromAmount: request.fromAmount,
Expand Down Expand Up @@ -146,15 +145,10 @@ export class UniswapHandler implements SwapBaseInterface {
}
}

const bridgeOriginToken = this.swapBaseHandler.chainService.getAssetBySlug(bridgeTokenSlug);

const bridgeOriginChain = this.swapBaseHandler.chainService.getChainInfoByKey(bridgeOriginToken.originChain);
const bridgeDestChain = this.swapBaseHandler.chainService.getChainInfoByKey(toToken.originChain);

const toAddress = SWAP_ROUTER_02_ADDRESSES(chainId);
// const toAddress = SWAP_ROUTER_02_ADDRESSES(chainId);

const evmApi = this.swapBaseHandler.chainService.getEvmApi(fromToken.originChain);
const [, calldata] = await handleUniswapQuote(request, evmApi, this.swapBaseHandler.chainService);
const { callData, routerAddress: toAddress } = await handleUniswapQuote(request, evmApi, this.swapBaseHandler.chainService);

const owner = getEthereumSmartAccountOwner(request.address);
let tx: UserOpBundle | QuoteResponse;
Expand All @@ -168,7 +162,7 @@ export class UniswapHandler implements SwapBaseInterface {

const swapTx = rawTx({
to: toAddress as `0x${string}`,
data: calldata as `0x${string}`,
data: callData as `0x${string}`,
gasLimit: BigInt(250_000)
});
const txBatch = batchTx(chainId, [approveSwapTx, swapTx]);
Expand All @@ -178,35 +172,48 @@ export class UniswapHandler implements SwapBaseInterface {
await klasterService.init(owner?.owner as string);

if (bridgeTokenSlug === '0x') {
tx = await klasterService.buildTx(bridgeOriginChain, [txBatch]);
tx = await klasterService.buildTx(fromChain, [txBatch]);
} else {
const bridgeOriginToken = this.swapBaseHandler.chainService.getAssetBySlug(bridgeTokenSlug);
const bridgeOriginChain = this.swapBaseHandler.chainService.getChainInfoByKey(bridgeOriginToken.originChain);
const bridgeDestChain = this.swapBaseHandler.chainService.getChainInfoByKey(toToken.originChain);

tx = await klasterService.getBridgeTx(bridgeOriginToken, toToken, bridgeOriginChain, bridgeDestChain, params.quote.toAmount, txBatch);
}
} else {
const swapApprovalTxConfig = await getERC20SpendingApprovalTx(toAddress, params.address, _getContractAddressOfToken(fromToken), evmApi);

const swapTxConfig: TransactionConfig = {
...swapApprovalTxConfig,
data: calldata as `0x${string}`,
gas: 250_000,
data: callData as `0x${string}`,
to: toAddress as `0x${string}`
};

if (bridgeTokenSlug === '0x') {
tx = await ParticleAAHandler.createUserOperation(_getEvmChainId(bridgeOriginChain) as number, owner as SmartAccountData, [swapApprovalTxConfig, swapTxConfig]);
tx = await ParticleAAHandler.createUserOperation(_getEvmChainId(fromChain) as number, owner as SmartAccountData, [swapApprovalTxConfig, swapTxConfig]);
} else {
const bridgeOriginToken = this.swapBaseHandler.chainService.getAssetBySlug(bridgeTokenSlug);
const bridgeOriginChain = this.swapBaseHandler.chainService.getChainInfoByKey(bridgeOriginToken.originChain);
const bridgeDestChain = this.swapBaseHandler.chainService.getChainInfoByKey(toToken.originChain);
const [feeResp, bridgeTxConfig] = await getAcrossBridgeData({
amount: BigInt(params.quote.fromAmount),
amount: BigInt(params.quote.toAmount),
srcAccount: request.address,
sourceChainId: _getEvmChainId(bridgeOriginChain) as number,
sourceTokenContract: _getContractAddressOfToken(bridgeOriginToken),
destAccount: request.address,
destinationChainId: _getEvmChainId(bridgeDestChain) as number,
destinationTokenContract: _getContractAddressOfToken(toToken),
sourceChainId: _getEvmChainId(bridgeOriginChain) as number,
sourceTokenContract: _getContractAddressOfToken(bridgeOriginToken),
srcAccount: owner?.owner as string,
isTestnet: this.isTestnet
});
const bridgeApprovalTxConfig = await getERC20SpendingApprovalTx(feeResp.spokePoolAddress, params.address, _getContractAddressOfToken(bridgeOriginToken), evmApi);

tx = await ParticleAAHandler.createUserOperation(_getEvmChainId(bridgeOriginChain) as number, owner as SmartAccountData, [swapApprovalTxConfig, swapTxConfig, bridgeApprovalTxConfig, bridgeTxConfig]);
tx = await ParticleAAHandler.createUserOperation(_getEvmChainId(fromChain) as number, owner as SmartAccountData, [
swapApprovalTxConfig,
swapTxConfig,
bridgeApprovalTxConfig,
bridgeTxConfig
]);
}
}

Expand Down
124 changes: 68 additions & 56 deletions packages/extension-base/src/services/swap-service/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,16 @@

import { Asset, Assets, Chain, Chains } from '@chainflip/sdk/swap';
import { COMMON_ASSETS, COMMON_CHAIN_SLUGS } from '@subwallet/chain-list';
import { _ChainAsset } from '@subwallet/chain-list/types';
import { _ChainAsset, _ChainInfo } from '@subwallet/chain-list/types';
import { ChainService } from '@subwallet/extension-base/services/chain-service';
import { _EvmApi } from '@subwallet/extension-base/services/chain-service/types';
import { _getAssetDecimals, _getAssetName, _getAssetSymbol, _getContractAddressOfToken, _getEvmChainId } from '@subwallet/extension-base/services/chain-service/utils';
import { CHAINFLIP_BROKER_API } from '@subwallet/extension-base/services/swap-service/handler/chainflip-handler';
import { SwapPair, SwapProviderId, SwapRequest } from '@subwallet/extension-base/types/swap';
import { CurrencyAmount, Percent, QUOTER_ADDRESSES, Token, TradeType, V3_CORE_FACTORY_ADDRESSES } from '@uniswap/sdk-core';
import { CurrencyAmount, Percent, QUOTER_ADDRESSES, SWAP_ROUTER_02_ADDRESSES, Token, TradeType, V3_CORE_FACTORY_ADDRESSES } from '@uniswap/sdk-core';
// @ts-ignore
import IUniswapV3PoolABI from '@uniswap/v3-core/artifacts/contracts/interfaces/IUniswapV3Pool.sol/IUniswapV3Pool.json';
import { computePoolAddress, FeeAmount, Pool, Route, SwapQuoter, SwapRouter, Trade } from '@uniswap/v3-sdk';
import { computePoolAddress, FeeAmount, Pool as PoolV3, Route as RouteV3, SwapQuoter, SwapRouter as SwapRouterV3, Trade as TradeV3 } from '@uniswap/v3-sdk';
import BigN from 'bignumber.js';
import { ethers } from 'ethers';

Expand Down Expand Up @@ -56,7 +56,7 @@ export const _PROVIDER_TO_SUPPORTED_PAIR_MAP: Record<string, string[]> = {
[SwapProviderId.KUSAMA_ASSET_HUB]: [COMMON_CHAIN_SLUGS.KUSAMA_ASSET_HUB],
[SwapProviderId.ROCOCO_ASSET_HUB]: [COMMON_CHAIN_SLUGS.ROCOCO_ASSET_HUB],
[SwapProviderId.UNISWAP_SEPOLIA]: [COMMON_CHAIN_SLUGS.ETHEREUM_SEPOLIA, 'base_sepolia'],
[SwapProviderId.UNISWAP_ETHEREUM]: [COMMON_CHAIN_SLUGS.ARBITRUM, 'base_mainnet']
[SwapProviderId.UNISWAP_ETHEREUM]: [COMMON_CHAIN_SLUGS.ETHEREUM, COMMON_CHAIN_SLUGS.ARBITRUM, 'base_mainnet']
};

export function getSwapAlternativeAsset (swapPair: SwapPair): string | undefined {
Expand Down Expand Up @@ -122,33 +122,28 @@ export interface UniSwapPoolInfo {
tick: number
}

export async function handleUniswapQuote (request: SwapRequest, web3Api: _EvmApi, chainService: ChainService): Promise<[string, string]> {
const { from, to: _to } = request.pair;
let to = _to;

if (to === 'base_sepolia-ERC20-WETH-0x4200000000000000000000000000000000000006') {
to = 'sepolia_ethereum-ERC20-WETH-0xfFf9976782d46CC05630D1f6eBAb18b2324d6B14';
} else if (to === 'arbitrum_one-ERC20-USDC-0xaf88d065e77c8cC2239327C5EDb3A432268e5831') {
to = 'base_mainnet-ERC20-USDC-0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913';
} else if (to === 'base_mainnet-ERC20-USDC-0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913') {
to = 'arbitrum_one-ERC20-USDC-0xaf88d065e77c8cC2239327C5EDb3A432268e5831';
} else if (to === 'optimism-ERC20-DAI-0xDA10009cBd5D07dd0CeCc66161FC93D7c9000da1') {
if (from === 'base_mainnet-ERC20-USDC-0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913') {
to = 'base_mainnet-ERC20-DAI-0x50c5725949A6F0c72E6C4a641F24049A917DB0Cb';
} else {
to = 'arbitrum_one-ERC20-DAI-0xDA10009cBd5D07dd0CeCc66161FC93D7c9000da1';
}
}
interface HandlerUniswapFunctionProps {
fromToken: _ChainAsset;
toToken: _ChainAsset;
fromChain: _ChainInfo;
recipient: string;
fromAmount: string;
web3Api: _EvmApi;
}

const fromToken = chainService.getAssetBySlug(from);
const toToken = chainService.getAssetBySlug(to);
interface HandlerUniswapFunctionResult {
quote: string;
callData: string;
routerAddress: string;
}

const fromChain = chainService.getChainInfoByKey(fromToken.originChain);
const chainId: number = _getEvmChainId(fromChain) || 0;
const useV2 = ['base_sepolia', 'base_mainnet', COMMON_CHAIN_SLUGS.ETHEREUM_SEPOLIA].includes(fromChain.slug);

const handleUniswapV3 = async ({ fromAmount, fromChain, fromToken, recipient, toToken, web3Api }: HandlerUniswapFunctionProps): Promise<HandlerUniswapFunctionResult> => {
const fromContract = _getContractAddressOfToken(fromToken);
const toContract = _getContractAddressOfToken(toToken);
const chainId: number = _getEvmChainId(fromChain) || 0;
const useV2 = ['base_sepolia', 'base_mainnet', COMMON_CHAIN_SLUGS.ETHEREUM_SEPOLIA].includes(fromChain.slug);
const swaptoDAI = _getAssetSymbol(toToken) === 'DAI';

const fromTokenStruct = new Token(
chainId,
Expand All @@ -167,7 +162,7 @@ export async function handleUniswapQuote (request: SwapRequest, web3Api: _EvmApi
);

const currentPoolAddress = computePoolAddress({
fee: to.includes('DAI') ? FeeAmount.LOW : FeeAmount.HIGH,
fee: swaptoDAI ? FeeAmount.LOW : FeeAmount.HIGH,
tokenA: fromTokenStruct,
tokenB: toTokenStruct,
factoryAddress: V3_CORE_FACTORY_ADDRESSES[chainId]
Expand All @@ -189,24 +184,6 @@ export async function handleUniswapQuote (request: SwapRequest, web3Api: _EvmApi
]);

const provider = new ethers.JsonRpcProvider(web3Api.apiUrl);
// const quoterContract1 = new ethers.Contract(
// QUOTER_ADDRESSES[chainId as number],
// Quoter.abi,
// provider
// );
// try {
// const quotedAmountOut = await quoterContract1.quoteExactInputSingle.staticCall([
// fromContract,
// toContract,
// fee,
// request.fromAmount,
// toContract
// ]);
//
// console.log(quotedAmountOut);
// } catch (e) {
// console.log(e);
// }

const poolInfo: UniSwapPoolInfo = {
token0: fromContract,
Expand All @@ -220,7 +197,7 @@ export async function handleUniswapQuote (request: SwapRequest, web3Api: _EvmApi
tick: parseInt(slot0[1])
};

const pool = new Pool(
const pool = new PoolV3(
fromTokenStruct,
toTokenStruct,
poolInfo.fee,
Expand All @@ -229,7 +206,7 @@ export async function handleUniswapQuote (request: SwapRequest, web3Api: _EvmApi
poolInfo.tick
);

const swapRoute = new Route(
const swapRoute = new RouteV3(
[pool],
fromTokenStruct,
toTokenStruct
Expand All @@ -239,7 +216,7 @@ export async function handleUniswapQuote (request: SwapRequest, web3Api: _EvmApi
swapRoute,
CurrencyAmount.fromRawAmount(
fromTokenStruct,
request.fromAmount
fromAmount
),
TradeType.EXACT_INPUT,
{
Expand All @@ -254,11 +231,11 @@ export async function handleUniswapQuote (request: SwapRequest, web3Api: _EvmApi

const availQuote = web3Api.api.eth.abi.decodeParameter('uint256', quoteCallReturnData);

const uncheckedTrade = Trade.createUncheckedTrade({
const uncheckedTrade = TradeV3.createUncheckedTrade({
route: swapRoute,
inputAmount: CurrencyAmount.fromRawAmount(
fromTokenStruct,
request.fromAmount
fromAmount
),
outputAmount: CurrencyAmount.fromRawAmount(
toTokenStruct,
Expand All @@ -267,14 +244,49 @@ export async function handleUniswapQuote (request: SwapRequest, web3Api: _EvmApi
tradeType: TradeType.EXACT_INPUT
});

const methodParameters = SwapRouter.swapCallParameters([uncheckedTrade], {
const methodParameters = SwapRouterV3.swapCallParameters([uncheckedTrade], {
slippageTolerance: new Percent(500, 10_000),
deadline: Math.floor(Date.now() / 1000) + 60 * 20,
recipient: request.address
recipient
});
const routerAddress = SWAP_ROUTER_02_ADDRESSES(chainId)

return {
quote: availQuote.toString(),
callData: methodParameters.calldata,
routerAddress
};
};

export async function handleUniswapQuote (request: SwapRequest, web3Api: _EvmApi, chainService: ChainService): Promise<HandlerUniswapFunctionResult> {
const { from, to: _to } = request.pair;
let to = _to;

if (to === 'base_sepolia-ERC20-WETH-0x4200000000000000000000000000000000000006') {
to = 'sepolia_ethereum-ERC20-WETH-0xfFf9976782d46CC05630D1f6eBAb18b2324d6B14';
} else if (to === 'arbitrum_one-ERC20-USDC-0xaf88d065e77c8cC2239327C5EDb3A432268e5831') {
to = 'base_mainnet-ERC20-USDC-0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913';
} else if (to === 'base_mainnet-ERC20-USDC-0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913') {
to = 'arbitrum_one-ERC20-USDC-0xaf88d065e77c8cC2239327C5EDb3A432268e5831';
} else if (to === 'optimism-ERC20-DAI-0xDA10009cBd5D07dd0CeCc66161FC93D7c9000da1') {
if (from === 'base_mainnet-ERC20-USDC-0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913') {
to = 'base_mainnet-ERC20-DAI-0x50c5725949A6F0c72E6C4a641F24049A917DB0Cb';
} else {
to = 'arbitrum_one-ERC20-DAI-0xDA10009cBd5D07dd0CeCc66161FC93D7c9000da1';
}
}

return [
availQuote.toString(),
methodParameters.calldata
];
const fromToken = chainService.getAssetBySlug(from);
const toToken = chainService.getAssetBySlug(to);

const fromChain = chainService.getChainInfoByKey(fromToken.originChain);

return await handleUniswapV3({
fromAmount: request.fromAmount,
fromChain,
fromToken,
recipient: request.address,
toToken,
web3Api
});
}
52 changes: 52 additions & 0 deletions patches/@uniswap+v3-periphery+1.4.4.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
diff --git a/node_modules/@uniswap/v3-periphery/artifacts/contracts/SwapRouter.sol/SwapRouter.json b/node_modules/@uniswap/v3-periphery/artifacts/contracts/SwapRouter.sol/SwapRouter.json
index d7c2857..5a42685 100644
--- a/node_modules/@uniswap/v3-periphery/artifacts/contracts/SwapRouter.sol/SwapRouter.json
+++ b/node_modules/@uniswap/v3-periphery/artifacts/contracts/SwapRouter.sol/SwapRouter.json
@@ -46,11 +46,6 @@
"name": "recipient",
"type": "address"
},
- {
- "internalType": "uint256",
- "name": "deadline",
- "type": "uint256"
- },
{
"internalType": "uint256",
"name": "amountIn",
@@ -102,11 +97,6 @@
"name": "recipient",
"type": "address"
},
- {
- "internalType": "uint256",
- "name": "deadline",
- "type": "uint256"
- },
{
"internalType": "uint256",
"name": "amountIn",
@@ -153,11 +143,6 @@
"name": "recipient",
"type": "address"
},
- {
- "internalType": "uint256",
- "name": "deadline",
- "type": "uint256"
- },
{
"internalType": "uint256",
"name": "amountOut",
@@ -209,11 +194,6 @@
"name": "recipient",
"type": "address"
},
- {
- "internalType": "uint256",
- "name": "deadline",
- "type": "uint256"
- },
{
"internalType": "uint256",
"name": "amountOut",
Loading

0 comments on commit b90250f

Please sign in to comment.