From cc5e8ce0bbea1ae21bb5e4a4868e49a8a04ad923 Mon Sep 17 00:00:00 2001 From: J94k Date: Tue, 27 Feb 2024 06:35:49 +0900 Subject: [PATCH 1/6] feat: add 0x API key in the swap requests --- .gitignore | 1 + src/common/utils/request.ts | 9 ++-- src/front/config/mainnet/api.js | 1 + src/front/config/mainnet/swapContract.js | 2 +- .../pages/Exchange/QuickSwap/Feedback.tsx | 4 +- .../pages/Exchange/QuickSwap/Footer.tsx | 2 + .../pages/Exchange/QuickSwap/constants.ts | 31 +++++++++--- .../shared/pages/Exchange/QuickSwap/index.tsx | 50 ++++++++++++------- .../shared/pages/Exchange/QuickSwap/types.ts | 1 + 9 files changed, 69 insertions(+), 32 deletions(-) diff --git a/.gitignore b/.gitignore index bd0c49db34..d4de88fec1 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,7 @@ # editors .idea +.vscode .DS_Store .eslintcache *-lock.* diff --git a/src/common/utils/request.ts b/src/common/utils/request.ts index c10369d283..613616c762 100644 --- a/src/common/utils/request.ts +++ b/src/common/utils/request.ts @@ -112,10 +112,11 @@ const sendRequest = (options) => { const opts = { ...defaultOptions, ...options } const req = request[opts.method](opts.endpoint) - // req.set({ - // 'Content-Type': opts.formData ? 'application/x-www-form-urlencoded; charset=UTF-8' : 'application/json', - // ...(opts.headers || {}), - // }) + if (opts.headers) { + req.set({ + ...opts.headers, + }) + } if (opts.timeout) { req.timeout({ diff --git a/src/front/config/mainnet/api.js b/src/front/config/mainnet/api.js index 3c4e254ea6..8293e9ef94 100644 --- a/src/front/config/mainnet/api.js +++ b/src/front/config/mainnet/api.js @@ -4,6 +4,7 @@ export default { zeroxPolygon: 'https://polygon.api.0x.org', zeroxFantom: 'https://fantom.api.0x.org', zeroxAvalanche: 'https://avalanche.api.0x.org', + zeroxArbitrum: 'https://arbitrum.api.0x.org', oneinch: 'https://api.1inch.exchange/v3.0', limitOrders: 'https://limit-orders.1inch.exchange/v1.0', horizon: 'https://horizon.stellar.org', diff --git a/src/front/config/mainnet/swapContract.js b/src/front/config/mainnet/swapContract.js index e7c9514c49..a29aada91d 100644 --- a/src/front/config/mainnet/swapContract.js +++ b/src/front/config/mainnet/swapContract.js @@ -8,7 +8,7 @@ export default { protectedBtcKey: '025c8ee352e8b0d12aecd8b3d9ac3bd93cae1b2cc5de7ac56c2995ab506ac800bd', btcPinKey: '032aec5d20f9a0bb913a9835330259748392927c9a812299c4498a9e2ed3e78d3f', zerox: '0xdef1c0ded9bec7f1a1670819833240f027b25eff', - + zeroxFantom: '0xdef189deaef76e379df891899eb5a00a94cbc250', uniswapRouter: '0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D', // Ethereum uniswapFactory: '0x5C69bEe701ef814a2B6a3EDD4B1652CB9cc5aA6f', pancakeswapRouter: '0x10ED43C718714eb63d5aA57B78B54704E256024E', // BSC diff --git a/src/front/shared/pages/Exchange/QuickSwap/Feedback.tsx b/src/front/shared/pages/Exchange/QuickSwap/Feedback.tsx index 1c6511b03d..13e2353855 100644 --- a/src/front/shared/pages/Exchange/QuickSwap/Feedback.tsx +++ b/src/front/shared/pages/Exchange/QuickSwap/Feedback.tsx @@ -3,7 +3,7 @@ import { FormattedMessage } from 'react-intl' import CSSModules from 'react-css-modules' import styles from './index.scss' import { BlockReasons, Actions } from './types' -import { API_NAME } from './constants' +import { SWAP_API } from './constants' function Feedback(props) { const { @@ -25,7 +25,7 @@ function Feedback(props) { return (
- {!isSourceMode && !API_NAME[network?.networkVersion] ? ( + {!isSourceMode && !SWAP_API[network?.networkVersion] ? (

{ if (isSourceMode) return + // TODO Check the correct proxy contract in the final data + const baseCurrency = fromWallet.standard ? fromWallet.baseCurrency : fromWallet.currency const assetName = fromWallet.standard ? fromWallet.tokenKey : fromWallet.currency diff --git a/src/front/shared/pages/Exchange/QuickSwap/constants.ts b/src/front/shared/pages/Exchange/QuickSwap/constants.ts index 877e7dee9e..d68405447d 100644 --- a/src/front/shared/pages/Exchange/QuickSwap/constants.ts +++ b/src/front/shared/pages/Exchange/QuickSwap/constants.ts @@ -11,12 +11,31 @@ export const GWEI_DECIMALS = 9 export const MAX_PERCENT = 100 export const SEC_PER_MINUTE = 60 -export const API_NAME = { - 1: 'zeroxEthereum', - 56: 'zeroxBsc', - 137: 'zeroxPolygon', - 250: 'zeroxFantom', - 43114: 'zeroxAvalanche', +export const SWAP_API = { + 1: { + name: 'zeroxEthereum', + spender: 'zerox', + }, + 56: { + name: 'zeroxBsc', + spender: 'zerox', + }, + 137: { + name: 'zeroxPolygon', + spender: 'zerox', + }, + 250: { + name: 'zeroxFantom', + spender: 'zeroxFantom', + }, + 43114: { + name: 'zeroxAvalanche', + spender: 'zerox', + }, + 42161: { + name: 'zeroxArbitrum', + spender: 'zerox', + }, } export const API_GAS_LIMITS = { diff --git a/src/front/shared/pages/Exchange/QuickSwap/index.tsx b/src/front/shared/pages/Exchange/QuickSwap/index.tsx index 0f353f4c8c..8c10694026 100644 --- a/src/front/shared/pages/Exchange/QuickSwap/index.tsx +++ b/src/front/shared/pages/Exchange/QuickSwap/index.tsx @@ -31,7 +31,7 @@ import { CurrencyMenuItem, } from './types' import { - API_NAME, + SWAP_API, GWEI_DECIMALS, COIN_DECIMALS, API_GAS_LIMITS, @@ -192,6 +192,7 @@ class QuickSwap extends PureComponent { gasLimit: '', blockReason: undefined, serviceFee: false, + zeroxApiKey: window.zeroxApiKey || '', } } @@ -314,7 +315,7 @@ class QuickSwap extends PureComponent { const { coin, blockchain } = getCoinInfo(currency.value) const network = externalConfig.evmNetworks[blockchain || coin] - return !!API_NAME[network?.networkVersion] + return !!SWAP_API[network?.networkVersion] }) } @@ -346,7 +347,7 @@ class QuickSwap extends PureComponent { const feeOptsKey = fromWallet?.standard || fromWallet?.currency const currentFeeOpts = externalConfig.opts.fee[feeOptsKey?.toLowerCase()] - const correctFeeRepresentation = !Number.isNaN(window?.zeroxFeePercent) + const correctFeeRepresentation = !Number.isNaN(window?.zeroxFeePercent) && window.zeroxFeePercent >= 0 && window.zeroxFeePercent <= 100 @@ -502,8 +503,8 @@ class QuickSwap extends PureComponent { })) } - createSwapRequest = (skipValidation = false) => { - const { slippage, spendedAmount, fromWallet, toWallet, serviceFee } = this.state + buildSwapParams = (route: '/price' | '/quote', skipValidation = false) => { + const { slippage, spendedAmount, fromWallet, toWallet, serviceFee, zeroxApiKey } = this.state const sellToken = fromWallet?.contractAddress || EVM_COIN_ADDRESS const buyToken = toWallet?.contractAddress || EVM_COIN_ADDRESS @@ -516,7 +517,7 @@ class QuickSwap extends PureComponent { const enoughBalanceForSwap = new BigNumber(fromWallet.balance).isGreaterThan(new BigNumber(spendedAmount)) const request = [ - `/swap/v1/quote?`, + `/swap/v1${route}?`, `buyToken=${buyToken}&`, `sellToken=${sellToken}&`, `sellAmount=${sellAmount}`, @@ -531,7 +532,6 @@ class QuickSwap extends PureComponent { if (serviceFee) { const { address, percent } = serviceFee - request.push(`&feeRecipient=${address}`) request.push(`&buyTokenPercentageFee=${percent}`) } @@ -544,11 +544,13 @@ class QuickSwap extends PureComponent { // allow users to enter an amount up to 100, because it's more easy then enter the amount from 0 to 1 // and now convert it into the api format const correctValue = new BigNumber(slippage).dividedBy(MAX_PERCENT) - request.push(`&slippagePercentage=${correctValue}`) } - return request.join('') + return { + headers: { '0x-api-key': zeroxApiKey }, + endpoint: request.join(''), + } } onInputDataChange = async () => { @@ -640,7 +642,11 @@ class QuickSwap extends PureComponent { } fetchSwapAPIData = async () => { - const { network, spendedAmount, isPending } = this.state + const { isSourceMode, network, spendedAmount, isPending, zeroxApiKey } = this.state + + if (!isSourceMode && !zeroxApiKey) { + return console.log('%c0x API key is not set', 'color:red') + } const dontFetch = ( new BigNumber(spendedAmount).isNaN() @@ -656,31 +662,37 @@ class QuickSwap extends PureComponent { })) let repeatRequest = true - let swapRequest = this.createSwapRequest() + // TODO Send basic requests to /price to avoid exceeding API limits + const params = this.buildSwapParams('/quote') + let { headers, endpoint } = params while (repeatRequest) { - const swap: any = await apiLooper.get(API_NAME[network.networkVersion], swapRequest, { - reportErrors: (error) => { + const swap: any = await apiLooper.get(SWAP_API[network.networkVersion].name, endpoint, { + headers, + sourceError: true, + reportErrors: (error: IError) => { if (!repeatRequest) { this.reportError(error) } }, - sourceError: true, }) + console.table(swap) + if (!(swap instanceof Error)) { repeatRequest = false await this.calculateDataFromSwap({ swap, - withoutValidation: swapRequest.match(/skipValidation/), + withoutValidation: endpoint.match(/skipValidation/), }) } else if (this.tryToSkipValidation(swap)) { // it's a special error. Will be a new request - swapRequest = this.createSwapRequest(true) + const p = this.buildSwapParams('/quote', true) + headers = p.headers + endpoint = p.endpoint } else { this.reportError(swap) - repeatRequest = false } } @@ -828,9 +840,9 @@ class QuickSwap extends PureComponent { wallet = toWallet } - const spender = isSourceMode + const spender: `0x${number}` = isSourceMode ? LIQUIDITY_SOURCE_DATA[network.networkVersion]?.router - : externalConfig.swapContract.zerox + : externalConfig.swapContract[SWAP_API[network.networkVersion].spender] if (!wallet.isToken) { this.setNeedApprove(direction, false) diff --git a/src/front/shared/pages/Exchange/QuickSwap/types.ts b/src/front/shared/pages/Exchange/QuickSwap/types.ts index 2b3ceca7d0..c5d18b6a56 100644 --- a/src/front/shared/pages/Exchange/QuickSwap/types.ts +++ b/src/front/shared/pages/Exchange/QuickSwap/types.ts @@ -93,4 +93,5 @@ export type ComponentState = { blockReason: BlockReasons | undefined liquidityErrorMessage: string serviceFee: ServiceFee | false + zeroxApiKey: string } From 273403e21157855046e9273961e4f13def5a3f4d Mon Sep 17 00:00:00 2001 From: J94k Date: Thu, 29 Feb 2024 06:35:26 +0900 Subject: [PATCH 2/6] chore: add 0x testnets and validate swap proxy address before the swap --- package.json | 1 + src/front/config/testnet/api.js | 3 ++- src/front/config/testnet/swapContract.js | 3 ++- .../shared/pages/Exchange/QuickSwap/Footer.tsx | 16 +++++++--------- .../shared/pages/Exchange/QuickSwap/constants.ts | 8 ++++++++ .../shared/pages/Exchange/QuickSwap/types.ts | 1 + 6 files changed, 21 insertions(+), 11 deletions(-) diff --git a/package.json b/package.json index cce76f3c38..67787d5255 100644 --- a/package.json +++ b/package.json @@ -241,6 +241,7 @@ "graphql-request": "^3.4.0", "history": "^4.9.0", "human-standard-token-abi": "^2.0.0", + "ip": "^2.0.1", "is-local-ip": "^1.1.0", "jdenticon": "^3.1.0", "json-stringify-safe": "^5.0.1", diff --git a/src/front/config/testnet/api.js b/src/front/config/testnet/api.js index 0dfbf10ba0..5783886d90 100644 --- a/src/front/config/testnet/api.js +++ b/src/front/config/testnet/api.js @@ -1,5 +1,6 @@ export default { - zeroxRopsten: 'https://ropsten.api.0x.org', + zeroxSepolia: 'https://sepolia.api.0x.org', + zeroxMumbai: 'https://mumbai.api.0x.org', oneinch: 'https://api.1inch.exchange/v3.0', limitOrders: 'https://limit-orders.1inch.exchange/v1.0', horizon: 'https://horizon-testnet.stellar.org', diff --git a/src/front/config/testnet/swapContract.js b/src/front/config/testnet/swapContract.js index d3a0f1faca..1b59a6cfd3 100644 --- a/src/front/config/testnet/swapContract.js +++ b/src/front/config/testnet/swapContract.js @@ -9,7 +9,8 @@ export default { reputationOracle: '0x6260B5ef52d72732674fF4BDE3B37a4222dB1785', protectedBtcKey: '023d894571a253b87868db7d54a8b583e0c8ce53b484af8a0b0390b7722975cfaa', btcPinKey: '02094916ddab5abf215a49422a71be54ceb92c3d8114909048fc45ee90acdb5b32', - + zeroxSepolia: '0xdef1c0ded9bec7f1a1670819833240f027b25eff', + zeroxMumbai: '0xf471d32cb40837bf24529fcf17418fc1a4807626', uniswapRouter: '0x1b02dA8Cb0d097eB8D57A175b88c7D8b47997506', // Rinkeby uniswapFactory: '0xc35DADB65012eC5796536bD9864eD8773aBc74C4', pancakeswapRouter: '0x9Ac64Cc6e4415144C455BD8E4837Fea55603e5c3', // BSC testnet diff --git a/src/front/shared/pages/Exchange/QuickSwap/Footer.tsx b/src/front/shared/pages/Exchange/QuickSwap/Footer.tsx index 4ec4cf7dcf..67bbda9b30 100644 --- a/src/front/shared/pages/Exchange/QuickSwap/Footer.tsx +++ b/src/front/shared/pages/Exchange/QuickSwap/Footer.tsx @@ -6,7 +6,7 @@ import ADDRESSES from 'common/helpers/constants/ADDRESSES' import actions from 'redux/actions' import { feedback, externalConfig, constants, transactions, routing } from 'helpers' import { ComponentState, BlockReasons, Actions, Direction } from './types' -import { GWEI_DECIMALS, COIN_DECIMALS, LIQUIDITY_SOURCE_DATA, SEC_PER_MINUTE } from './constants' +import { SWAP_API, GWEI_DECIMALS, COIN_DECIMALS, LIQUIDITY_SOURCE_DATA, SEC_PER_MINUTE } from './constants' import Button from 'components/controls/Button/Button' type FooterProps = { @@ -63,9 +63,9 @@ function Footer(props: FooterProps) { } = parentState const approve = async (direction) => { - const spender = isSourceMode + const spender: `0x${number}` = isSourceMode ? LIQUIDITY_SOURCE_DATA[network.networkVersion]?.router - : externalConfig.swapContract.zerox + : externalConfig.swapContract[SWAP_API[network.networkVersion].spender] let wallet = fromWallet let amount = spendedAmount @@ -97,8 +97,10 @@ function Footer(props: FooterProps) { const apiSwap = async () => { if (isSourceMode) return - - // TODO Check the correct proxy contract in the final data + if (!swapData) throw new Error('No swap data. Can not complete swap') + if (swapData.to !== externalConfig.swapContract[SWAP_API[network.networkVersion].spender]) { + return console.log('%c0x constant proxy is not equal to swap transaction proxy', 'color:red') + } const baseCurrency = fromWallet.standard ? fromWallet.baseCurrency : fromWallet.currency const assetName = fromWallet.standard ? fromWallet.tokenKey : fromWallet.currency @@ -109,10 +111,6 @@ function Footer(props: FooterProps) { setPending(true) try { - if (!swapData) { - throw new Error('No swap data. Can not complete swap') - } - if (gasLimit) swapData.gas = gasLimit if (gasPrice) swapData.gasPrice = utils.amount.formatWithDecimals(gasPrice, GWEI_DECIMALS) diff --git a/src/front/shared/pages/Exchange/QuickSwap/constants.ts b/src/front/shared/pages/Exchange/QuickSwap/constants.ts index d68405447d..98f4f3cc51 100644 --- a/src/front/shared/pages/Exchange/QuickSwap/constants.ts +++ b/src/front/shared/pages/Exchange/QuickSwap/constants.ts @@ -16,6 +16,10 @@ export const SWAP_API = { name: 'zeroxEthereum', spender: 'zerox', }, + 11155111: { + name: 'zeroxSepolia', + spender: 'zeroxSepolia', + }, 56: { name: 'zeroxBsc', spender: 'zerox', @@ -24,6 +28,10 @@ export const SWAP_API = { name: 'zeroxPolygon', spender: 'zerox', }, + 80001: { + name: 'zeroxMumbai', + spender: 'zeroxMumbai', + }, 250: { name: 'zeroxFantom', spender: 'zeroxFantom', diff --git a/src/front/shared/pages/Exchange/QuickSwap/types.ts b/src/front/shared/pages/Exchange/QuickSwap/types.ts index c5d18b6a56..0b98c0644c 100644 --- a/src/front/shared/pages/Exchange/QuickSwap/types.ts +++ b/src/front/shared/pages/Exchange/QuickSwap/types.ts @@ -24,6 +24,7 @@ export type SwapData = { gasPrice: string gas: string sellAmount: string + to: `0x${number}` } export enum Sections { From a4fad0773cad77598e454093a17d51523827575c Mon Sep 17 00:00:00 2001 From: J94k Date: Fri, 1 Mar 2024 05:34:20 +0900 Subject: [PATCH 3/6] feat: add logic to use /price to avoid reaching API limits --- .../pages/Exchange/QuickSwap/Footer.tsx | 59 +++++++- .../Exchange/QuickSwap/ReviewSwapModal.tsx | 3 + .../pages/Exchange/QuickSwap/index.scss | 4 + .../shared/pages/Exchange/QuickSwap/index.tsx | 143 ++++++------------ .../pages/Exchange/QuickSwap/swapApi.ts | 140 +++++++++++++++++ 5 files changed, 245 insertions(+), 104 deletions(-) create mode 100644 src/front/shared/pages/Exchange/QuickSwap/ReviewSwapModal.tsx create mode 100644 src/front/shared/pages/Exchange/QuickSwap/swapApi.ts diff --git a/src/front/shared/pages/Exchange/QuickSwap/Footer.tsx b/src/front/shared/pages/Exchange/QuickSwap/Footer.tsx index 67bbda9b30..87382af39f 100644 --- a/src/front/shared/pages/Exchange/QuickSwap/Footer.tsx +++ b/src/front/shared/pages/Exchange/QuickSwap/Footer.tsx @@ -1,13 +1,22 @@ import { FormattedMessage } from 'react-intl' +import { useState } from 'react' import CSSModules from 'react-css-modules' import styles from './index.scss' import utils from 'common/utils' import ADDRESSES from 'common/helpers/constants/ADDRESSES' import actions from 'redux/actions' -import { feedback, externalConfig, constants, transactions, routing } from 'helpers' +import { feedback, externalConfig, constants, transactions, routing, apiLooper } from 'helpers' import { ComponentState, BlockReasons, Actions, Direction } from './types' -import { SWAP_API, GWEI_DECIMALS, COIN_DECIMALS, LIQUIDITY_SOURCE_DATA, SEC_PER_MINUTE } from './constants' +import { buildApiSwapParams, estimateApiSwapData } from './swapApi' +import { + SWAP_API, + GWEI_DECIMALS, + COIN_DECIMALS, + LIQUIDITY_SOURCE_DATA, + SEC_PER_MINUTE, +} from './constants' import Button from 'components/controls/Button/Button' +import ReviewSwapModal from './ReviewSwapModal' type FooterProps = { parentState: ComponentState @@ -60,8 +69,40 @@ function Footer(props: FooterProps) { error, slippage, currentLiquidityPair, + serviceFee, + zeroxApiKey, } = parentState + const [finalizeSwap, setFinalizeSwap] = useState(false) + const [quote, setQuote] = useState | undefined>(undefined) + + const startSwapReview = async () => { + setFinalizeSwap(true) + + const { headers, endpoint } = buildApiSwapParams({ + route: '/quote', + slippage, + spendedAmount, + fromWallet, + toWallet, + serviceFee, + zeroxApiKey, + }) + const rawQuote: any = await apiLooper.get(SWAP_API[network.networkVersion].name, endpoint, { + headers, + sourceError: true, + reportErrors: (error: IError) => {}, + }) + const data = await estimateApiSwapData({ + data: rawQuote, + baseChainWallet, + toWallet, + gasLimit, + gasPrice, + }) + setQuote(data.swapData) + } + const approve = async (direction) => { const spender: `0x${number}` = isSourceMode ? LIQUIDITY_SOURCE_DATA[network.networkVersion]?.router @@ -227,7 +268,11 @@ function Footer(props: FooterProps) { const doNotMakeApiRequest = isApiRequestBlocking() - const commonBlockReasons = isPending || (blockReason !== BlockReasons.NotApproved && !!error && (!error.message?.match('transfer amount exceeds allowance'))) + const commonBlockReasons = + isPending || + (blockReason !== BlockReasons.NotApproved && + !!error && + !error.message?.match('transfer amount exceeds allowance')) const formFilled = !!spendedAmount && !!receivedAmount const approvingDoesNotMakeSense = @@ -252,6 +297,9 @@ function Footer(props: FooterProps) { return (

+ {finalizeSwap && ( + setFinalizeSwap(false)} /> + )} {needApproveA ? ( ) : !isSourceMode ? ( - ) : sourceAction === Actions.Swap ? ( ) : sourceAction === Actions.Swap ? ( diff --git a/src/front/shared/pages/Exchange/QuickSwap/ReviewSwapModal.tsx b/src/front/shared/pages/Exchange/QuickSwap/ReviewSwapModal.tsx index 4f0ebef2ea..2182ade140 100644 --- a/src/front/shared/pages/Exchange/QuickSwap/ReviewSwapModal.tsx +++ b/src/front/shared/pages/Exchange/QuickSwap/ReviewSwapModal.tsx @@ -1,3 +1,25 @@ -export default function ReviewSwapModal() { - return
Review swap here
+import { Modal } from 'components/modal' + +interface Props { + data: any + onSwap: VoidFunction + onClose: VoidFunction +} + +export default function ReviewSwapModal(props: Props) { + const { data, onSwap, onClose } = props + + return ( +
+ + <>{JSON.stringify(data, undefined, 2)} + + +
+ ) } diff --git a/src/front/shared/pages/Exchange/QuickSwap/index.tsx b/src/front/shared/pages/Exchange/QuickSwap/index.tsx index 59b48aeb7e..f5d2501ee6 100644 --- a/src/front/shared/pages/Exchange/QuickSwap/index.tsx +++ b/src/front/shared/pages/Exchange/QuickSwap/index.tsx @@ -622,6 +622,7 @@ class QuickSwap extends PureComponent { gasPrice, onError: this.reportError, }) + console.log('SWAP PRICE response', data) this.setState(() => ({ ...data })) } else if (this.tryToSkipValidation(swap)) { const p = buildApiSwapParams({ @@ -643,6 +644,45 @@ class QuickSwap extends PureComponent { } } + finalizeApiSwapData = async () => { + const { + network, + spendedAmount, + zeroxApiKey, + slippage, + fromWallet, + toWallet, + serviceFee, + baseChainWallet, + gasLimit, + gasPrice, + } = this.state + + const { headers, endpoint } = buildApiSwapParams({ + route: '/quote', + slippage, + spendedAmount, + fromWallet, + toWallet, + serviceFee, + zeroxApiKey, + }) + const rawQuote: any = await apiLooper.get(SWAP_API[network.networkVersion].name, endpoint, { + headers, + sourceError: true, + reportErrors: this.reportError, + }) + const data = await estimateApiSwapData({ + data: rawQuote, + baseChainWallet, + toWallet, + gasLimit, + gasPrice, + }) + console.log('SWAP QUOTE response', data) + this.setState(() => ({ ...data })) + } + updateCurrentPairAddress = async () => { const { network, baseChainWallet, fromWallet, toWallet } = this.state const tokenA = fromWallet?.contractAddress || EVM_COIN_ADDRESS @@ -1201,6 +1241,7 @@ class QuickSwap extends PureComponent { insufficientBalanceB={insufficientBalanceB} setPending={this.setPending} onInputDataChange={this.onInputDataChange} + finalizeApiSwapData={this.finalizeApiSwapData} baseChainWallet={baseChainWallet} /> From 18b0e86020ea671bb5b46e971bfa582d372e43e4 Mon Sep 17 00:00:00 2001 From: J94k Date: Fri, 17 May 2024 22:19:58 +0900 Subject: [PATCH 5/6] feat: complete swap preview UI --- .../pages/Exchange/QuickSwap/Footer.tsx | 24 +++++- .../Exchange/QuickSwap/ReviewSwapModal.tsx | 79 +++++++++++++++---- .../pages/Exchange/QuickSwap/index.scss | 10 ++- .../shared/pages/Exchange/QuickSwap/index.tsx | 7 ++ .../shared/pages/Exchange/QuickSwap/types.ts | 23 +++--- 5 files changed, 115 insertions(+), 28 deletions(-) diff --git a/src/front/shared/pages/Exchange/QuickSwap/Footer.tsx b/src/front/shared/pages/Exchange/QuickSwap/Footer.tsx index 519960f13b..a93077a196 100644 --- a/src/front/shared/pages/Exchange/QuickSwap/Footer.tsx +++ b/src/front/shared/pages/Exchange/QuickSwap/Footer.tsx @@ -18,6 +18,7 @@ import Button from 'components/controls/Button/Button' import ReviewSwapModal from './ReviewSwapModal' type FooterProps = { + history: any parentState: ComponentState insufficientBalanceA: boolean insufficientBalanceB: boolean @@ -36,6 +37,7 @@ type FooterProps = { function Footer(props: FooterProps) { const { + history, parentState, isSourceMode, sourceAction, @@ -70,6 +72,9 @@ function Footer(props: FooterProps) { error, slippage, currentLiquidityPair, + swapFee, + serviceFee, + fiat, } = parentState const [finalizeSwap, setFinalizeSwap] = useState(false) @@ -137,7 +142,6 @@ function Footer(props: FooterProps) { if (txHash) { const txInfoUrl = transactions.getTxRouter(assetName.toLowerCase(), txHash) - routing.redirectTo(txInfoUrl) } @@ -148,6 +152,7 @@ function Footer(props: FooterProps) { } setPending(false) + setFinalizeSwap(false) } const directSwap = async () => { @@ -274,7 +279,22 @@ function Footer(props: FooterProps) { return (
{finalizeSwap && ( - setFinalizeSwap(false)} /> + setFinalizeSwap(false)} + history={history} + swapFee={swapFee} + fiat={fiat} + serviceFee={serviceFee} + slippage={slippage} + network={network} + spendedAmount={spendedAmount} + baseChainWallet={baseChainWallet} + fromWallet={fromWallet} + toWallet={toWallet} + /> )} {needApproveA ? ( - -
+ } + onClose={onClose} + showCloseButton + > +
+ {!isPending && ( + + )} + {isSwapStarted && ( +

+ +

+ )} + +
+
) } diff --git a/src/front/shared/pages/Exchange/QuickSwap/index.scss b/src/front/shared/pages/Exchange/QuickSwap/index.scss index ab49693f0e..26b74e986f 100644 --- a/src/front/shared/pages/Exchange/QuickSwap/index.scss +++ b/src/front/shared/pages/Exchange/QuickSwap/index.scss @@ -216,8 +216,14 @@ $maxWidth: 38em; margin-bottom: 0.5rem; } -.swapPreviewModal { - color: green; +.swapPreviewWrapper { + max-width: $maxWidth; +} + +.swapInProgressMessage { + width: 100%; + padding: 30px 0; + text-align: center; } @media all and (max-width: 500px) { diff --git a/src/front/shared/pages/Exchange/QuickSwap/index.tsx b/src/front/shared/pages/Exchange/QuickSwap/index.tsx index f5d2501ee6..8d331c31ab 100644 --- a/src/front/shared/pages/Exchange/QuickSwap/index.tsx +++ b/src/front/shared/pages/Exchange/QuickSwap/index.tsx @@ -667,6 +667,12 @@ class QuickSwap extends PureComponent { serviceFee, zeroxApiKey, }) + + this.resetSwapData() + this.setState(() => ({ + swapFee: '', + isPending: true, + })) const rawQuote: any = await apiLooper.get(SWAP_API[network.networkVersion].name, endpoint, { headers, sourceError: true, @@ -1229,6 +1235,7 @@ class QuickSwap extends PureComponent { />