diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index fd61e41274..873ea894a4 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -129,7 +129,6 @@ jobs: key: ${{ runner.os }}-generatedFiles-${{ hashFiles('**/yarn.lock') }} - name: Run eslint - if: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.repo.owner.login != github.repository_owner }} run: yarn lint integration-tests: diff --git a/apps/cowswap-frontend/.eslintrc.json b/apps/cowswap-frontend/.eslintrc.json index b2c745ef49..6ed98b0c25 100644 --- a/apps/cowswap-frontend/.eslintrc.json +++ b/apps/cowswap-frontend/.eslintrc.json @@ -57,7 +57,7 @@ "position": "before" }, { - "pattern": "{@cowswap,@cowprotocol,@uniswap,@safe-global,@ethersproject,@web3-react}/**", + "pattern": "{@cowprotocol,@cowprotocol,@uniswap,@safe-global,@ethersproject,@web3-react}/**", "group": "external", "position": "before" }, diff --git a/apps/cowswap-frontend/cosmos.config.json b/apps/cowswap-frontend/cosmos.config.json index e6367b2b64..70dc78a271 100644 --- a/apps/cowswap-frontend/cosmos.config.json +++ b/apps/cowswap-frontend/cosmos.config.json @@ -3,7 +3,7 @@ "fixtureFileSuffix": "cosmos", "watchDirs": ["src"], "port": 5001, - "exportPath": "./public/cosmos", + "exportPath": "../../build/cosmos", "publicUrl": "./", "plugins": ["react-cosmos-plugin-vite"], "vite": { diff --git a/apps/cowswap-frontend/index.html b/apps/cowswap-frontend/index.html index 672c7f28b6..37517addc5 100644 --- a/apps/cowswap-frontend/index.html +++ b/apps/cowswap-frontend/index.html @@ -36,134 +36,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/apps/cowswap-frontend/jest.config.ts b/apps/cowswap-frontend/jest.config.ts index 23c90f2f6e..db7f62924a 100644 --- a/apps/cowswap-frontend/jest.config.ts +++ b/apps/cowswap-frontend/jest.config.ts @@ -3,7 +3,7 @@ /* eslint-disable */ export default { displayName: 'cowswap', - preset: './jest.preset.js', + preset: '../../jest.preset.js', transform: { '^(?!.*\\.(js|jsx|ts|tsx|css|json)$)': '@nx/react/plugins/jest', '^.+\\.[tj]sx?$': ['babel-jest', { presets: ['@nx/react/babel'] }], diff --git a/apps/cowswap-frontend/jest.preset.js b/apps/cowswap-frontend/jest.preset.js deleted file mode 100644 index 098821875b..0000000000 --- a/apps/cowswap-frontend/jest.preset.js +++ /dev/null @@ -1,11 +0,0 @@ -const nxPreset = require('@nx/jest/preset').default - -module.exports = { - ...nxPreset, - moduleNameMapper: { - '\\.svg': '/testing/svgrMock.js', - '\\.gif': '/testing/imgMock.js', - '\\.webp': '/testing/imgMock.js', - '\\.png': '/testing/imgMock.js', - }, -} diff --git a/apps/cowswap-frontend/package.json b/apps/cowswap-frontend/package.json index 9b31c7b72c..0b3b20ea50 100644 --- a/apps/cowswap-frontend/package.json +++ b/apps/cowswap-frontend/package.json @@ -5,18 +5,18 @@ "author": "", "license": "ISC", "scripts": { - "ipfs:build": "nx exec -- cross-env PUBLIC_URL=\".\" yarn build", - "ipfs:publish": "nx exec -- ipfs-deploy build -p pinata -O", - "patch-package": "nx exec -- patch-package", - "i18n": "nx exec -- yarn i18n:compile", - "i18n:compile": "yarn i18n:extract && lingui compile", - "i18n:extract": "cross-env NODE_ENV=development lingui extract --locale en-US", - "i18n:pseudo": "lingui extract --locale pseudo && lingui compile", - "postinstall": "yarn i18n", - "cosmos:clear": "nx exec -- rm -rf ./public/cosmos", - "cosmos:run": "nx exec -- yarn _cosmos:run ", - "cosmos:export": "nx exec -- cross-env NODE_ENV=development cosmos-export", - "_cosmos:run": "yarn cosmos:clear && cosmos" + "ipfs:build": "cross-env PUBLIC_URL=\".\" yarn build", + "ipfs:publish": "npx ipfs-deploy build -p pinata -O", + "patch-package": "npx patch-package", + "i18n": "yarn run i18n:compile", + "i18n:compile": "yarn run i18n:extract && npx lingui compile", + "i18n:extract": "cross-env NODE_ENV=development npx lingui extract --locale en-US", + "i18n:pseudo": "npx lingui extract --locale pseudo && lingui compile", + "postinstall": "yarn run i18n", + "cosmos:clear": "rm -rf ./public/cosmos", + "cosmos:run": "yarn run _cosmos:run", + "cosmos:export": "cross-env NODE_ENV=development npx cosmos-export", + "_cosmos:run": "yarn cosmos:clear && npx cosmos" }, "browser": { "crypto": false diff --git a/apps/cowswap-frontend/project.json b/apps/cowswap-frontend/project.json index e483f72f76..7e3ecd7bdf 100644 --- a/apps/cowswap-frontend/project.json +++ b/apps/cowswap-frontend/project.json @@ -9,7 +9,7 @@ "outputs": ["{options.outputPath}"], "defaultConfiguration": "production", "options": { - "outputPath": "dist/apps/cowswap-frontend" + "outputPath": "build" }, "configurations": { "development": { diff --git a/apps/cowswap-frontend/src/api/1inch/index.ts b/apps/cowswap-frontend/src/api/1inch/index.ts index 23e0101787..02381b7e58 100644 --- a/apps/cowswap-frontend/src/api/1inch/index.ts +++ b/apps/cowswap-frontend/src/api/1inch/index.ts @@ -1,12 +1,12 @@ +import { getTokensFromMarket } from '@cowprotocol/common-utils' import { OrderKind } from '@cowprotocol/contracts' import { SupportedChainId as ChainId } from '@cowprotocol/cow-sdk' import { PriceInformation } from 'types' -import { getTokensFromMarket } from 'legacy/utils/misc' +import { LegacyPriceQuoteParams } from 'legacy/state/price/types' import { getValidParams } from 'legacy/utils/price' -import { LegacyPriceQuoteParams } from 'api/gnosisProtocol/legacy/types' import { fetchWithRateLimit } from 'common/utils/fetch' export const API_NAME = '1inch' diff --git a/apps/cowswap-frontend/src/legacy/utils/blocknative.ts b/apps/cowswap-frontend/src/api/blocknative.ts similarity index 96% rename from apps/cowswap-frontend/src/legacy/utils/blocknative.ts rename to apps/cowswap-frontend/src/api/blocknative.ts index 3da30ab01b..02e8ff218e 100644 --- a/apps/cowswap-frontend/src/legacy/utils/blocknative.ts +++ b/apps/cowswap-frontend/src/api/blocknative.ts @@ -1,8 +1,8 @@ +import { ALL_SUPPORTED_CHAIN_IDS } from '@cowprotocol/cow-sdk' + import * as Sentry from '@sentry/browser' import BlocknativeSdk from 'bnc-sdk' -import { ALL_SUPPORTED_CHAIN_IDS } from 'legacy/constants/chains' - const BLOCKNATIVE_API_KEY = process.env.REACT_APP_BLOCKNATIVE_API_KEY interface SDKError { diff --git a/apps/cowswap-frontend/src/api/gasPrices/index.ts b/apps/cowswap-frontend/src/api/gasPrices/index.ts index 35b24aa52b..6da9ca3898 100644 --- a/apps/cowswap-frontend/src/api/gasPrices/index.ts +++ b/apps/cowswap-frontend/src/api/gasPrices/index.ts @@ -1,8 +1,6 @@ +import { DEFAULT_NETWORK_FOR_LISTS, GAS_API_KEYS, GAS_FEE_ENDPOINTS } from '@cowprotocol/common-const' import { SupportedChainId as ChainId } from '@cowprotocol/cow-sdk' -import { GAS_FEE_ENDPOINTS, GAS_API_KEYS } from 'legacy/constants' -import { DEFAULT_NETWORK_FOR_LISTS } from 'legacy/constants/lists' - import { fetchWithRateLimit } from 'common/utils/fetch' const fetchRateLimitted = fetchWithRateLimit({ diff --git a/apps/cowswap-frontend/src/api/gnosisProtocol/api.ts b/apps/cowswap-frontend/src/api/gnosisProtocol/api.ts index b08515a235..c4fa3e3061 100644 --- a/apps/cowswap-frontend/src/api/gnosisProtocol/api.ts +++ b/apps/cowswap-frontend/src/api/gnosisProtocol/api.ts @@ -1,34 +1,33 @@ +import { ZERO_ADDRESS } from '@cowprotocol/common-const' +import { isBarn, isDev, isLocal, isPr, toErc20Address, toNativeBuyAddress } from '@cowprotocol/common-utils' import { Address, CowEnv, EnrichedOrder, NativePriceResponse, - OrderBookApiError, OrderKind, OrderQuoteRequest, OrderQuoteResponse, + OrderQuoteSideKindBuy, + OrderQuoteSideKindSell, PartialApiContext, + PriceQuality, SigningScheme, SupportedChainId as ChainId, - Trade, - PriceQuality, TotalSurplus, - OrderQuoteSideKindBuy, - OrderQuoteSideKindSell, + Trade, } from '@cowprotocol/cow-sdk' import { orderBookApi } from 'cowSdk' -import { ZERO_ADDRESS } from 'legacy/constants/misc' -import { isBarn, isDev, isLocal, isPr } from 'legacy/utils/environments' -import { toErc20Address, toNativeBuyAddress } from 'legacy/utils/tokens' +import { LegacyFeeQuoteParams as FeeQuoteParams } from 'legacy/state/price/types' import { getAppData } from 'modules/appData' -import { ApiErrorCodes, ApiErrorObject } from 'api/gnosisProtocol/errors/OperatorError' +import { ApiErrorCodes } from 'api/gnosisProtocol/errors/OperatorError' import GpQuoteError, { GpQuoteErrorDetails, mapOperatorErrorToQuoteError } from 'api/gnosisProtocol/errors/QuoteError' -import { LegacyFeeQuoteParams as FeeQuoteParams } from './legacy/types' +import { getIsOrderBookTypedError } from './getIsOrderBookTypedError' function getProfileUrl(): Partial> { if (isLocal || isDev || isPr || isBarn) { @@ -103,7 +102,20 @@ const ETH_FLOW_AUX_QUOTE_PARAMS = { } function _mapNewToLegacyParams(params: FeeQuoteParams): OrderQuoteRequest { - const { amount, kind, userAddress, receiver, validTo, sellToken, buyToken, chainId, priceQuality, isEthFlow } = params + const { + amount, + kind, + userAddress, + receiver, + validTo, + sellToken, + buyToken, + chainId, + priceQuality, + isEthFlow, + appData, + appDataHash, + } = params const fallbackAddress = userAddress || ZERO_ADDRESS const baseParams = { @@ -112,7 +124,8 @@ function _mapNewToLegacyParams(params: FeeQuoteParams): OrderQuoteRequest { buyToken: toNativeBuyAddress(buyToken, chainId), from: fallbackAddress, receiver: receiver || fallbackAddress, - appData: getAppData().appDataKeccak256, + appData: appData || getAppData().appDataKeccak256, + appDataHash, validTo, partiallyFillable: false, priceQuality, @@ -153,7 +166,7 @@ export async function getQuote(params: FeeQuoteParams): Promise { - if (isOrderbookTypedError(error)) { + if (getIsOrderBookTypedError(error)) { const errorObject = mapOperatorErrorToQuoteError(error.body) return Promise.reject(errorObject ? new GpQuoteError(errorObject) : error) @@ -163,13 +176,6 @@ export async function getQuote(params: FeeQuoteParams): Promise - -function isOrderbookTypedError(e: any): e is OrderbookTypedError { - const error = e as OrderbookTypedError - return error.body.errorType !== undefined && error.body.description !== undefined -} - export async function getOrder(chainId: ChainId, orderId: string, env?: CowEnv): Promise { const contextOverride = { chainId, diff --git a/apps/cowswap-frontend/src/api/gnosisProtocol/getIsOrderBookTypedError.ts b/apps/cowswap-frontend/src/api/gnosisProtocol/getIsOrderBookTypedError.ts new file mode 100644 index 0000000000..61726597af --- /dev/null +++ b/apps/cowswap-frontend/src/api/gnosisProtocol/getIsOrderBookTypedError.ts @@ -0,0 +1,10 @@ +import { OrderBookApiError } from '@cowprotocol/cow-sdk' + +import { ApiErrorObject } from './errors/OperatorError' + +export type OrderBookTypedError = OrderBookApiError + +export function getIsOrderBookTypedError(e: any): e is OrderBookTypedError { + const error = e as OrderBookTypedError + return error.body.errorType !== undefined && error.body.description !== undefined +} diff --git a/apps/cowswap-frontend/src/api/gnosisProtocol/hooks.ts b/apps/cowswap-frontend/src/api/gnosisProtocol/hooks.ts index 971dd6ac5a..82e70ad753 100644 --- a/apps/cowswap-frontend/src/api/gnosisProtocol/hooks.ts +++ b/apps/cowswap-frontend/src/api/gnosisProtocol/hooks.ts @@ -1,11 +1,10 @@ +import { GP_ORDER_UPDATE_INTERVAL } from '@cowprotocol/common-const' import { EnrichedOrder } from '@cowprotocol/cow-sdk' +import { useWalletInfo } from '@cowprotocol/wallet' import useSWR from 'swr' -import { GP_ORDER_UPDATE_INTERVAL } from 'legacy/constants' - import { useSWROrdersRequest } from 'modules/orders/hooks/useSWROrdersRequest' -import { useWalletInfo } from 'modules/wallet' import { getOrders } from './api' diff --git a/apps/cowswap-frontend/src/api/gnosisProtocol/index.ts b/apps/cowswap-frontend/src/api/gnosisProtocol/index.ts index ede6377c72..901a8a4395 100644 --- a/apps/cowswap-frontend/src/api/gnosisProtocol/index.ts +++ b/apps/cowswap-frontend/src/api/gnosisProtocol/index.ts @@ -2,6 +2,7 @@ import * as realApi from './api' import * as mockApi from './mock' export type { UnsupportedToken, OrderID } from './api' +export { getIsOrderBookTypedError } from './getIsOrderBookTypedError' const useMock = process.env.REACT_APP_MOCK === 'true' diff --git a/apps/cowswap-frontend/src/api/gnosisProtocol/priceApi.ts b/apps/cowswap-frontend/src/api/gnosisProtocol/priceApi.ts index cf9f0cb12a..0ba9d83320 100644 --- a/apps/cowswap-frontend/src/api/gnosisProtocol/priceApi.ts +++ b/apps/cowswap-frontend/src/api/gnosisProtocol/priceApi.ts @@ -1,8 +1,8 @@ +import { RAW_CODE_LINK } from '@cowprotocol/common-const' +import { environmentName } from '@cowprotocol/common-utils' import { SupportedChainId } from '@cowprotocol/cow-sdk' -import { RAW_CODE_LINK } from 'legacy/constants' import { GpPriceStrategy } from 'legacy/state/gas/atoms' -import { environmentName } from 'legacy/utils/environments' const API_NAME = 'CoW Protocol' const STRATEGY_URL_BASE = RAW_CODE_LINK + '/configuration/config/' diff --git a/apps/cowswap-frontend/src/api/matcha-0x/index.ts b/apps/cowswap-frontend/src/api/matcha-0x/index.ts index 6c9a7017ff..4482a577a0 100644 --- a/apps/cowswap-frontend/src/api/matcha-0x/index.ts +++ b/apps/cowswap-frontend/src/api/matcha-0x/index.ts @@ -1,12 +1,12 @@ +import { getTokensFromMarket } from '@cowprotocol/common-utils' import { OrderKind } from '@cowprotocol/contracts' import { SupportedChainId as ChainId } from '@cowprotocol/cow-sdk' import { PriceInformation } from 'types' -import { getTokensFromMarket } from 'legacy/utils/misc' +import { LegacyPriceQuoteParams } from 'legacy/state/price/types' import { getValidParams } from 'legacy/utils/price' -import { LegacyPriceQuoteParams } from 'api/gnosisProtocol/legacy/types' import { fetchWithRateLimit } from 'common/utils/fetch' // copy/pasting as the library types correspond to the internal types, not API response diff --git a/apps/cowswap-frontend/src/api/proxy/hooks.ts b/apps/cowswap-frontend/src/api/proxy/hooks.ts index 97326bd6b7..4d1d43bc92 100644 --- a/apps/cowswap-frontend/src/api/proxy/hooks.ts +++ b/apps/cowswap-frontend/src/api/proxy/hooks.ts @@ -1,17 +1,15 @@ import { atom, useAtomValue, useSetAtom } from 'jotai' +import { isAddress } from '@cowprotocol/common-utils' import { SupportedChainId } from '@cowprotocol/cow-sdk' +import { ALL_SUPPORTED_CHAIN_IDS } from '@cowprotocol/cow-sdk' import * as Sentry from '@sentry/react' import useSWR from 'swr' - -import { ALL_SUPPORTED_CHAIN_IDS } from 'legacy/constants/chains' -import { isAddress } from 'legacy/utils' +import { Nullish } from 'types' import { getTokens } from './api' -import { Nullish } from '../../types' - import type { Chain, FetchTokensApiResult, FetchTokensResult, TokenLogoCache } from './types' function isValidQuery(query: string): boolean { diff --git a/apps/cowswap-frontend/src/assets/icon/arrow.svg b/apps/cowswap-frontend/src/assets/icon/arrow.svg new file mode 100644 index 0000000000..4875d9d873 --- /dev/null +++ b/apps/cowswap-frontend/src/assets/icon/arrow.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/apps/cowswap-frontend/src/assets/icon/check.svg b/apps/cowswap-frontend/src/assets/icon/check.svg new file mode 100644 index 0000000000..67ed5ae733 --- /dev/null +++ b/apps/cowswap-frontend/src/assets/icon/check.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/apps/cowswap-frontend/src/assets/icon/gas-free.svg b/apps/cowswap-frontend/src/assets/icon/gas-free.svg new file mode 100644 index 0000000000..96b8d2d0c0 --- /dev/null +++ b/apps/cowswap-frontend/src/assets/icon/gas-free.svg @@ -0,0 +1 @@ + diff --git a/apps/cowswap-frontend/src/legacy/assets/images/x.svg b/apps/cowswap-frontend/src/assets/icon/x.svg similarity index 100% rename from apps/cowswap-frontend/src/legacy/assets/images/x.svg rename to apps/cowswap-frontend/src/assets/icon/x.svg diff --git a/apps/cowswap-frontend/src/common/constants/cosmos.ts b/apps/cowswap-frontend/src/common/constants/cosmos.ts new file mode 100644 index 0000000000..a933e516b3 --- /dev/null +++ b/apps/cowswap-frontend/src/common/constants/cosmos.ts @@ -0,0 +1,11 @@ +import { Token } from '@uniswap/sdk-core' + +export const MOCK_TOKEN = new Token( + 1, + '0x7Fc66500c84A76Ad7e9c93437bFc5Ac33E2DDaE9', + 18, + 'AAVE', + 'Aave Token' +) + +export const IMAGE_ACCOUNT = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAE8AAABOCAYAAABhaEsjAAAKCklEQVR42t2c+1dTVxbH+RP8fbTG+qitj6KooCi9dmYBYoQICDhAiLxVHhEXRIiQy0NeARKMgiht0GFkarWxavE5pDLOOFO1sZ2qIwEODyEPjVf9B/YcqcujS5B7yb3JjWet72/8QD7r7LP3/p59rp+3ltKIZmVrTVSgXJW/MiHXKIlQmJZt24kWRqahBVvSYF6EAiQRKTBfugMWRqUzS2J2ojnhyeaAtCLTKpWWjmlol2W3miR+H/oiwEYpacO4fpPWYQmtc0AwPQpr1A8hoOhn8Ff+CMt3nYMlGZ2wWN4CC+Iq4aMtuTA7XAF/CE2a0BwMdEVBNQTs004osKQRgkt16Av6oHHDfoPMYkGzPihg6i4bFdk0ro/SOZjgCies46i19BgEqvsgoPAW+O85+BLalMIgIXBfozFIraV8GlqSwUbF6J3m0HoCwh0Flt0goFgoRNOMQsoOpfhYaNqosDqneX2lw21gZPdZIaD4EIHDTSi4rFncEOkumyTxsNNMQpMncOV2WK3uJDBmqNXFWhRZ1y4+iLKm8fyN1Q6GP2hEa0qvEAj8yKgymiSi2G3SRrt5XYUDhAAXRP+Cf2wDf+CIUGhli8xr4BIMo1SE1kZ2G+/hOgKrStoEAEfKnKCSBo3HwVWdcWg21ZPdJki47r8gCLR3yxu9kVLqPFMfZh4b0wRXOgUFF6i57RFwJJk0WGijWViAijabJqRK2B23lh6AVcWkGPaU1u3XWfyF2oG7jDaNUMCIbLgs+ZuHwRGtxQCNJp53IP2tTfNljQOEyqqkLLlGsquXtLH8kJk3cAidwA13CfT8sxgu9ZbBuZ5KOH21Bk5eboDj3c3Qfr4FDp9tB92ZDqj/thOquk6B5q/fQfGJH6Dg68uQe6wHdrb1QlrrTUg23IZ4/S8ga7wP0vo+CKtF8GX1CIRUjcO68gf4n9d5B9q7PbLObXAPEC1xDKSgF0ObQSgxaAuMPIiF2PoK74MjCQRwHeheNzI+WE7ACaiqTqVIwBFhz5DxV+lm1omMojbN8yGp4OCeY126Loc/0sSnE9EO5H7+2ZBJ8nQojR0AntT/WzTkHVGJDuAGtU7JCR4zXmP2HDgihzUSjl/IhI2aavGEb3EDw7oDeeI0K14MRfMIhbvu3Y2FPzdqRAMwUN3ILvvah5tIkvCiniEpVOJEslZdJ4rsG063vj95PHp0RcGgKAGhcNe13mQIrajyOsCNdLP+vfAeDx0gZ52INPI/GZR2FHg7dBmKnuLs6+u74e8iGVZ0un17FwSW/Qsf4AavAaToZnry8mSkvYPUdeLTzZ/2vDJJ+2F1yXEvwTuIJk8UaC9JFCLU9ZtFxEQot2Oz9DIEFHu+F07QGam3uwnbKOVC8SBmeFdvqCe547hHrHoPKaRM93biGB44qhcnNKLu65rJrazycewBnvGYlbWhTP926DqG1Baxwzvbc+A9XqADgjS3cDI57AHDtAleO86IYWY9RkoQO7xTV+tY3LgNeMSJTj54QvHqvLNST1Gc6OF1Xmpi6UiPYUe6B/9IvZD3HfrfzzvUrXyGtogenrHbwPEi6SGsKBQmG6/Zpz07AW9k0NAhXmhEbedbud2JlDtAEqmET1OLYGVRPb/nnroJTcBzItrsC/AOnf2K287TPII5mzMnhiLnxWTDir3V/NlUWK/g7bX4ArzG0ye43cSp+2F22BtTpZt3wGcZJRCg4mcX1pguSvycQyWML8Cr/aaLE7zVql8xtOTX8LAwzGRYmJiPz8Jat+Ftqz/q7/d4uBh8AV5F1xlO8FYW3HgJbFJ9JE2F5XkVbva5BgrbUIU+Aa+08ywneMtzu6eAR3bh4jQVrCiamdm6Xq3zHXiq492c4C3J7CKw3iPJ1iw8KH5gpvD2+QS8gq+vcIK3WHGUQJpGszelwGeZJRzDFsNzIiXyBXg5x8yc4C1MqCWA2AiH8fyEXFzS1LCCl/TSmnIMa3wCXuaRG5zgSbYWEjAcNDcyHZbuKmNXqthQueiL5OdYipb/cJmgx6GYNgN4JJkskhfgzqRuqrtc+L23HWzpED08JIVEwx0Oo2oDBIYbkkSlw+fKqkkfyEzAG0AXsDEg1rsLMkkVp/+VNbxVRRY+4JGSJlVFOpM3Z1jQ6C2KQdtFDc81EAVbm+6zhrdC2UsA8KT5cTmvS5qQsld3uAw2Q13De0QNz2GNgciGh6zhfZ7TzSs40pnsgCVZagirOhJFbHhUImpzYOxhPETU97MvkDNO8gyOaB5u7ZS6VskbF0Ator4AQvcTIbwOsYb3SUqrcPA2Kyxvzx1jK96FYkUL7+F/d8CfaobZF8jb6wSDt1CWoX93TmVEI1pr6re7GXjwe5Slg2yHj2NLeYZGMm9OTSv17hhtf73+uUhLlp/v7IYvqsbYPfYrG8ZdglIQeMtisicft0A2C+UayhIlvH//lA8bKu0sHeQ+mB2eKky2DZdPPSFvF+mIWe/NQghm+XJ8VeEd4iDzqKWxOyFIoZx6wBFZddQzFCM2eBMPaIIrHCwL5B8F2XVLorON00/CDypFt/su9ZayzrTLdp/jP1w3yfGuU0mmhWdFV6lnIhutPW+uYF8gp3fyDs8/freR/csfVCeq3Xf6Wg17BzmlhWd4iUimpCWs4aGJRyypooF38nIjVweZN/nH7VZyf+1o1dJisarw60rW8D6OUfMYrruQ30yXA6lEYRi0X2hh3V3M3ZLHV5JgOIXru+F7ET8ZzfJ623b4+2Msu4sRmBORyUcxDAHb89z/gM1Iv0HmQilehaf7roN9dxGW4r79HqGg/fhaY8NGr55/9adOsoKHv3TmdnexMj7H5Mf3GrbSNINkXoGHn96zdJAvugVu7qYUi0SmFOYLF6PWQvo58jw8TaeJZYH8l5n7dFHpFp3RRMAJA7AYh7Bnn5QWnzjPzkFOPjQjcJ/IMiwSSiEsOBLCB+inKMlj8PYaL7GCtyChmvutmDStw2S2eAYcKWMMsseDccgT8HLbe9gVyNElXDIqLIhMpf28tdCDbIl9sAAJ7UBnt/2DBTwHzJXuZgVuTrgc+SfkUAJh4X4OugQM49SWmyzmU8bJDPIUmo21SJZuopQcM6rwYayTuAYTO14I8OxUbrjN4pNx1veCWxSVgZbGZov7K7ZPbEaFE+UhPkua+Oa70xfIRXemSAipzDr5XtrPl1Z/30HFk6EsMx+2fnTTvWnh+ef//a3e9NPoLBQk30OTEsQHl+2BQvKoL6/DheLQTF+SS7XWaeEtzfoGZ9AUZk2S0rRAqqD8PrRltbZS9v40/ZPB7RYXigcWWXrib8Jq0aTAXn4IMeSAA60vt+s3KE/LSIfwgS+LhZ41irSUfUCezwxs0z8d3Gp+NhRreYpikGswGhgUhRUJTwa2QmjtMLOx2o6Cy51mqsZpXF/pzE9qGZFRNPIqrP8DVTMveX7cETIAAAAASUVORK5CYII=" diff --git a/apps/cowswap-frontend/src/common/constants/featureFlags.ts b/apps/cowswap-frontend/src/common/constants/featureFlags.ts index bb23b1417d..d947ca6461 100644 --- a/apps/cowswap-frontend/src/common/constants/featureFlags.ts +++ b/apps/cowswap-frontend/src/common/constants/featureFlags.ts @@ -1,4 +1,3 @@ -export const AMOUNTS_FORMATTING_FEATURE_FLAG = 'highlight-amounts-formatting' export const ordersTableFeatures = { // Temporary hide estimated execution price because it requires rework and retest DISPLAY_EST_EXECUTION_PRICE: false, diff --git a/apps/cowswap-frontend/src/common/constants/routes.ts b/apps/cowswap-frontend/src/common/constants/routes.ts index c13ebd8665..91d41b6ddf 100644 --- a/apps/cowswap-frontend/src/common/constants/routes.ts +++ b/apps/cowswap-frontend/src/common/constants/routes.ts @@ -1,4 +1,4 @@ -import { isInjectedWidget } from 'common/utils/isInjectedWidget' +import { isInjectedWidget } from '@cowprotocol/common-utils' export const TRADE_WIDGET_PREFIX = isInjectedWidget() ? '/widget' : '' @@ -31,7 +31,6 @@ export const Routes = { DOCS: '/docs', STATS: '/stats', TWITTER: '/twitter', - KITCHEN_SINK: '/kitchen-sink', } as const export type RoutesKeys = keyof typeof Routes diff --git a/apps/cowswap-frontend/src/common/constants/theme.ts b/apps/cowswap-frontend/src/common/constants/theme.ts new file mode 100644 index 0000000000..6f4442824d --- /dev/null +++ b/apps/cowswap-frontend/src/common/constants/theme.ts @@ -0,0 +1,65 @@ +export enum UI { + // Colors + COLOR_WHITE = '--cow-color-white', + COLOR_BLUE = '--cow-color-blue', + COLOR_GREY = '--cow-color-grey', + COLOR_LIGHT_BLUE = '--cow-color-lightBlue', + COLOR_LIGHT_BLUE_OPACITY_90 = '--cow-color-lightBlue-opacity-90', + COLOR_LIGHT_BLUE_OPACITY_80 = '--cow-color-lightBlue-opacity-80', + COLOR_YELLOW = '--cow-color-yellow', + COLOR_YELLOW_LIGHT = '--cow-color-yellow-light', + COLOR_GREEN = '--cow-color-green', + COLOR_RED = '--cow-color-red', + + // Elements + COLOR_BORDER = '--cow-color-border', + COLOR_CONTAINER_BG_01 = '--cow-container-bg-01', + COLOR_CONTAINER_BG_02 = '--cow-container-bg-02', + + // Misc + MODAL_BACKDROP = '--cow-modal-backdrop', + BORDER_RADIUS_NORMAL = '--cow-border-radius-normal', + PADDING_NORMAL = '--cow-padding-normal', + BOX_SHADOW_NORMAL = '--cow-box-shadow-normal', + + // Icons + ICON_SIZE_NORMAL = '--cow-icon-size-normal', + ICON_SIZE_LARGE = '--cow-icon-size-large', + ICON_COLOR_NORMAL = '--cow-icon-color-normal', + + // States + COLOR_INFORMATION = '--cow-color-information', + COLOR_INFORMATION_BG = '--cow-color-information-bg', + COLOR_INFORMATION_TEXT = '--cow-color-information-text', + COLOR_ALERT = '--cow-color-alert', + COLOR_ALERT_BG = '--cow-color-alert-bg', + COLOR_ALERT_TEXT = '--cow-color-alert-text', + COLOR_ALERT2 = '--cow-color-alert2', + COLOR_ALERT2_BG = '--cow-color-alert2-bg', + COLOR_ALERT2_TEXT = '--cow-color-alert2-text', + COLOR_SUCCESS = '--cow-color-success', + COLOR_SUCCESS_BG = '--cow-color-success-bg', + COLOR_SUCCESS_TEXT = '--cow-color-success-text', + COLOR_DANGER = '--cow-color-danger', + COLOR_DANGER_BG = '--cow-color-danger-bg', + COLOR_DANGER_TEXT = '--cow-color-danger-text', + + // Text + COLOR_TEXT1 = '--cow-color-text1', + COLOR_TEXT1_INACTIVE = '--cow-color-text1-inactive', + COLOR_TEXT1_OPACITY_25 = '--cow-color-text1-opacity-25', + COLOR_TEXT1_OPACITY_10 = '--cow-color-text1-opacity-10', + COLOR_TEXT2 = '--cow-color-text2', + COLOR_LINK = '--cow-color-link', + COLOR_LINK_OPACITY_10 = '--cow-color-link-opacity-10', + FONT_WEIGHT_NORMAL = '--cow-font-weight-normal', + FONT_WEIGHT_MEDIUM = '--cow-font-weight-medium', + FONT_WEIGHT_BOLD = '--cow-font-weight-bold', + FONT_SIZE_SMALLER = '--cow-font-size-smaller', + FONT_SIZE_SMALL = '--cow-font-size-small', + FONT_SIZE_NORMAL = '--cow-font-size-normal', + FONT_SIZE_MEDIUM = '--cow-font-size-medium', + FONT_SIZE_LARGE = '--cow-font-size-large', + FONT_SIZE_LARGER = '--cow-font-size-larger', + FONT_SIZE_LARGEST = '--cow-font-size-largest', +} diff --git a/apps/cowswap-frontend/src/common/containers/ImportTokenModal/index.tsx b/apps/cowswap-frontend/src/common/containers/ImportTokenModal/index.tsx index ed8254fd3d..b3d32f64fc 100644 --- a/apps/cowswap-frontend/src/common/containers/ImportTokenModal/index.tsx +++ b/apps/cowswap-frontend/src/common/containers/ImportTokenModal/index.tsx @@ -1,22 +1,21 @@ import { useAtomValue } from 'jotai' import { useCallback, useEffect, useMemo, useState } from 'react' +import { TOKEN_SHORTHANDS, WRAPPED_NATIVE_CURRENCY } from '@cowprotocol/common-const' +import { useDebounce } from '@cowprotocol/common-hooks' +import { isInjectedWidget } from '@cowprotocol/common-utils' import { SupportedChainId } from '@cowprotocol/cow-sdk' import { Token } from '@uniswap/sdk-core' import TokenWarningModal from 'legacy/components/TokenWarningModal' -import { TOKEN_SHORTHANDS, WRAPPED_NATIVE_CURRENCY } from 'legacy/constants/tokens' import { useSearchInactiveTokenLists } from 'legacy/hooks/Tokens' -import useDebounce from 'legacy/hooks/useDebounce' -import { Field } from 'legacy/state/swap/actions' +import { Field } from 'legacy/state/types' import { useAddUserToken } from 'legacy/state/user/hooks' import { tokensByAddressAtom, tokensBySymbolAtom } from 'modules/tokensList/state/tokensListAtom' import { useNavigateOnCurrencySelection } from 'modules/trade/hooks/useNavigateOnCurrencySelection' import { useTradeState } from 'modules/trade/hooks/useTradeState' -import { isInjectedWidget } from 'common/utils/isInjectedWidget' - export interface ImportTokenModalProps { chainId: SupportedChainId } diff --git a/apps/cowswap-frontend/src/common/containers/MultipleOrdersCancellationModal/index.tsx b/apps/cowswap-frontend/src/common/containers/MultipleOrdersCancellationModal/index.tsx index 7a3acd8a85..305d779af0 100644 --- a/apps/cowswap-frontend/src/common/containers/MultipleOrdersCancellationModal/index.tsx +++ b/apps/cowswap-frontend/src/common/containers/MultipleOrdersCancellationModal/index.tsx @@ -1,14 +1,14 @@ import { useAtomValue, useSetAtom } from 'jotai' import React, { useCallback, useState } from 'react' -import { ButtonPrimary } from 'legacy/components/Button' -import { ConfirmOperationType } from 'legacy/components/TransactionConfirmationModal' +import { isRejectRequestProviderError } from '@cowprotocol/common-utils' +import { ButtonPrimary } from '@cowprotocol/ui' +import { useWalletInfo } from '@cowprotocol/wallet' + import { LegacyConfirmationModalContent } from 'legacy/components/TransactionConfirmationModal/LegacyConfirmationModalContent' import { LegacyConfirmationPendingContent } from 'legacy/components/TransactionConfirmationModal/LegacyConfirmationPendingContent' import { useRequestOrderCancellation } from 'legacy/state/orders/hooks' -import { isRejectRequestProviderError } from 'legacy/utils/misc' - -import { useWalletInfo } from 'modules/wallet' +import { ConfirmOperationType } from 'legacy/state/types' import { ordersToCancelAtom, updateOrdersToCancelAtom } from 'common/hooks/useMultipleOrdersCancellation/state' import { useCancelMultipleOrders } from 'common/hooks/useMultipleOrdersCancellation/useCancelMultipleOrders' diff --git a/apps/cowswap-frontend/src/common/containers/PermitModal/index.tsx b/apps/cowswap-frontend/src/common/containers/PermitModal/index.tsx new file mode 100644 index 0000000000..d2bb9c8d1a --- /dev/null +++ b/apps/cowswap-frontend/src/common/containers/PermitModal/index.tsx @@ -0,0 +1,15 @@ +import { useMemo } from 'react' + +import { Identicon, useWalletInfo } from '@cowprotocol/wallet' + +import { PermitModal as Pure, PermitModalProps } from '../../pure/PermitModal' + +export type PermitModalContainerProps = Omit + +export function PermitModal(props: PermitModalContainerProps) { + const { account } = useWalletInfo() + + const icon = useMemo(() => (account ? : undefined), [account]) + + return +} diff --git a/apps/cowswap-frontend/src/common/containers/TradeApprove/TradeApproveModal.tsx b/apps/cowswap-frontend/src/common/containers/TradeApprove/TradeApproveModal.tsx index ae8551e5da..da418b2659 100644 --- a/apps/cowswap-frontend/src/common/containers/TradeApprove/TradeApproveModal.tsx +++ b/apps/cowswap-frontend/src/common/containers/TradeApprove/TradeApproveModal.tsx @@ -1,9 +1,10 @@ import { useAtom } from 'jotai' import React from 'react' -import { TransactionConfirmationModal, ConfirmOperationType } from 'legacy/components/TransactionConfirmationModal' +import { TokenSymbol } from '@cowprotocol/ui' -import { TokenSymbol } from 'common/pure/TokenSymbol' +import { TransactionConfirmationModal } from 'legacy/components/TransactionConfirmationModal' +import { ConfirmOperationType } from 'legacy/state/types' import { tradeApproveStateAtom } from './tradeApproveStateAtom' diff --git a/apps/cowswap-frontend/src/common/containers/TradeApprove/useTradeApproveCallback.ts b/apps/cowswap-frontend/src/common/containers/TradeApprove/useTradeApproveCallback.ts index 13fc68b5ec..bd0d54c884 100644 --- a/apps/cowswap-frontend/src/common/containers/TradeApprove/useTradeApproveCallback.ts +++ b/apps/cowswap-frontend/src/common/containers/TradeApprove/useTradeApproveCallback.ts @@ -1,12 +1,11 @@ import { useSetAtom } from 'jotai' import { useCallback } from 'react' +import { approvalAnalytics } from '@cowprotocol/analytics' +import { isRejectRequestProviderError } from '@cowprotocol/common-utils' import { TransactionResponse } from '@ethersproject/providers' import { Currency, CurrencyAmount } from '@uniswap/sdk-core' -import { approvalAnalytics } from 'legacy/components/analytics' -import { isRejectRequestProviderError } from 'legacy/utils/misc' - import { useApproveCallback } from 'common/hooks/useApproveCallback' import { useTradeSpenderAddress } from 'common/hooks/useTradeSpenderAddress' diff --git a/apps/cowswap-frontend/src/common/containers/WalletUnsupportedNetworkBanner/index.tsx b/apps/cowswap-frontend/src/common/containers/WalletUnsupportedNetworkBanner/index.tsx index bb55a359df..2adb5e0422 100644 --- a/apps/cowswap-frontend/src/common/containers/WalletUnsupportedNetworkBanner/index.tsx +++ b/apps/cowswap-frontend/src/common/containers/WalletUnsupportedNetworkBanner/index.tsx @@ -1,10 +1,10 @@ +import { getChainInfo } from '@cowprotocol/common-const' +import { ALL_SUPPORTED_CHAIN_IDS } from '@cowprotocol/cow-sdk' + import { Trans } from '@lingui/macro' import { AlertCircle } from 'react-feather' import styled from 'styled-components/macro' -import { getChainInfo } from 'legacy/constants/chainInfo' -import { ALL_SUPPORTED_CHAIN_IDS } from 'legacy/constants/chains' - import { useIsProviderNetworkUnsupported } from 'common/hooks/useIsProviderNetworkUnsupported' export const UNSUPPORTED_WALLET_TEXT = ( diff --git a/apps/cowswap-frontend/src/common/containers/ZeroApprovalModal/ZeroApprovalModal.tsx b/apps/cowswap-frontend/src/common/containers/ZeroApprovalModal/ZeroApprovalModal.tsx index 7cce503f84..b8a11da4a5 100644 --- a/apps/cowswap-frontend/src/common/containers/ZeroApprovalModal/ZeroApprovalModal.tsx +++ b/apps/cowswap-frontend/src/common/containers/ZeroApprovalModal/ZeroApprovalModal.tsx @@ -1,6 +1,6 @@ import { useCallback, useEffect, useState } from 'react' -import { useWalletDetails, useWalletDisplayedAddress } from 'modules/wallet' +import { useWalletDetails, useWalletDisplayedAddress } from '@cowprotocol/wallet' import { ConfirmationPendingContent } from 'common/pure/ConfirmationPendingContent' import { CowModal } from 'common/pure/Modal' diff --git a/apps/cowswap-frontend/src/common/hooks/featureFlags/useIsEthFlowBundlingEnabled.ts b/apps/cowswap-frontend/src/common/hooks/featureFlags/useIsEthFlowBundlingEnabled.ts deleted file mode 100644 index 83e356e127..0000000000 --- a/apps/cowswap-frontend/src/common/hooks/featureFlags/useIsEthFlowBundlingEnabled.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { useIsBundlingSupported } from 'modules/wallet' - -import { useFeatureFlags } from 'common/hooks/featureFlags/useFeatureFlags' - -export function useIsEthFlowBundlingEnabled(): boolean { - const isBundlingSupported = useIsBundlingSupported() - - const { ethFlowBundlingEnabled } = useFeatureFlags() - - return isBundlingSupported && ethFlowBundlingEnabled -} diff --git a/apps/cowswap-frontend/src/common/hooks/featureFlags/useIsPermitEnabled.ts b/apps/cowswap-frontend/src/common/hooks/featureFlags/useIsPermitEnabled.ts new file mode 100644 index 0000000000..04e42129b7 --- /dev/null +++ b/apps/cowswap-frontend/src/common/hooks/featureFlags/useIsPermitEnabled.ts @@ -0,0 +1,25 @@ +import { SupportedChainId } from '@cowprotocol/cow-sdk' +import { useIsSmartContractWallet } from '@cowprotocol/wallet' + +import { useFeatureFlags } from './useFeatureFlags' + +export function useIsPermitEnabled(chainId: SupportedChainId | undefined): boolean { + const isSmartContractWallet = useIsSmartContractWallet() + const { permitEnabledMainnet, permitEnabledGoerli, permitEnabledGnosis } = useFeatureFlags() + + // Permit is only available for EOAs + if (isSmartContractWallet) { + return false + } + + switch (chainId) { + case SupportedChainId.MAINNET: + return !!permitEnabledMainnet + case SupportedChainId.GNOSIS_CHAIN: + return !!permitEnabledGnosis + case SupportedChainId.GOERLI: + return !!permitEnabledGoerli + default: + return false + } +} diff --git a/apps/cowswap-frontend/src/common/hooks/featureFlags/useIsTxBundlingEnabled.ts b/apps/cowswap-frontend/src/common/hooks/featureFlags/useIsTxBundlingEnabled.ts deleted file mode 100644 index d4fc5a328d..0000000000 --- a/apps/cowswap-frontend/src/common/hooks/featureFlags/useIsTxBundlingEnabled.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { useIsBundlingSupported } from 'modules/wallet' - -import { useFeatureFlags } from 'common/hooks/featureFlags/useFeatureFlags' - -export function useIsTxBundlingEnabled(): boolean { - const isBundlingSupported = useIsBundlingSupported() - - const { txBundlingEnabled } = useFeatureFlags() - - return isBundlingSupported && txBundlingEnabled -} diff --git a/apps/cowswap-frontend/src/legacy/components/analytics/hooks/useAnalyticsReporter.ts b/apps/cowswap-frontend/src/common/hooks/useAnalyticsReporter.ts similarity index 66% rename from apps/cowswap-frontend/src/legacy/components/analytics/hooks/useAnalyticsReporter.ts rename to apps/cowswap-frontend/src/common/hooks/useAnalyticsReporter.ts index 267438612d..c41f6db6e8 100644 --- a/apps/cowswap-frontend/src/legacy/components/analytics/hooks/useAnalyticsReporter.ts +++ b/apps/cowswap-frontend/src/common/hooks/useAnalyticsReporter.ts @@ -1,31 +1,28 @@ import { useEffect } from 'react' +import { + Dimensions, + GOOGLE_ANALYTICS_CLIENT_ID_STORAGE_KEY, + googleAnalytics, + PixelEvent, + sendAllPixels, +} from '@cowprotocol/analytics' +import { usePrevious } from '@cowprotocol/common-hooks' +import { + getConnectionName, + getIsMetaMask, + getWeb3ReactConnection, + useWalletDetails, + useWalletInfo, +} from '@cowprotocol/wallet' import { useWeb3React } from '@web3-react/core' import ReactGA from 'react-ga4' import { useLocation } from 'react-router-dom' import { getCLS, getFCP, getFID, getLCP, Metric } from 'web-vitals' -// Mod imports -import usePrevious from 'legacy/hooks/usePrevious' - -import { useWalletDetails, useWalletInfo } from 'modules/wallet' -import { getConnectionName, getIsMetaMask } from 'modules/wallet/api/utils/connection' -import { getWeb3ReactConnection } from 'modules/wallet/web3-react/connection' - import { useGetMarketDimension } from './useGetMarketDimension' -import { googleAnalytics } from '../googleAnalytics' -import { GOOGLE_ANALYTICS_CLIENT_ID_STORAGE_KEY } from '../index' -import { PIXEL_EVENTS } from '../pixel/constants' -import { sendFacebookEvent } from '../pixel/facebook' -import { sendLinkedinEvent } from '../pixel/linkedin' -import { sendMicrosoftEvent } from '../pixel/microsoft' -import { sendPavedEvent } from '../pixel/paved' -import { sendRedditEvent } from '../pixel/reddit' -import { sendTwitterEvent } from '../pixel/twitter' -import { Dimensions } from '../types' - export function sendTiming(timingCategory: any, timingVar: any, timingValue: any, timingLabel: any) { return googleAnalytics.gaCommandSendTiming(timingCategory, timingVar, timingValue, timingLabel) } @@ -87,12 +84,7 @@ export function useAnalyticsReporter() { // Handle pixel tracking on wallet connection if (!prevAccount && account) { - sendFacebookEvent(PIXEL_EVENTS.CONNECT_WALLET) - sendLinkedinEvent(PIXEL_EVENTS.CONNECT_WALLET) - sendTwitterEvent(PIXEL_EVENTS.CONNECT_WALLET) - sendRedditEvent(PIXEL_EVENTS.CONNECT_WALLET) - sendPavedEvent(PIXEL_EVENTS.CONNECT_WALLET) - sendMicrosoftEvent(PIXEL_EVENTS.CONNECT_WALLET) + sendAllPixels(PixelEvent.CONNECT_WALLET) } }, [account, walletName, prevAccount]) @@ -113,12 +105,18 @@ export function useAnalyticsReporter() { // Handle initiate pixel tracking useEffect(() => { if (!initiatedPixel) { - sendFacebookEvent(PIXEL_EVENTS.INIT) - sendLinkedinEvent(PIXEL_EVENTS.INIT) - sendTwitterEvent(PIXEL_EVENTS.INIT) - sendRedditEvent(PIXEL_EVENTS.INIT) - sendPavedEvent(PIXEL_EVENTS.INIT) - sendMicrosoftEvent(PIXEL_EVENTS.INIT) + // // Init all pixels + // const enablePixelFunctions = [ + // enablePixelFacebook, + // enablePixelMicrosoft, + // enablePixelPaved, + // enablePixelReddit, + // enablePixelTwitter, + // ] + // enablePixelFunctions.forEach((enablePixel) => enablePixel()) + + // Sent + sendAllPixels(PixelEvent.INIT) initiatedPixel = true } diff --git a/apps/cowswap-frontend/src/common/hooks/useApproveCallback.ts b/apps/cowswap-frontend/src/common/hooks/useApproveCallback.ts index 53333ae140..8a279423ac 100644 --- a/apps/cowswap-frontend/src/common/hooks/useApproveCallback.ts +++ b/apps/cowswap-frontend/src/common/hooks/useApproveCallback.ts @@ -1,17 +1,16 @@ import { useCallback } from 'react' -import { Erc20 } from '@cowswap/abis' +import { Erc20 } from '@cowprotocol/abis' +import { useTokenContract } from '@cowprotocol/common-hooks' +import { calculateGasMargin } from '@cowprotocol/common-utils' +import { useWalletInfo } from '@cowprotocol/wallet' import { BigNumber } from '@ethersproject/bignumber' import { MaxUint256 } from '@ethersproject/constants' import { TransactionResponse } from '@ethersproject/providers' import { Currency, CurrencyAmount } from '@uniswap/sdk-core' import { APPROVE_GAS_LIMIT_DEFAULT } from 'legacy/hooks/useApproveCallback/useApproveCallbackMod' -import { useTokenContract } from 'legacy/hooks/useContract' import { useTransactionAdder } from 'legacy/state/enhancedTransactions/hooks' -import { calculateGasMargin } from 'legacy/utils/calculateGasMargin' - -import { useWalletInfo } from 'modules/wallet' export async function estimateApprove( tokenContract: Erc20, diff --git a/apps/cowswap-frontend/src/common/hooks/useApproveState.ts b/apps/cowswap-frontend/src/common/hooks/useApproveState.ts index 3b9bddf8d2..d2278e88c6 100644 --- a/apps/cowswap-frontend/src/common/hooks/useApproveState.ts +++ b/apps/cowswap-frontend/src/common/hooks/useApproveState.ts @@ -1,19 +1,17 @@ import { useMemo } from 'react' +import { usePrevious } from '@cowprotocol/common-hooks' +import { FractionUtils } from '@cowprotocol/common-utils' +import { useWalletInfo } from '@cowprotocol/wallet' import { Currency, CurrencyAmount, Token } from '@uniswap/sdk-core' import { Nullish } from 'types' -import usePrevious from 'legacy/hooks/usePrevious' +import { ApprovalState } from 'legacy/hooks/useApproveCallback/useApproveCallbackMod' import { useTokenAllowance } from 'legacy/hooks/useTokenAllowance' import { useHasPendingApproval } from 'legacy/state/enhancedTransactions/hooks' -import { useWalletInfo } from 'modules/wallet' - import { useSafeMemo } from 'common/hooks/useSafeMemo' -import { FractionUtils } from 'utils/fractionUtils' - -import { ApprovalState } from '../../legacy/hooks/useApproveCallback/useApproveCallbackMod' function getCurrencyToApprove(amountToApprove: Nullish>): Token | undefined { if (!amountToApprove) return undefined diff --git a/apps/cowswap-frontend/src/common/hooks/useAreThereTokensWithSameSymbol.ts b/apps/cowswap-frontend/src/common/hooks/useAreThereTokensWithSameSymbol.ts index b939c8456f..cbc61ffca8 100644 --- a/apps/cowswap-frontend/src/common/hooks/useAreThereTokensWithSameSymbol.ts +++ b/apps/cowswap-frontend/src/common/hooks/useAreThereTokensWithSameSymbol.ts @@ -1,7 +1,7 @@ import { useAtomValue } from 'jotai' import { useCallback } from 'react' -import { isAddress } from 'legacy/utils' +import { isAddress } from '@cowprotocol/common-utils' import { tokensBySymbolAtom } from 'modules/tokensList/state/tokensListAtom' diff --git a/apps/cowswap-frontend/src/common/hooks/useCancelOrder/index.ts b/apps/cowswap-frontend/src/common/hooks/useCancelOrder/index.ts index 90bd592da4..12945cc6b1 100644 --- a/apps/cowswap-frontend/src/common/hooks/useCancelOrder/index.ts +++ b/apps/cowswap-frontend/src/common/hooks/useCancelOrder/index.ts @@ -2,15 +2,16 @@ import { useSetAtom } from 'jotai' import { useResetAtom } from 'jotai/utils' import { useCallback } from 'react' +import { calculateGasMargin } from '@cowprotocol/common-utils' +import { useWalletDetails, useWalletInfo } from '@cowprotocol/wallet' + import { useCloseModal, useOpenModal } from 'legacy/state/application/hooks' import { ApplicationModal } from 'legacy/state/application/reducer' import { useGasPrices } from 'legacy/state/gas/hooks' import { Order, OrderStatus } from 'legacy/state/orders/actions' -import { calculateGasMargin } from 'legacy/utils/calculateGasMargin' import { getIsEthFlowOrder } from 'modules/swap/containers/EthFlowStepper' import { getSwapErrorMessage } from 'modules/trade/utils/swapErrorHelper' -import { useWalletDetails, useWalletInfo } from 'modules/wallet' import { useGetOnChainCancellation } from 'common/hooks/useCancelOrder/useGetOnChainCancellation' import { isOrderCancellable } from 'common/utils/isOrderCancellable' diff --git a/apps/cowswap-frontend/src/common/hooks/useCancelOrder/onChainCancellation.ts b/apps/cowswap-frontend/src/common/hooks/useCancelOrder/onChainCancellation.ts index 898b11501a..b1d2b6c910 100644 --- a/apps/cowswap-frontend/src/common/hooks/useCancelOrder/onChainCancellation.ts +++ b/apps/cowswap-frontend/src/common/hooks/useCancelOrder/onChainCancellation.ts @@ -1,8 +1,8 @@ -import { GPv2Settlement, CoWSwapEthFlow } from '@cowswap/abis' +import { GPv2Settlement, CoWSwapEthFlow } from '@cowprotocol/abis' +import { calculateGasMargin } from '@cowprotocol/common-utils' import { BigNumber } from '@ethersproject/bignumber' import { Order } from 'legacy/state/orders/actions' -import { calculateGasMargin } from 'legacy/utils/calculateGasMargin' import { logTradeFlowError } from 'modules/trade/utils/logger' diff --git a/apps/cowswap-frontend/src/common/hooks/useCancelOrder/useGetOnChainCancellation.ts b/apps/cowswap-frontend/src/common/hooks/useCancelOrder/useGetOnChainCancellation.ts index e96ebcb006..aeb2a9ee56 100644 --- a/apps/cowswap-frontend/src/common/hooks/useCancelOrder/useGetOnChainCancellation.ts +++ b/apps/cowswap-frontend/src/common/hooks/useCancelOrder/useGetOnChainCancellation.ts @@ -1,6 +1,7 @@ import { useCallback } from 'react' -import { useEthFlowContract, useGP2SettlementContract } from 'legacy/hooks/useContract' +import { useEthFlowContract, useGP2SettlementContract } from '@cowprotocol/common-hooks' + import { Order } from 'legacy/state/orders/actions' import { getIsEthFlowOrder } from 'modules/swap/containers/EthFlowStepper' diff --git a/apps/cowswap-frontend/src/common/hooks/useCancelOrder/useOffChainCancelOrder.ts b/apps/cowswap-frontend/src/common/hooks/useCancelOrder/useOffChainCancelOrder.ts index a9062a06fe..fa52b7e520 100644 --- a/apps/cowswap-frontend/src/common/hooks/useCancelOrder/useOffChainCancelOrder.ts +++ b/apps/cowswap-frontend/src/common/hooks/useCancelOrder/useOffChainCancelOrder.ts @@ -1,13 +1,12 @@ import { useCallback } from 'react' +import { useWalletInfo } from '@cowprotocol/wallet' import { useWeb3React } from '@web3-react/core' import { Order } from 'legacy/state/orders/actions' import { useRequestOrderCancellation } from 'legacy/state/orders/hooks' import { sendOrderCancellation } from 'legacy/utils/trade' -import { useWalletInfo } from 'modules/wallet' - export function useOffChainCancelOrder() { const { provider } = useWeb3React() const { account, chainId } = useWalletInfo() diff --git a/apps/cowswap-frontend/src/common/hooks/useCancelOrder/useSendOnChainCancellation.test.ts b/apps/cowswap-frontend/src/common/hooks/useCancelOrder/useSendOnChainCancellation.test.ts index d100e08744..b7680f9e67 100644 --- a/apps/cowswap-frontend/src/common/hooks/useCancelOrder/useSendOnChainCancellation.test.ts +++ b/apps/cowswap-frontend/src/common/hooks/useCancelOrder/useSendOnChainCancellation.test.ts @@ -1,16 +1,14 @@ +import { COW, NATIVE_CURRENCY_BUY_TOKEN } from '@cowprotocol/common-const' +import { useEthFlowContract, useGP2SettlementContract } from '@cowprotocol/common-hooks' +import { useWalletInfo } from '@cowprotocol/wallet' import { BigNumber } from '@ethersproject/bignumber' import { renderHook } from '@testing-library/react-hooks' -import { NATIVE_CURRENCY_BUY_TOKEN } from 'legacy/constants' -import { COW } from 'legacy/constants/tokens' -import { useEthFlowContract, useGP2SettlementContract } from 'legacy/hooks/useContract' import { useTransactionAdder } from 'legacy/state/enhancedTransactions/hooks' import { Order } from 'legacy/state/orders/actions' import { useRequestOrderCancellation, useSetOrderCancellationHash } from 'legacy/state/orders/hooks' -import { useWalletInfo } from 'modules/wallet' - import { useSendOnChainCancellation } from './useSendOnChainCancellation' import { WithMockedWeb3 } from '../../../test-utils' @@ -20,15 +18,21 @@ const settlementCancellationTxHash = '0xcfwj23g4fwe111' const ethFlowCancellationTxHash = '0xcfwj23g4fwe222' jest.mock('legacy/state/orders/hooks') -jest.mock('modules/wallet', () => { +jest.mock('@cowprotocol/wallet', () => { return { - ...jest.requireActual('modules/wallet'), + ...jest.requireActual('@cowprotocol/wallet'), useWalletInfo: jest.fn().mockReturnValue({ chainId }), } }) +jest.mock('@cowprotocol/common-hooks', () => { + return { + ...jest.requireActual('@cowprotocol/common-hooks'), + useEthFlowContract: jest.fn(), + useGP2SettlementContract: jest.fn(), + } +}) jest.mock('legacy/state/enhancedTransactions/hooks') -jest.mock('legacy/hooks/useContract') -jest.mock('legacy/components/analytics/hooks/useAnalyticsReporter.ts') +jest.mock('common/hooks/useAnalyticsReporter') const orderMock = { id: 'xx1', diff --git a/apps/cowswap-frontend/src/common/hooks/useCancelOrder/useSendOnChainCancellation.ts b/apps/cowswap-frontend/src/common/hooks/useCancelOrder/useSendOnChainCancellation.ts index 0ef191e21e..7167570bef 100644 --- a/apps/cowswap-frontend/src/common/hooks/useCancelOrder/useSendOnChainCancellation.ts +++ b/apps/cowswap-frontend/src/common/hooks/useCancelOrder/useSendOnChainCancellation.ts @@ -1,12 +1,13 @@ import { useCallback } from 'react' +import { useWalletInfo } from '@cowprotocol/wallet' + import { useTransactionAdder } from 'legacy/state/enhancedTransactions/hooks' import { Order } from 'legacy/state/orders/actions' import { useRequestOrderCancellation, useSetOrderCancellationHash } from 'legacy/state/orders/hooks' import { getIsEthFlowOrder } from 'modules/swap/containers/EthFlowStepper' import { useSetPartOrderCancelling } from 'modules/twap/hooks/useSetPartOrderCancelling' -import { useWalletInfo } from 'modules/wallet' import { CancelledOrderInfo } from './onChainCancellation' import { useGetOnChainCancellation } from './useGetOnChainCancellation' diff --git a/apps/cowswap-frontend/src/common/hooks/useCategorizeRecentActivity.ts b/apps/cowswap-frontend/src/common/hooks/useCategorizeRecentActivity.ts index a19dd1a91d..14a67c4b22 100644 --- a/apps/cowswap-frontend/src/common/hooks/useCategorizeRecentActivity.ts +++ b/apps/cowswap-frontend/src/common/hooks/useCategorizeRecentActivity.ts @@ -2,12 +2,12 @@ import { useMemo } from 'react' import { OrderClass } from '@cowprotocol/cow-sdk' -import { useRecentActivity, TransactionAndOrder } from 'legacy/hooks/useRecentActivity' -import { PENDING_STATES } from 'legacy/state/orders/actions' +import { useRecentActivity } from 'legacy/hooks/useRecentActivity' +import { OrderStatus, PENDING_STATES } from 'legacy/state/orders/actions' import { getIsFinalizedOrder } from 'utils/orderUtils/getIsFinalizedOrder' -const isPending = (data: TransactionAndOrder) => PENDING_STATES.includes(data.status) +export const isPending = ({ status }: { status: OrderStatus }) => PENDING_STATES.includes(status) export function useCategorizeRecentActivity() { // Returns all RECENT (last day) transaction and orders in 2 arrays: pending and confirmed diff --git a/apps/cowswap-frontend/src/common/hooks/useConfirmPriceImpactWithoutFee.ts b/apps/cowswap-frontend/src/common/hooks/useConfirmPriceImpactWithoutFee.ts index d018aa2ad7..e08532f148 100644 --- a/apps/cowswap-frontend/src/common/hooks/useConfirmPriceImpactWithoutFee.ts +++ b/apps/cowswap-frontend/src/common/hooks/useConfirmPriceImpactWithoutFee.ts @@ -1,9 +1,8 @@ import { useCallback, useState } from 'react' +import { ALLOWED_PRICE_IMPACT_HIGH, PRICE_IMPACT_WITHOUT_FEE_CONFIRM_MIN } from '@cowprotocol/common-const' import { Percent } from '@uniswap/sdk-core' -import { ALLOWED_PRICE_IMPACT_HIGH, PRICE_IMPACT_WITHOUT_FEE_CONFIRM_MIN } from 'legacy/constants/misc' - import { useConfirmationRequest } from 'common/hooks/useConfirmationRequest' function getDescription(priceImpactWithoutFee: Percent) { diff --git a/apps/cowswap-frontend/src/common/hooks/useExternalTokenSearch.ts b/apps/cowswap-frontend/src/common/hooks/useExternalTokenSearch.ts index 80062b15cc..6a28ceb4e0 100644 --- a/apps/cowswap-frontend/src/common/hooks/useExternalTokenSearch.ts +++ b/apps/cowswap-frontend/src/common/hooks/useExternalTokenSearch.ts @@ -1,9 +1,8 @@ import { useMemo } from 'react' +import { useWalletInfo } from '@cowprotocol/wallet' import { Token } from '@uniswap/sdk-core' -import { useWalletInfo } from 'modules/wallet' - import { useProxyTokens } from 'api/proxy' export function useExternalTokenSearch(query: string, existingTokens: Map): Token[] { diff --git a/apps/cowswap-frontend/src/legacy/components/analytics/hooks/useGetMarketDimension.ts b/apps/cowswap-frontend/src/common/hooks/useGetMarketDimension.ts similarity index 100% rename from apps/cowswap-frontend/src/legacy/components/analytics/hooks/useGetMarketDimension.ts rename to apps/cowswap-frontend/src/common/hooks/useGetMarketDimension.ts diff --git a/apps/cowswap-frontend/src/common/hooks/useGetSurplusFiatValue.ts b/apps/cowswap-frontend/src/common/hooks/useGetSurplusFiatValue.ts index 65c8f83f18..8ef03b1dfe 100644 --- a/apps/cowswap-frontend/src/common/hooks/useGetSurplusFiatValue.ts +++ b/apps/cowswap-frontend/src/common/hooks/useGetSurplusFiatValue.ts @@ -1,10 +1,10 @@ import { useMemo } from 'react' +import { MIN_FIAT_SURPLUS_VALUE, MIN_FIAT_SURPLUS_VALUE_MODAL, MIN_SURPLUS_UNITS } from '@cowprotocol/common-const' import { Currency, CurrencyAmount } from '@uniswap/sdk-core' import { Nullish } from 'types' -import { MIN_FIAT_SURPLUS_VALUE, MIN_FIAT_SURPLUS_VALUE_MODAL, MIN_SURPLUS_UNITS } from 'legacy/constants' import { Order } from 'legacy/state/orders/actions' import { useUsdAmount } from 'modules/usdAmount' diff --git a/apps/cowswap-frontend/src/common/hooks/useIsAdvancedOrdersEnabled.ts b/apps/cowswap-frontend/src/common/hooks/useIsAdvancedOrdersEnabled.ts deleted file mode 100644 index b5b2f65df5..0000000000 --- a/apps/cowswap-frontend/src/common/hooks/useIsAdvancedOrdersEnabled.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { useFeatureFlags } from './featureFlags/useFeatureFlags' - -export function useIsAdvancedOrdersEnabled(): boolean | undefined { - const { advancedOrdersEnabled } = useFeatureFlags() - - return advancedOrdersEnabled -} diff --git a/apps/cowswap-frontend/src/common/hooks/useIsSmartContractWallet.ts b/apps/cowswap-frontend/src/common/hooks/useIsSmartContractWallet.ts deleted file mode 100644 index c55ef81dad..0000000000 --- a/apps/cowswap-frontend/src/common/hooks/useIsSmartContractWallet.ts +++ /dev/null @@ -1,54 +0,0 @@ -import { useState, useEffect } from 'react' - -import { useWeb3React } from '@web3-react/core' - -import useSWR from 'swr' - -import useIsAmbireWallet from 'legacy/hooks/useIsAmbireWallet' -import useIsArgentWallet from 'legacy/hooks/useIsArgentWallet' - -import { useWalletInfo } from 'modules/wallet' - -function useCheckIsSmartContract(): boolean | undefined { - const { provider } = useWeb3React() - const { account } = useWalletInfo() - - const { data } = useSWR(['isSmartContract', account, provider], async () => { - if (!account || !provider) { - return false - } - - try { - const code = await provider.getCode(account) - return code !== '0x' - } catch (e: any) { - console.debug(`checkIsSmartContractWallet: failed to check address ${account}`, e.message) - return false - } - }) - - return data -} - -export function useIsSmartContractWallet(): boolean { - const [isSmartContractWallet, setIsSmartContractWallet] = useState(false) - - const { account } = useWalletInfo() - - const isArgentWallet = useIsArgentWallet() - const isSmartContract = useCheckIsSmartContract() - const isAmbireWallet = useIsAmbireWallet() - - useEffect(() => { - if (!account) { - setIsSmartContractWallet(false) - return - } - - if (isAmbireWallet || isArgentWallet || isSmartContract) { - setIsSmartContractWallet(true) - } - }, [account, isAmbireWallet, isArgentWallet, isSmartContract]) - - return isSmartContractWallet -} diff --git a/apps/cowswap-frontend/src/common/hooks/useLegacySetChainIdToUrl.ts b/apps/cowswap-frontend/src/common/hooks/useLegacySetChainIdToUrl.ts index bec8b623eb..d2cbbd1f67 100644 --- a/apps/cowswap-frontend/src/common/hooks/useLegacySetChainIdToUrl.ts +++ b/apps/cowswap-frontend/src/common/hooks/useLegacySetChainIdToUrl.ts @@ -1,11 +1,10 @@ import { useCallback } from 'react' +import { getChainInfo } from '@cowprotocol/common-const' import { SupportedChainId } from '@cowprotocol/cow-sdk' import { useLocation, useNavigate } from 'react-router-dom' -import { getChainInfo } from 'legacy/constants/chainInfo' - import { useTradeTypeInfo } from 'modules/trade' /** diff --git a/apps/cowswap-frontend/src/common/hooks/useMultipleOrdersCancellation/useCancelMultipleOrders.ts b/apps/cowswap-frontend/src/common/hooks/useMultipleOrdersCancellation/useCancelMultipleOrders.ts index 20a14be3d1..bb08231d0b 100644 --- a/apps/cowswap-frontend/src/common/hooks/useMultipleOrdersCancellation/useCancelMultipleOrders.ts +++ b/apps/cowswap-frontend/src/common/hooks/useMultipleOrdersCancellation/useCancelMultipleOrders.ts @@ -1,12 +1,11 @@ import { useCallback } from 'react' import { OrderSigningUtils } from '@cowprotocol/cow-sdk' +import { useWalletInfo } from '@cowprotocol/wallet' import { useWeb3React } from '@web3-react/core' import { orderBookApi } from 'cowSdk' -import { useWalletInfo } from 'modules/wallet' - import { CancellableOrder, isOrderCancellable } from 'common/utils/isOrderCancellable' export function useCancelMultipleOrders(): (orders: CancellableOrder[]) => Promise { diff --git a/apps/cowswap-frontend/src/common/hooks/useNeedsApproval.ts b/apps/cowswap-frontend/src/common/hooks/useNeedsApproval.ts index 6f4622707d..d3478d41f1 100644 --- a/apps/cowswap-frontend/src/common/hooks/useNeedsApproval.ts +++ b/apps/cowswap-frontend/src/common/hooks/useNeedsApproval.ts @@ -1,12 +1,12 @@ +import { isEnoughAmount } from '@cowprotocol/common-utils' +import { useWalletInfo } from '@cowprotocol/wallet' import { Currency, CurrencyAmount } from '@uniswap/sdk-core' import { Nullish } from 'types' import { useBalancesAndAllowances } from 'modules/tokens' -import { useWalletInfo } from 'modules/wallet' import { useTradeSpenderAddress } from 'common/hooks/useTradeSpenderAddress' -import { isEnoughAmount } from 'utils/isEnoughAmount' /** * Hook to check if a token needs approval diff --git a/apps/cowswap-frontend/src/common/hooks/useNeedsZeroApproval.ts b/apps/cowswap-frontend/src/common/hooks/useNeedsZeroApproval.ts index ad4e917180..dbc96cf941 100644 --- a/apps/cowswap-frontend/src/common/hooks/useNeedsZeroApproval.ts +++ b/apps/cowswap-frontend/src/common/hooks/useNeedsZeroApproval.ts @@ -1,6 +1,6 @@ import { useEffect, useState } from 'react' -import { Erc20 } from '@cowswap/abis' +import { Erc20 } from '@cowprotocol/abis' import { CurrencyAmount, Token } from '@uniswap/sdk-core' import { Nullish } from 'types' diff --git a/apps/cowswap-frontend/src/common/hooks/useOnSelectNetwork.ts b/apps/cowswap-frontend/src/common/hooks/useOnSelectNetwork.ts index f09bec350c..a77499dc6a 100644 --- a/apps/cowswap-frontend/src/common/hooks/useOnSelectNetwork.ts +++ b/apps/cowswap-frontend/src/common/hooks/useOnSelectNetwork.ts @@ -1,6 +1,8 @@ import { useCallback } from 'react' import { SupportedChainId } from '@cowprotocol/cow-sdk' +import { getWeb3ReactConnection } from '@cowprotocol/wallet' +import { switchChain } from '@cowprotocol/wallet' import { useWeb3React } from '@web3-react/core' import { useAddPopup, useCloseModal } from 'legacy/state/application/hooks' @@ -8,9 +10,6 @@ import { ApplicationModal } from 'legacy/state/application/reducer' import { updateConnectionError } from 'legacy/state/connection/reducer' import { useAppDispatch } from 'legacy/state/hooks' -import { getWeb3ReactConnection } from 'modules/wallet/web3-react/connection' -import { switchChain } from 'modules/wallet/web3-react/hooks/switchChain' - import { useLegacySetChainIdToUrl } from './useLegacySetChainIdToUrl' export function useOnSelectNetwork(): (chainId: SupportedChainId, skipClose?: boolean) => Promise { diff --git a/apps/cowswap-frontend/src/common/hooks/usePrice.ts b/apps/cowswap-frontend/src/common/hooks/usePrice.ts index 6e3b9db800..c5f6118763 100644 --- a/apps/cowswap-frontend/src/common/hooks/usePrice.ts +++ b/apps/cowswap-frontend/src/common/hooks/usePrice.ts @@ -1,9 +1,8 @@ +import { buildPriceFromCurrencyAmounts } from '@cowprotocol/common-utils' import { Currency, CurrencyAmount, Price } from '@uniswap/sdk-core' import { Nullish } from 'types' -import { buildPriceFromCurrencyAmounts } from 'modules/utils/orderUtils/buildPriceFromCurrencyAmounts' - import { useSafeMemo } from 'common/hooks/useSafeMemo' export function usePrice( diff --git a/apps/cowswap-frontend/src/common/hooks/useRateInfoParams.ts b/apps/cowswap-frontend/src/common/hooks/useRateInfoParams.ts index 11a28941c4..de4c03d2ac 100644 --- a/apps/cowswap-frontend/src/common/hooks/useRateInfoParams.ts +++ b/apps/cowswap-frontend/src/common/hooks/useRateInfoParams.ts @@ -1,16 +1,16 @@ import { useCallback } from 'react' +import { tryParseCurrencyAmount } from '@cowprotocol/common-utils' +import { useWalletInfo } from '@cowprotocol/wallet' import { Currency, CurrencyAmount } from '@uniswap/sdk-core' import { Nullish } from 'types' import { useTradeUsdAmounts } from 'modules/usdAmount' -import { useWalletInfo } from 'modules/wallet' import { usePrice } from 'common/hooks/usePrice' import { useSafeMemoObject } from 'common/hooks/useSafeMemo' import { RateInfoParams } from 'common/pure/RateInfo' -import tryParseCurrencyAmount from 'lib/utils/tryParseCurrencyAmount' export function useRateInfoParams( inputCurrencyAmount: Nullish>, diff --git a/apps/cowswap-frontend/src/api/gnosisSafe/hooks/useSafeApiKit.ts b/apps/cowswap-frontend/src/common/hooks/useSafeApiKit.ts similarity index 83% rename from apps/cowswap-frontend/src/api/gnosisSafe/hooks/useSafeApiKit.ts rename to apps/cowswap-frontend/src/common/hooks/useSafeApiKit.ts index ac936afa20..90bd897a9c 100644 --- a/apps/cowswap-frontend/src/api/gnosisSafe/hooks/useSafeApiKit.ts +++ b/apps/cowswap-frontend/src/common/hooks/useSafeApiKit.ts @@ -1,12 +1,10 @@ import { useEffect, useState } from 'react' +import { createSafeApiKitInstance } from '@cowprotocol/core' +import { useIsSafeWallet, useWalletInfo } from '@cowprotocol/wallet' import SafeApiKit from '@safe-global/api-kit' import { useWeb3React } from '@web3-react/core' -import { useIsSafeWallet, useWalletInfo } from 'modules/wallet' - -import { createSafeApiKitInstance } from 'api/gnosisSafe' - export function useSafeApiKit(): SafeApiKit | null { const [safeApiClient, setSafeApiClient] = useState(null) const { chainId } = useWalletInfo() diff --git a/apps/cowswap-frontend/src/common/hooks/useShouldZeroApprove/shouldZeroApprove.ts b/apps/cowswap-frontend/src/common/hooks/useShouldZeroApprove/shouldZeroApprove.ts index eb36850036..545796d95e 100644 --- a/apps/cowswap-frontend/src/common/hooks/useShouldZeroApprove/shouldZeroApprove.ts +++ b/apps/cowswap-frontend/src/common/hooks/useShouldZeroApprove/shouldZeroApprove.ts @@ -1,4 +1,4 @@ -import { Erc20 } from '@cowswap/abis' +import { Erc20 } from '@cowprotocol/abis' import { Currency, CurrencyAmount } from '@uniswap/sdk-core' import { Nullish } from 'types' diff --git a/apps/cowswap-frontend/src/common/hooks/useShouldZeroApprove/useShouldZeroApprove.ts b/apps/cowswap-frontend/src/common/hooks/useShouldZeroApprove/useShouldZeroApprove.ts index d05993c1b6..0246824844 100644 --- a/apps/cowswap-frontend/src/common/hooks/useShouldZeroApprove/useShouldZeroApprove.ts +++ b/apps/cowswap-frontend/src/common/hooks/useShouldZeroApprove/useShouldZeroApprove.ts @@ -1,11 +1,10 @@ import { useEffect, useState } from 'react' +import { useTokenContract } from '@cowprotocol/common-hooks' import { Currency, CurrencyAmount } from '@uniswap/sdk-core' import { Nullish } from 'types' -import { useTokenContract } from 'legacy/hooks/useContract' - import { useApprovalStateForSpender } from 'lib/hooks/useApproval' import { shouldZeroApprove as shouldZeroApproveFn } from './shouldZeroApprove' diff --git a/apps/cowswap-frontend/src/common/hooks/useTokenBySymbolOrAddress.ts b/apps/cowswap-frontend/src/common/hooks/useTokenBySymbolOrAddress.ts index 677cadec7c..5bc0025f73 100644 --- a/apps/cowswap-frontend/src/common/hooks/useTokenBySymbolOrAddress.ts +++ b/apps/cowswap-frontend/src/common/hooks/useTokenBySymbolOrAddress.ts @@ -1,6 +1,7 @@ import { useAtomValue } from 'jotai' import { useMemo } from 'react' +import { doesTokenMatchSymbolOrAddress } from '@cowprotocol/common-utils' import { NativeCurrency, Token } from '@uniswap/sdk-core' import { useFavouriteTokens } from 'legacy/state/user/hooks' @@ -8,7 +9,6 @@ import { useFavouriteTokens } from 'legacy/state/user/hooks' import { tokensByAddressAtom, tokensBySymbolAtom } from 'modules/tokensList/state/tokensListAtom' import useNativeCurrency from 'lib/hooks/useNativeCurrency' -import { doesTokenMatchSymbolOrAddress } from 'utils/doesTokenMatchSymbolOrAddress' export function useTokenBySymbolOrAddress(symbolOrAddress?: string | null): Token | NativeCurrency | null { const tokensByAddress = useAtomValue(tokensByAddressAtom) diff --git a/apps/cowswap-frontend/src/common/hooks/useTradeSpenderAddress.ts b/apps/cowswap-frontend/src/common/hooks/useTradeSpenderAddress.ts index dc8ecc1af2..2115b5b5f3 100644 --- a/apps/cowswap-frontend/src/common/hooks/useTradeSpenderAddress.ts +++ b/apps/cowswap-frontend/src/common/hooks/useTradeSpenderAddress.ts @@ -1,8 +1,7 @@ import { useMemo } from 'react' -import { GP_VAULT_RELAYER } from 'legacy/constants' - -import { useWalletInfo } from 'modules/wallet' +import { GP_VAULT_RELAYER } from '@cowprotocol/common-const' +import { useWalletInfo } from '@cowprotocol/wallet' export function useTradeSpenderAddress(): string | undefined { const { chainId } = useWalletInfo() diff --git a/apps/cowswap-frontend/src/common/hooks/useWalletStatusIcon.ts b/apps/cowswap-frontend/src/common/hooks/useWalletStatusIcon.ts index de738b1d5c..8d246eb0f2 100644 --- a/apps/cowswap-frontend/src/common/hooks/useWalletStatusIcon.ts +++ b/apps/cowswap-frontend/src/common/hooks/useWalletStatusIcon.ts @@ -1,7 +1,7 @@ +import { useWalletDetails } from '@cowprotocol/wallet' import { useWeb3React } from '@web3-react/core' import { getStatusIcon } from 'modules/account/containers/AccountDetails' -import { useWalletDetails } from 'modules/wallet' export function useWalletStatusIcon(): JSX.Element | null { const walletDetails = useWalletDetails() diff --git a/apps/cowswap-frontend/src/common/hooks/useZeroApprove.ts b/apps/cowswap-frontend/src/common/hooks/useZeroApprove.ts index 7380cda8a4..eb52d63f07 100644 --- a/apps/cowswap-frontend/src/common/hooks/useZeroApprove.ts +++ b/apps/cowswap-frontend/src/common/hooks/useZeroApprove.ts @@ -1,19 +1,17 @@ import { useSetAtom } from 'jotai' import { useCallback } from 'react' +import { useIsSafeWallet, walletConnectConnectionV2 } from '@cowprotocol/wallet' import SafeApiKit from '@safe-global/api-kit' import { SafeMultisigTransactionResponse } from '@safe-global/safe-core-sdk-types' import { Currency, CurrencyAmount } from '@uniswap/sdk-core' import { useIsActiveWallet } from 'legacy/hooks/useIsActiveWallet' -import { useIsSafeWallet } from 'modules/wallet' -import { walletConnectConnection } from 'modules/wallet/web3-react/connection/walletConnect' - -import { useSafeApiKit } from 'api/gnosisSafe/hooks/useSafeApiKit' import { pollUntil } from 'common/utils/pollUntil' import { useApproveCallback } from './useApproveCallback' +import { useSafeApiKit } from './useSafeApiKit' import { useTradeSpenderAddress } from './useTradeSpenderAddress' import { zeroApprovalState } from '../state/useZeroApprovalState' @@ -46,7 +44,7 @@ export function useZeroApprove(currency: Currency) { const amountToApprove = CurrencyAmount.fromRawAmount(currency, 0) const approveCallback = useApproveCallback(amountToApprove, spender) const safeApiKit = useSafeApiKit() - const isWalletConnect = useIsActiveWallet(walletConnectConnection) + const isWalletConnect = useIsActiveWallet(walletConnectConnectionV2) const isSafeWallet = useIsSafeWallet() return useCallback(async () => { diff --git a/apps/cowswap-frontend/src/common/pure/AnimatedConfirmation/index.tsx b/apps/cowswap-frontend/src/common/pure/AnimatedConfirmation/index.tsx index 038e8339d3..5116334866 100644 --- a/apps/cowswap-frontend/src/common/pure/AnimatedConfirmation/index.tsx +++ b/apps/cowswap-frontend/src/common/pure/AnimatedConfirmation/index.tsx @@ -1,6 +1,6 @@ -import styled, { keyframes } from 'styled-components/macro' +import { useTheme } from '@cowprotocol/common-hooks' -import useTheme from 'legacy/hooks/useTheme' +import styled, { keyframes } from 'styled-components/macro' const Wrapper = styled.div` height: 90px; diff --git a/apps/cowswap-frontend/src/common/pure/ApproveButton/index.cosmos.tsx b/apps/cowswap-frontend/src/common/pure/ApproveButton/index.cosmos.tsx index c946e29f17..90b6b42274 100644 --- a/apps/cowswap-frontend/src/common/pure/ApproveButton/index.cosmos.tsx +++ b/apps/cowswap-frontend/src/common/pure/ApproveButton/index.cosmos.tsx @@ -1,9 +1,9 @@ +import { COW, GNO } from '@cowprotocol/common-const' import { SupportedChainId } from '@cowprotocol/cow-sdk' import { DemoContainer } from 'cosmos.decorator' import { useSelect } from 'react-cosmos/client' -import { COW, GNO } from 'legacy/constants/tokens' import { ApprovalState } from 'legacy/hooks/useApproveCallback/useApproveCallbackMod' import { ApproveButton } from '.' diff --git a/apps/cowswap-frontend/src/common/pure/ApproveButton/index.tsx b/apps/cowswap-frontend/src/common/pure/ApproveButton/index.tsx index fd4adbac7c..7803251226 100644 --- a/apps/cowswap-frontend/src/common/pure/ApproveButton/index.tsx +++ b/apps/cowswap-frontend/src/common/pure/ApproveButton/index.tsx @@ -1,20 +1,16 @@ import { useContext, useMemo } from 'react' +import { ButtonSize, Loader, TokenSymbol, AutoRow, ButtonConfirmed } from '@cowprotocol/ui' +import { MouseoverTooltip } from '@cowprotocol/ui' import { Currency } from '@uniswap/sdk-core' import { Trans } from '@lingui/macro' import { CheckCircle, HelpCircle } from 'react-feather' import { ThemeContext } from 'styled-components/macro' -import { ButtonConfirmed } from 'legacy/components/Button' -import Loader from 'legacy/components/Loader' -import { AutoRow } from 'legacy/components/Row' -import { MouseoverTooltip } from 'legacy/components/Tooltip' import { ApprovalState } from 'legacy/hooks/useApproveCallback/useApproveCallbackMod' -import { ButtonSize } from 'legacy/theme/enum' import { CurrencyLogo } from 'common/pure/CurrencyLogo' -import { TokenSymbol } from 'common/pure/TokenSymbol' export interface ApproveButtonProps { currency: Currency | undefined | null diff --git a/apps/cowswap-frontend/src/common/pure/ButtonSecondary/index.tsx b/apps/cowswap-frontend/src/common/pure/ButtonSecondary/index.tsx index 4b62545f8c..24d7de6f44 100644 --- a/apps/cowswap-frontend/src/common/pure/ButtonSecondary/index.tsx +++ b/apps/cowswap-frontend/src/common/pure/ButtonSecondary/index.tsx @@ -1,8 +1,10 @@ import styled from 'styled-components/macro' -export const ButtonSecondary = styled.button` - background: var(--cow-color-lightBlue-opacity-90); - color: var(--cow-color-white); +import { UI } from 'common/constants/theme' + +export const ButtonSecondary = styled.button<{ padding?: string; minHeight?: string }>` + background: var(${UI.COLOR_LIGHT_BLUE_OPACITY_90}); + color: var(${UI.COLOR_LIGHT_BLUE}); font-size: 12px; font-weight: 600; border: 0; @@ -10,12 +12,12 @@ export const ButtonSecondary = styled.button` border-radius: 12px; position: relative; transition: background 0.2s ease-in-out; - min-height: 35px; - padding: 0 12px; + min-height: ${({ minHeight = '35px' }) => minHeight}; + padding: ${({ padding = '0 12px' }) => padding}; cursor: pointer; white-space: nowrap; &:hover { - background: var(--cow-color-lightBlue-opacity-80); + background: var(${UI.COLOR_LIGHT_BLUE_OPACITY_80}); } ` diff --git a/apps/cowswap-frontend/src/common/pure/CancellationModal/RequestCancellationModal.tsx b/apps/cowswap-frontend/src/common/pure/CancellationModal/RequestCancellationModal.tsx index 133d38b207..47f7520166 100644 --- a/apps/cowswap-frontend/src/common/pure/CancellationModal/RequestCancellationModal.tsx +++ b/apps/cowswap-frontend/src/common/pure/CancellationModal/RequestCancellationModal.tsx @@ -1,5 +1,6 @@ import React, { useCallback, useState } from 'react' +import { TokenAmount, ButtonPrimary } from '@cowprotocol/ui' import type { BigNumber } from '@ethersproject/bignumber' import { CurrencyAmount, NativeCurrency } from '@uniswap/sdk-core' @@ -7,14 +8,13 @@ import { ArrowRight, ArrowLeft } from 'react-feather' import { NavHashLink } from 'react-router-hash-link' import styled from 'styled-components/macro' -import { ButtonPrimary } from 'legacy/components/Button' import NotificationBanner from 'legacy/components/NotificationBanner' import { LegacyConfirmationModalContent } from 'legacy/components/TransactionConfirmationModal/LegacyConfirmationModalContent' import { LinkStyledButton } from 'legacy/theme' import { Routes } from 'common/constants/routes' +import { UI } from 'common/constants/theme' import { CancellationType } from 'common/hooks/useCancelOrder/state' -import { TokenAmount } from 'common/pure/TokenAmount' export type RequestCancellationModalProps = { summary?: string @@ -63,7 +63,7 @@ const CancellationSummary = styled.span` padding: 12px; margin: 0; border-radius: 6px; - background: ${({ theme }) => theme.grey1}; + background: var(${UI.COLOR_GREY}); line-height: 1.6; ` diff --git a/apps/cowswap-frontend/src/common/pure/CancellationModal/index.tsx b/apps/cowswap-frontend/src/common/pure/CancellationModal/index.tsx index c2782961e3..ea5d19324a 100644 --- a/apps/cowswap-frontend/src/common/pure/CancellationModal/index.tsx +++ b/apps/cowswap-frontend/src/common/pure/CancellationModal/index.tsx @@ -1,8 +1,9 @@ import { useMemo } from 'react' -import { ConfirmOperationType } from 'legacy/components/TransactionConfirmationModal' +import { shortenOrderId } from '@cowprotocol/common-utils' + import { LegacyConfirmationPendingContent } from 'legacy/components/TransactionConfirmationModal/LegacyConfirmationPendingContent' -import { shortenOrderId } from 'legacy/utils' +import { ConfirmOperationType } from 'legacy/state/types' import { CancellationModalContext } from 'common/hooks/useCancelOrder/state' import { CowModal as Modal } from 'common/pure/Modal' diff --git a/apps/cowswap-frontend/src/common/pure/ConfirmationModal/ConfirmationModal.tsx b/apps/cowswap-frontend/src/common/pure/ConfirmationModal/ConfirmationModal.tsx index 7a01bf4dc5..3e650d13bb 100644 --- a/apps/cowswap-frontend/src/common/pure/ConfirmationModal/ConfirmationModal.tsx +++ b/apps/cowswap-frontend/src/common/pure/ConfirmationModal/ConfirmationModal.tsx @@ -1,6 +1,7 @@ import { Trans } from '@lingui/macro' import styled from 'styled-components/macro' +import { UI } from 'common/constants/theme' import { ContentWrapper, Modal } from 'common/pure/Modal' import { ConfirmationModalHeader } from './ConfirmationModalHeader' @@ -10,7 +11,7 @@ import { ConfirmedButton } from '../ConfirmedButton' const ModalContentWrapper = styled(ContentWrapper)` flex: 1; padding: 1.5rem; - color: ${({ theme }) => theme.text2}; + color: var(${UI.COLOR_TEXT2}); border-radius: 1.5rem; ` @@ -20,7 +21,7 @@ const Description = styled.p` ` const Warning = styled.strong` - color: ${({ theme }) => theme.text1}; + color: var(${UI.COLOR_TEXT1}); ` export interface ConfirmationModalProps { diff --git a/apps/cowswap-frontend/src/common/pure/ConfirmationModal/ConfirmationModalHeader.tsx b/apps/cowswap-frontend/src/common/pure/ConfirmationModal/ConfirmationModalHeader.tsx index 4fca4186c4..f3a21bd1b2 100644 --- a/apps/cowswap-frontend/src/common/pure/ConfirmationModal/ConfirmationModalHeader.tsx +++ b/apps/cowswap-frontend/src/common/pure/ConfirmationModal/ConfirmationModalHeader.tsx @@ -3,6 +3,8 @@ import { ReactNode } from 'react' import { X as CloseIcon } from 'react-feather' import styled from 'styled-components/macro' +import { UI } from 'common/constants/theme' + const Container = styled.header` display: flex; width: 100%; @@ -10,7 +12,7 @@ const Container = styled.header` padding: 0 0 16px; margin: 0 0 24px; border-bottom: 1px solid ${({ theme }) => theme.grey1}; - color: ${({ theme }) => theme.text1}; + color: var(${UI.COLOR_TEXT1}); ` const Title = styled.b` @@ -30,7 +32,7 @@ const Close = styled(CloseIcon)` } > line { - stroke: ${({ theme }) => theme.text1}; + stroke: var(${UI.COLOR_TEXT1}); } ` diff --git a/apps/cowswap-frontend/src/common/pure/ConfirmationPendingContent/ConfirmationPendingContent.cosmos.tsx b/apps/cowswap-frontend/src/common/pure/ConfirmationPendingContent/ConfirmationPendingContent.cosmos.tsx index c5ff82c2ad..89f5958975 100644 --- a/apps/cowswap-frontend/src/common/pure/ConfirmationPendingContent/ConfirmationPendingContent.cosmos.tsx +++ b/apps/cowswap-frontend/src/common/pure/ConfirmationPendingContent/ConfirmationPendingContent.cosmos.tsx @@ -1,4 +1,4 @@ -import { Identicon } from 'modules/wallet' +import { Identicon } from '@cowprotocol/wallet' import { ConfirmationPendingContent } from './ConfirmationPendingContent' diff --git a/apps/cowswap-frontend/src/common/pure/ConfirmationPendingContent/styled.tsx b/apps/cowswap-frontend/src/common/pure/ConfirmationPendingContent/styled.tsx index e25f01b343..c9640e8c95 100644 --- a/apps/cowswap-frontend/src/common/pure/ConfirmationPendingContent/styled.tsx +++ b/apps/cowswap-frontend/src/common/pure/ConfirmationPendingContent/styled.tsx @@ -1,9 +1,13 @@ +import { RowBetween } from '@cowprotocol/ui' +import { ExternalLink } from '@cowprotocol/ui' + import { transparentize } from 'polished' import { Link } from 'react-router-dom' import styled, { css } from 'styled-components/macro' -import { RowBetween } from 'legacy/components/Row' -import { CloseIcon, ExternalLink } from 'legacy/theme' +import { CloseIcon } from 'legacy/theme' + +import { UI } from 'common/constants/theme' export const Wrapper = styled.div` width: 100%; @@ -32,7 +36,7 @@ export const Header = styled.div` flex-direction: row; justify-content: space-between; align-items: center; - background: ${({ theme }) => theme.bg1}; + background: var(${UI.COLOR_CONTAINER_BG_01}); position: sticky; top: 0; left: 0; @@ -105,7 +109,7 @@ export const GPModalHeader = styled(RowBetween)` left: 0; width: 100%; padding: 16px 0; - background: ${({ theme }) => theme.bg1}; + background: var(${UI.COLOR_CONTAINER_BG_01}); z-index: 20; ` @@ -144,7 +148,7 @@ export const ButtonCustom = styled.button` border-radius: 16px; min-height: 52px; border: 1px solid ${({ theme }) => theme.border2}; - color: ${({ theme }) => theme.text1}; + color: var(${UI.COLOR_TEXT1}); background: transparent; outline: 0; padding: 8px 16px; @@ -171,7 +175,7 @@ export const UpperSection = styled.div` display: flex; flex-flow: column wrap; padding: 16px 16px 32px; - background: ${({ theme }) => theme.grey1}; + background: var(${UI.COLOR_GREY}); border-radius: 16px 16px 0 0; ${({ theme }) => theme.mediaWidth.upToSmall` @@ -236,7 +240,7 @@ export const StepsIconWrapper = styled.div` height: 100%; width: 100%; padding: 18px; - stroke: ${({ theme }) => theme.text1}; + stroke: var(${UI.COLOR_TEXT1}); } @keyframes spin { @@ -294,7 +298,7 @@ export const StepsWrapper = styled.div` flex: 1 1 auto; height: 2px; border: 0; - background: ${({ theme }) => theme.text1}; + background: var(${UI.COLOR_TEXT1}); margin: auto; position: absolute; width: 100%; @@ -309,7 +313,7 @@ export const StepsWrapper = styled.div` content: ''; height: 4px; width: 100%; - background: ${({ theme }) => theme.grey1}; + background: var(${UI.COLOR_GREY}); display: block; margin: 0; animation: Shrink 1s forwards linear; diff --git a/apps/cowswap-frontend/src/common/pure/ConfirmedButton/ConfirmedButton.tsx b/apps/cowswap-frontend/src/common/pure/ConfirmedButton/ConfirmedButton.tsx index 43665d4c35..aed8a57be4 100644 --- a/apps/cowswap-frontend/src/common/pure/ConfirmedButton/ConfirmedButton.tsx +++ b/apps/cowswap-frontend/src/common/pure/ConfirmedButton/ConfirmedButton.tsx @@ -1,8 +1,10 @@ import { ChangeEventHandler, KeyboardEventHandler, ReactNode, useCallback, useState } from 'react' +import { ButtonError } from '@cowprotocol/ui' + import styled from 'styled-components/macro' -import { ButtonError } from 'legacy/components/Button' +import { UI } from 'common/constants/theme' const Container = styled.div`` const Instruction = styled.p` @@ -17,7 +19,7 @@ const Input = styled.input` padding: 10px; border-radius: 4px; background: ${({ theme }) => theme.bg3}; - color: ${({ theme }) => theme.text1}; + color: var(${UI.COLOR_TEXT1}); outline: none; font-size: 15px; diff --git a/apps/cowswap-frontend/src/common/pure/CowSwapSafeAppLink/index.tsx b/apps/cowswap-frontend/src/common/pure/CowSwapSafeAppLink/index.tsx index 973db4b64d..3b6ca0db35 100644 --- a/apps/cowswap-frontend/src/common/pure/CowSwapSafeAppLink/index.tsx +++ b/apps/cowswap-frontend/src/common/pure/CowSwapSafeAppLink/index.tsx @@ -1,4 +1,4 @@ -import { ExternalLink } from 'legacy/theme' +import { ExternalLink } from '@cowprotocol/ui' import { SAFE_COW_APP_LINK } from 'common/constants/common' diff --git a/apps/cowswap-frontend/src/common/pure/CurrencyAmountPreview/index.tsx b/apps/cowswap-frontend/src/common/pure/CurrencyAmountPreview/index.tsx index 2ad6e613c7..3d110c6844 100644 --- a/apps/cowswap-frontend/src/common/pure/CurrencyAmountPreview/index.tsx +++ b/apps/cowswap-frontend/src/common/pure/CurrencyAmountPreview/index.tsx @@ -1,3 +1,4 @@ +import { TokenAmount } from '@cowprotocol/ui' import { Currency, CurrencyAmount } from '@uniswap/sdk-core' import { Trans } from '@lingui/macro' @@ -7,7 +8,6 @@ import { PriceImpact } from 'legacy/hooks/usePriceImpact' import { CurrencySelectButton } from 'common/pure/CurrencySelectButton' import { FiatValue } from 'common/pure/FiatValue' -import { TokenAmount } from 'common/pure/TokenAmount' import * as styledEl from '../CurrencyInputPanel/styled' diff --git a/apps/cowswap-frontend/src/common/pure/CurrencyArrowSeparator/index.tsx b/apps/cowswap-frontend/src/common/pure/CurrencyArrowSeparator/index.tsx index 471fad4878..abbe36bc15 100644 --- a/apps/cowswap-frontend/src/common/pure/CurrencyArrowSeparator/index.tsx +++ b/apps/cowswap-frontend/src/common/pure/CurrencyArrowSeparator/index.tsx @@ -1,6 +1,6 @@ import React from 'react' -import loadingCowWebp from 'legacy/assets/cow-swap/cow-load.webp' +import loadingCowWebp from '@cowprotocol/assets/cow-swap/cow-load.webp' import * as styledEl from './styled' diff --git a/apps/cowswap-frontend/src/common/pure/CurrencyArrowSeparator/styled.tsx b/apps/cowswap-frontend/src/common/pure/CurrencyArrowSeparator/styled.tsx index 580d59cca5..edd284c7c9 100644 --- a/apps/cowswap-frontend/src/common/pure/CurrencyArrowSeparator/styled.tsx +++ b/apps/cowswap-frontend/src/common/pure/CurrencyArrowSeparator/styled.tsx @@ -1,6 +1,8 @@ import { ArrowDown } from 'react-feather' import styled, { css } from 'styled-components/macro' +import { UI } from 'common/constants/theme' + import { loadingAnimationMixin } from './style-mixins' export const Box = styled.div<{ withRecipient: boolean; isCollapsed: boolean; hasSeparatorLine?: boolean }>` @@ -42,7 +44,7 @@ export const LoadingWrapper = styled.div<{ isLoading: boolean; border?: boolean transition: transform 0.25s; border: ${({ border, theme }) => (border ? `1px solid ${theme.grey1}` : '0')}; box-shadow: 0px 0px 0px 3px ${({ theme }) => theme.bg1}; - background: ${({ theme }) => theme.grey1}; + background: var(${UI.COLOR_GREY}); border-radius: 8px; width: var(--size); margin: auto; @@ -57,7 +59,7 @@ export const LoadingWrapper = styled.div<{ isLoading: boolean; border?: boolean export const ArrowDownIcon = styled(ArrowDown)` display: block; margin: auto; - stroke: ${({ theme }) => theme.text1}; + stroke: var(${UI.COLOR_TEXT1}); stroke-width: 3px; padding: 0; height: 100%; diff --git a/apps/cowswap-frontend/src/common/pure/CurrencyInputPanel/CurrencyInputPanel.tsx b/apps/cowswap-frontend/src/common/pure/CurrencyInputPanel/CurrencyInputPanel.tsx index 74e5d38d3c..f38f8fafcb 100644 --- a/apps/cowswap-frontend/src/common/pure/CurrencyInputPanel/CurrencyInputPanel.tsx +++ b/apps/cowswap-frontend/src/common/pure/CurrencyInputPanel/CurrencyInputPanel.tsx @@ -1,24 +1,24 @@ import React, { useCallback, useEffect, useState } from 'react' +import { setMaxSellTokensAnalytics } from '@cowprotocol/analytics' +import { formatInputAmount } from '@cowprotocol/common-utils' import { SupportedChainId } from '@cowprotocol/cow-sdk' +import { TokenAmount } from '@cowprotocol/ui' +import { MouseoverTooltip } from '@cowprotocol/ui' import { Currency, CurrencyAmount } from '@uniswap/sdk-core' import { Trans } from '@lingui/macro' -import { setMaxSellTokensAnalytics } from 'legacy/components/analytics' import CurrencySearchModal from 'legacy/components/SearchModal/CurrencySearchModal' -import { MouseoverTooltip } from 'legacy/components/Tooltip' import { BalanceAndSubsidy } from 'legacy/hooks/useCowBalanceAndSubsidy' import { PriceImpact } from 'legacy/hooks/usePriceImpact' -import { Field } from 'legacy/state/swap/actions' +import { Field } from 'legacy/state/types' import { ReceiveAmount } from 'modules/swap/pure/ReceiveAmount' import { CurrencyInfo } from 'common/pure/CurrencyInputPanel/types' import { CurrencySelectButton } from 'common/pure/CurrencySelectButton' import { FiatValue } from 'common/pure/FiatValue' -import { TokenAmount } from 'common/pure/TokenAmount' -import { formatInputAmount } from 'utils/amountFormat' import * as styledEl from './styled' diff --git a/apps/cowswap-frontend/src/common/pure/CurrencyInputPanel/defaultCurrencyInputProps.ts b/apps/cowswap-frontend/src/common/pure/CurrencyInputPanel/defaultCurrencyInputProps.ts index 8f3cc64b58..4729bd4f10 100644 --- a/apps/cowswap-frontend/src/common/pure/CurrencyInputPanel/defaultCurrencyInputProps.ts +++ b/apps/cowswap-frontend/src/common/pure/CurrencyInputPanel/defaultCurrencyInputProps.ts @@ -1,9 +1,9 @@ +import { COW } from '@cowprotocol/common-const' import { SupportedChainId } from '@cowprotocol/cow-sdk' import { CurrencyAmount, Percent } from '@uniswap/sdk-core' -import { COW } from 'legacy/constants/tokens' import { PriceImpact } from 'legacy/hooks/usePriceImpact' -import { Field } from 'legacy/state/swap/actions' +import { Field } from 'legacy/state/types' import { CurrencyInputPanelProps } from 'common/pure/CurrencyInputPanel/index' diff --git a/apps/cowswap-frontend/src/common/pure/CurrencyInputPanel/index.cosmos.tsx b/apps/cowswap-frontend/src/common/pure/CurrencyInputPanel/index.cosmos.tsx index bc90130c79..fbe8c02dd5 100644 --- a/apps/cowswap-frontend/src/common/pure/CurrencyInputPanel/index.cosmos.tsx +++ b/apps/cowswap-frontend/src/common/pure/CurrencyInputPanel/index.cosmos.tsx @@ -1,12 +1,12 @@ +import { COW } from '@cowprotocol/common-const' import { SupportedChainId } from '@cowprotocol/cow-sdk' import { CurrencyAmount, Percent } from '@uniswap/sdk-core' import { DemoContainer } from 'cosmos.decorator' import { useSelect, useValue } from 'react-cosmos/client' -import { COW } from 'legacy/constants/tokens' import { PriceImpact } from 'legacy/hooks/usePriceImpact' -import { Field } from 'legacy/state/swap/actions' +import { Field } from 'legacy/state/types' import { CurrencyInputPanel, CurrencyInputPanelProps } from './CurrencyInputPanel' import { defaultCurrencyInputPanelProps } from './defaultCurrencyInputProps' @@ -27,10 +27,7 @@ function useCustomProps(): Partial { options: [Field.INPUT, Field.OUTPUT], defaultValue: Field.INPUT, }) - const [priceImpactError] = useSelect('priceImpactParams.error', { - options: ['fetch-quote-error', 'insufficient-liquidity', 'fee-exceeds-sell-amount'], - defaultValue: 'fetch-quote-error', - }) + const [priceImpactRaw] = useValue('priceImpactParams.priceImpact', { defaultValue: 2 }) const balance = CurrencyAmount.fromRawAmount(currency, balanceAmountRaw * 10 ** 18) diff --git a/apps/cowswap-frontend/src/common/pure/CurrencyInputPanel/styled.tsx b/apps/cowswap-frontend/src/common/pure/CurrencyInputPanel/styled.tsx index 461d57261e..0df08c487e 100644 --- a/apps/cowswap-frontend/src/common/pure/CurrencyInputPanel/styled.tsx +++ b/apps/cowswap-frontend/src/common/pure/CurrencyInputPanel/styled.tsx @@ -1,10 +1,11 @@ +import { TokenAmount, loadingOpacityMixin } from '@cowprotocol/ui' + import { transparentize } from 'polished' import styled from 'styled-components/macro' -import { loadingOpacityMixin } from 'legacy/components/Loader/styled' import Input from 'legacy/components/NumericalInput' -import { TokenAmount } from 'common/pure/TokenAmount' +import { UI } from 'common/constants/theme' export const OuterWrapper = styled.div` max-width: 100%; @@ -72,7 +73,7 @@ export const NumericalInput = styled(Input)<{ $loading: boolean }>` background: none; font-size: 28px; font-weight: 500; - color: ${({ theme }) => theme.text1}; + color: var(${UI.COLOR_TEXT1}); &::placeholder { color: ${({ theme }) => transparentize(0.3, theme.text1)}; @@ -88,7 +89,7 @@ export const NumericalInput = styled(Input)<{ $loading: boolean }>` export const TokenAmountStyled = styled(TokenAmount)` font-size: 28px; font-weight: 500; - color: ${({ theme }) => theme.text1}; + color: var(${UI.COLOR_TEXT1}); ${({ theme }) => theme.mediaWidth.upToSmall` font-size: 26px; diff --git a/apps/cowswap-frontend/src/common/pure/CurrencyInputPanel/types.ts b/apps/cowswap-frontend/src/common/pure/CurrencyInputPanel/types.ts index 41e89acbd1..1f4380dddd 100644 --- a/apps/cowswap-frontend/src/common/pure/CurrencyInputPanel/types.ts +++ b/apps/cowswap-frontend/src/common/pure/CurrencyInputPanel/types.ts @@ -1,6 +1,6 @@ import { Currency, CurrencyAmount } from '@uniswap/sdk-core' -import { Field } from 'legacy/state/swap/actions' +import { Field } from 'legacy/state/types' import { ReceiveAmountInfo } from 'modules/swap/helpers/tradeReceiveAmount' diff --git a/apps/cowswap-frontend/src/common/pure/CurrencyLogo/hooks/useCurrencyLogoURIs.ts b/apps/cowswap-frontend/src/common/pure/CurrencyLogo/hooks/useCurrencyLogoURIs.ts index 5bd9aa3aa5..17040c8aae 100644 --- a/apps/cowswap-frontend/src/common/pure/CurrencyLogo/hooks/useCurrencyLogoURIs.ts +++ b/apps/cowswap-frontend/src/common/pure/CurrencyLogo/hooks/useCurrencyLogoURIs.ts @@ -1,13 +1,11 @@ +import XDaiLogo from '@cowprotocol/assets/cow-swap/xdai.png' +import EthereumLogo from '@cowprotocol/assets/images/ethereum-logo.png' +import { NATIVE_CURRENCY_BUY_ADDRESS, ADDRESS_IMAGE_OVERRIDE } from '@cowprotocol/common-const' +import { uriToHttp } from '@cowprotocol/common-utils' import { SupportedChainId } from '@cowprotocol/cow-sdk' import { Currency } from '@uniswap/sdk-core' -import XDaiLogo from 'legacy/assets/cow-swap/xdai.png' -import EthereumLogo from 'legacy/assets/images/ethereum-logo.png' -import { NATIVE_CURRENCY_BUY_ADDRESS } from 'legacy/constants' -import { ADDRESS_IMAGE_OVERRIDE } from 'legacy/constants/tokens' - import { useProxyTokenLogo } from 'api/proxy' -import uriToHttp from 'lib/utils/uriToHttp' type Network = 'ethereum' | 'xdai' diff --git a/apps/cowswap-frontend/src/common/pure/CurrencyLogo/index.tsx b/apps/cowswap-frontend/src/common/pure/CurrencyLogo/index.tsx index 55a83b19d6..e4d58c4152 100644 --- a/apps/cowswap-frontend/src/common/pure/CurrencyLogo/index.tsx +++ b/apps/cowswap-frontend/src/common/pure/CurrencyLogo/index.tsx @@ -4,7 +4,7 @@ import { Currency } from '@uniswap/sdk-core' import styled from 'styled-components/macro' -import Logo from 'legacy/components/Logo' +import Logo from 'legacy/components/Loader/Logo' import useCurrencyLogoURIs from './hooks/useCurrencyLogoURIs' diff --git a/apps/cowswap-frontend/src/common/pure/CurrencySelectButton/index.cosmos.tsx b/apps/cowswap-frontend/src/common/pure/CurrencySelectButton/index.cosmos.tsx index 2361ebdedd..738139d32a 100644 --- a/apps/cowswap-frontend/src/common/pure/CurrencySelectButton/index.cosmos.tsx +++ b/apps/cowswap-frontend/src/common/pure/CurrencySelectButton/index.cosmos.tsx @@ -1,9 +1,8 @@ +import { COW, GNO } from '@cowprotocol/common-const' import { SupportedChainId } from '@cowprotocol/cow-sdk' import { useSelect } from 'react-cosmos/client' -import { COW, GNO } from 'legacy/constants/tokens' - import { CurrencySelectButton, CurrencySelectButtonProps } from 'common/pure/CurrencySelectButton/index' const COW_TOKEN = COW[SupportedChainId.MAINNET] diff --git a/apps/cowswap-frontend/src/common/pure/CurrencySelectButton/index.tsx b/apps/cowswap-frontend/src/common/pure/CurrencySelectButton/index.tsx index 444bac31ad..aba96807d2 100644 --- a/apps/cowswap-frontend/src/common/pure/CurrencySelectButton/index.tsx +++ b/apps/cowswap-frontend/src/common/pure/CurrencySelectButton/index.tsx @@ -1,10 +1,10 @@ +import { TokenSymbol } from '@cowprotocol/ui' import { Currency } from '@uniswap/sdk-core' import { Trans } from '@lingui/macro' import { Nullish } from 'types' import { CurrencyLogo } from 'common/pure/CurrencyLogo' -import { TokenSymbol } from 'common/pure/TokenSymbol' import * as styledEl from './styled' diff --git a/apps/cowswap-frontend/src/common/pure/CurrencySelectButton/styled.tsx b/apps/cowswap-frontend/src/common/pure/CurrencySelectButton/styled.tsx index d6017e31d6..f03be68b0a 100644 --- a/apps/cowswap-frontend/src/common/pure/CurrencySelectButton/styled.tsx +++ b/apps/cowswap-frontend/src/common/pure/CurrencySelectButton/styled.tsx @@ -1,8 +1,8 @@ +import { ReactComponent as DropDown } from '@cowprotocol/assets/images/dropdown.svg' + import { lighten, transparentize } from 'polished' import styled from 'styled-components/macro' -import { ReactComponent as DropDown } from 'legacy/assets/images/dropdown.svg' - export const CurrencySelectWrapper = styled.button<{ isLoading: boolean; $stubbed: boolean; readonlyMode: boolean }>` display: flex; justify-content: space-between; diff --git a/apps/cowswap-frontend/src/common/pure/ExecutedSummary/styled.ts b/apps/cowswap-frontend/src/common/pure/ExecutedSummary/styled.ts index f0e05b64de..af3fa38057 100644 --- a/apps/cowswap-frontend/src/common/pure/ExecutedSummary/styled.ts +++ b/apps/cowswap-frontend/src/common/pure/ExecutedSummary/styled.ts @@ -1,8 +1,6 @@ -import styled from 'styled-components/macro' - -import { TokenAmount } from 'common/pure/TokenAmount' +import { TokenAmount, FiatAmount } from '@cowprotocol/ui' -import { FiatAmount } from '../FiatAmount' +import styled from 'styled-components/macro' export const SummaryWrapper = styled.div` font-size: 1rem; diff --git a/apps/cowswap-frontend/src/common/pure/ExecutionPrice/hooks/useExecutionPriceFiat.ts b/apps/cowswap-frontend/src/common/pure/ExecutionPrice/hooks/useExecutionPriceFiat.ts index 9cf9119ffa..a5b66c3f85 100644 --- a/apps/cowswap-frontend/src/common/pure/ExecutionPrice/hooks/useExecutionPriceFiat.ts +++ b/apps/cowswap-frontend/src/common/pure/ExecutionPrice/hooks/useExecutionPriceFiat.ts @@ -1,9 +1,8 @@ +import { rawToTokenAmount } from '@cowprotocol/common-utils' import { Currency, CurrencyAmount, Price } from '@uniswap/sdk-core' import { useUsdAmount } from 'modules/usdAmount' -import { rawToTokenAmount } from 'utils/rawToTokenAmount' - function getPriceQuoteAmount(price: Price, isInverted: boolean): CurrencyAmount { const executionPrice = isInverted ? price.invert() : price diff --git a/apps/cowswap-frontend/src/common/pure/ExecutionPrice/index.tsx b/apps/cowswap-frontend/src/common/pure/ExecutionPrice/index.tsx index d083c5cddf..b3ff29c995 100644 --- a/apps/cowswap-frontend/src/common/pure/ExecutionPrice/index.tsx +++ b/apps/cowswap-frontend/src/common/pure/ExecutionPrice/index.tsx @@ -1,9 +1,7 @@ +import { tryParseCurrencyAmount } from '@cowprotocol/common-utils' +import { FiatAmount, TokenAmount } from '@cowprotocol/ui' import { Currency, Price } from '@uniswap/sdk-core' -import { FiatAmount } from 'common/pure/FiatAmount' -import { TokenAmount } from 'common/pure/TokenAmount' -import tryParseCurrencyAmount from 'lib/utils/tryParseCurrencyAmount' - import { useExecutionPriceFiat } from './hooks/useExecutionPriceFiat' export interface ExecutionPriceProps { diff --git a/apps/cowswap-frontend/src/common/pure/ExpertModeModal/index.tsx b/apps/cowswap-frontend/src/common/pure/ExpertModeModal/index.tsx index 4c122fd84f..9f4bcfca3a 100644 --- a/apps/cowswap-frontend/src/common/pure/ExpertModeModal/index.tsx +++ b/apps/cowswap-frontend/src/common/pure/ExpertModeModal/index.tsx @@ -2,6 +2,7 @@ import { Trans } from '@lingui/macro' import { X } from 'react-feather' import styled from 'styled-components/macro' +import { UI } from 'common/constants/theme' import { Modal } from 'common/pure/Modal' import { ConfirmedButton } from '../ConfirmedButton' @@ -12,8 +13,8 @@ const ModalContentWrapper = styled.div` align-items: center; justify-content: center; padding: 24px; - color: ${({ theme }) => theme.text2}; - background-color: ${({ theme }) => theme.bg1}; + color: var(${UI.COLOR_TEXT2}); + background-color: var(${UI.COLOR_CONTAINER_BG_01}); border-radius: 24px; > p { @@ -22,7 +23,7 @@ const ModalContentWrapper = styled.div` } > p > strong { - color: ${({ theme }) => theme.text1}; + color: var(${UI.COLOR_TEXT1}); } ` @@ -33,7 +34,7 @@ const Header = styled.div` padding: 0 0 16px; margin: 0 0 24px; border-bottom: 1px solid ${({ theme }) => theme.grey1}; - color: ${({ theme }) => theme.text1}; + color: var(${UI.COLOR_TEXT1}); > b { font-size: 21px; @@ -53,7 +54,7 @@ const StyledCloseIcon = styled(X)` } > line { - stroke: ${({ theme }) => theme.text1}; + stroke: var(${UI.COLOR_TEXT1}); } ` diff --git a/apps/cowswap-frontend/src/common/pure/FiatValue/index.tsx b/apps/cowswap-frontend/src/common/pure/FiatValue/index.tsx index c469e46736..85a2691256 100644 --- a/apps/cowswap-frontend/src/common/pure/FiatValue/index.tsx +++ b/apps/cowswap-frontend/src/common/pure/FiatValue/index.tsx @@ -1,3 +1,4 @@ +import { FiatAmount } from '@cowprotocol/ui' import { Currency, CurrencyAmount } from '@uniswap/sdk-core' import styled from 'styled-components/macro' @@ -5,14 +6,14 @@ import { Nullish } from 'types' import { PriceImpact } from 'legacy/hooks/usePriceImpact' -import { FiatAmount } from 'common/pure/FiatAmount' +import { UI } from 'common/constants/theme' import { PriceImpactIndicator } from '../PriceImpactIndicator' const FiatValueWrapper = styled.div<{ hasValue$: boolean }>` display: inline-block; font-size: 14px; - color: ${({ theme, hasValue$ }) => (hasValue$ ? theme.text1 : theme.text4)}; + color: ${({ theme, hasValue$ }) => (hasValue$ ? `var(${UI.COLOR_TEXT1})` : theme.text4)}; ` export function FiatValue({ diff --git a/apps/cowswap-frontend/src/common/pure/HelpCircle/index.tsx b/apps/cowswap-frontend/src/common/pure/HelpCircle/index.tsx index abcdf92f63..a6a9c1722c 100644 --- a/apps/cowswap-frontend/src/common/pure/HelpCircle/index.tsx +++ b/apps/cowswap-frontend/src/common/pure/HelpCircle/index.tsx @@ -1,7 +1,8 @@ +import { questionIcon } from '@cowprotocol/assets/cow-swap/question' + import SVG from 'react-inlinesvg' import styled from 'styled-components/macro' -import { questionIcon } from 'legacy/assets/cow-swap/question' import { useIsDarkMode } from 'legacy/state/user/hooks' const HelpCircleWrapper = styled.div` diff --git a/apps/cowswap-frontend/src/common/pure/Icon/index.cosmos.tsx b/apps/cowswap-frontend/src/common/pure/Icon/index.cosmos.tsx new file mode 100644 index 0000000000..85c6f61220 --- /dev/null +++ b/apps/cowswap-frontend/src/common/pure/Icon/index.cosmos.tsx @@ -0,0 +1,26 @@ +import styled from 'styled-components/macro'; + +import { UI } from 'common/constants/theme' + +import { Icon, IconType } from './index'; + +const Wrapper = styled.div` + width: 400px; + height: 400px; + background: var(${UI.COLOR_CONTAINER_BG_01}); + border-radius: var(${UI.BORDER_RADIUS_NORMAL}); + display: flex; + align-items: center; + justify-content: center; + margin: 100px; +`; + +const IconFixtures = { + 'icon ALERT / default size': ( + + + + ), +}; + +export default IconFixtures; diff --git a/apps/cowswap-frontend/src/common/pure/Icon/index.tsx b/apps/cowswap-frontend/src/common/pure/Icon/index.tsx new file mode 100644 index 0000000000..88a1c94d73 --- /dev/null +++ b/apps/cowswap-frontend/src/common/pure/Icon/index.tsx @@ -0,0 +1,80 @@ +import iconInformation from '@cowprotocol/assets/cow-swap/alert-circle.svg' +import iconAlert from '@cowprotocol/assets/cow-swap/alert.svg' +import iconDanger from '@cowprotocol/assets/cow-swap/alert.svg' +import iconSuccess from '@cowprotocol/assets/cow-swap/check.svg' + +import SVG from 'react-inlinesvg' +import styled from 'styled-components/macro' + +import { UI } from 'common/constants/theme' + +export enum IconType { + ALERT = 'ALERT', + INFORMATION = 'INFORMATION', + DANGER = 'DANGER', + SUCCESS = 'SUCCESS', +} + +const IconTypeMap: Record = { + [IconType.ALERT]: iconAlert, + [IconType.INFORMATION]: iconInformation, + [IconType.DANGER]: iconDanger, + [IconType.SUCCESS]: iconSuccess, +} + +interface IconProps { + image: keyof typeof IconType + size?: number + bgColor?: UI | string + color?: UI + description?: string + padding?: string + borderRadius?: string +} + +const Wrapper = styled.div>` + display: flex; + position: relative; + align-items: center; + justify-content: center; + width: ${({ size }) => size}px; + height: ${({ size }) => size}px; + min-width: ${({ size }) => size}px; + min-height: ${({ size }) => size}px; + border-radius: ${({ borderRadius }) => borderRadius}; + background-color: ${({ bgColor }) => (bgColor ? `var(${bgColor})` : 'transparent')}; + padding: ${({ padding }) => padding}; + + > svg { + object-fit: contain; + z-index: 2; + position: relative; + width: 100%; + height: 100%; + display: flex; + align-items: center; + justify-content: center; + } + + > svg > path { + fill: ${({ color = UI.COLOR_TEXT1 }) => `var(${color})`}; + } +` + +export function Icon({ + image, + size = 16, + bgColor, + color, + description, + borderRadius = '0', + padding = '0 3px 0 0', +}: IconProps) { + const svgPath = IconTypeMap[image] + + return ( + + + + ) +} diff --git a/apps/cowswap-frontend/src/common/pure/IconSpinner/index.cosmos.tsx b/apps/cowswap-frontend/src/common/pure/IconSpinner/index.cosmos.tsx new file mode 100644 index 0000000000..12ec959113 --- /dev/null +++ b/apps/cowswap-frontend/src/common/pure/IconSpinner/index.cosmos.tsx @@ -0,0 +1,47 @@ +import styled from 'styled-components/macro'; + +import { MOCK_TOKEN, IMAGE_ACCOUNT } from 'common/constants/cosmos'; +import { UI } from 'common/constants/theme' + +import { IconSpinner} from './index'; + +const Wrapper = styled.div` + width: 400px; + height: 400px; + background: var(${UI.COLOR_CONTAINER_BG_01}); + border-radius: var(${UI.BORDER_RADIUS_NORMAL}); + display: flex; + align-items: center; + justify-content: center; + margin: 100px; +`; + +const SpinnerFixtures = { + 'token image / default size': ( + + + + ), + 'token image / custom size': ( + + + + ), + 'token image / custom size + spinnerWidth': ( + + + + ), + 'regular image / custom size': ( + + + + ), + 'no children': ( + + + + ), +}; + +export default SpinnerFixtures; diff --git a/apps/cowswap-frontend/src/common/pure/IconSpinner/index.tsx b/apps/cowswap-frontend/src/common/pure/IconSpinner/index.tsx new file mode 100644 index 0000000000..a9b678d3bb --- /dev/null +++ b/apps/cowswap-frontend/src/common/pure/IconSpinner/index.tsx @@ -0,0 +1,91 @@ +import { Currency } from '@uniswap/sdk-core' + +import styled from 'styled-components/macro' + +import { UI } from 'common/constants/theme' +import { CurrencyLogo } from 'common/pure/CurrencyLogo' + +interface IconSpinnerProps { + currency?: Currency | null + image?: string + size?: number + children?: React.ReactNode + bgColor?: UI + spinnerWidth?: number +} + +const Wrapper = styled.div<{ size: number; spinnerWidth: number; bgColor: UI }>` + --bgColor: ${({ bgColor }) => `var(${bgColor})`}; + display: flex; + position: relative; + align-items: center; + justify-content: center; + width: ${({ size }) => size}px; + height: ${({ size }) => size}px; + min-width: ${({ size }) => size}px; + min-height: ${({ size }) => size}px; + border-radius: ${({ size }) => size}px; + + &:before { + content: ""; + position: absolute; + top: calc(-1 * ${({ spinnerWidth }) => spinnerWidth}px); + left: calc(-1 * ${({ spinnerWidth }) => spinnerWidth}px); + width: calc(100% + 2 * ${({ spinnerWidth }) => spinnerWidth}px); + height: calc(100% + 2 * ${({ spinnerWidth }) => spinnerWidth}px); + border-radius: 50%; + background: conic-gradient(from 0deg at 50% 50%, var(${UI.COLOR_BORDER}) 0%, var(${UI.COLOR_LINK}) 100%); + animation: spin 2s linear infinite; + z-index: 1; + } + + > img, + > svg, + > span { + object-fit: contain; + z-index: 2; + position: relative; + border: ${({ spinnerWidth }) => spinnerWidth}px solid var(${UI.COLOR_CONTAINER_BG_01}); + border-radius: ${({ size }) => size}px; + background-color: var(--bgColor); + width: 100%; + height: 100%; + display: flex; + align-items: center; + justify-content: center; + } + + @keyframes spin { + from { + transform: rotate(0deg); + } + to { + transform: rotate(360deg); + } + } +` + +export function IconSpinner({ + currency, + image, + size = 24, + children, + bgColor = UI.COLOR_CONTAINER_BG_01, + spinnerWidth = 2 +}: IconSpinnerProps) { + + return ( + + {(() => { + if (currency) { + return + } else if (image) { + return Spinning icon + } else if (children) { + return {children} + } + return + })()} + + ) +} diff --git a/apps/cowswap-frontend/src/common/pure/InlineBanner/banners.tsx b/apps/cowswap-frontend/src/common/pure/InlineBanner/banners.tsx index dff983b59e..0cf8c5c066 100644 --- a/apps/cowswap-frontend/src/common/pure/InlineBanner/banners.tsx +++ b/apps/cowswap-frontend/src/common/pure/InlineBanner/banners.tsx @@ -1,16 +1,21 @@ +import { TokenAmount } from '@cowprotocol/ui' import { Currency, CurrencyAmount, Percent } from '@uniswap/sdk-core' import { Nullish } from 'types' -import { TokenAmount } from 'common/pure/TokenAmount' - +import { ButtonSecondary } from '../ButtonSecondary' import { CowSwapSafeAppLink } from '../CowSwapSafeAppLink' -import { InlineBanner } from './index' +import { InlineBanner, InlineBannerProps } from './index' + +export enum BannerOrientation { + Horizontal = 'horizontal', + Vertical = 'vertical', +} export function BundleTxApprovalBanner() { return ( - + Token approval bundling

For your convenience, token approval and order placement will be bundled into a single transaction, streamlining @@ -27,7 +32,7 @@ export type BundleTxWrapBannerProps = { export function BundleTxWrapBanner({ nativeCurrencySymbol, wrappedCurrencySymbol }: BundleTxWrapBannerProps) { return ( - + Token wrapping bundling

For your convenience, CoW Swap will bundle all the necessary actions for this trade into a single transaction. @@ -49,7 +54,7 @@ export function BundleTxSafeWcBanner({ nativeCurrencySymbol, supportsWrapping }: const supportsWrappingText = supportsWrapping ? `${nativeCurrencySymbol} wrapping, ` : '' return ( - + Use Safe web app

Use the Safe web app for streamlined trading: {supportsWrappingText}token approval and orders bundled in one go! @@ -82,3 +87,37 @@ export function SmallVolumeWarningBanner({ feePercentage, feeAmount }: SmallVolu ) } + +type CustomRecipientBannerProps = InlineBannerProps & { onDismiss?: () => void } + +export function CustomRecipientWarningBanner({ + bannerType, + borderRadius, + orientation, + iconSize = 21, + iconPadding = '0', + padding = '10px 16px', + onDismiss, +}: CustomRecipientBannerProps) { + const handleDismiss = () => onDismiss?.() + + return ( + +

+ Caution: Order recipient address differs from order owner! +

+ {onDismiss && ( + + Dismiss + + )} +
+ ) +} diff --git a/apps/cowswap-frontend/src/common/pure/InlineBanner/index.cosmos.tsx b/apps/cowswap-frontend/src/common/pure/InlineBanner/index.cosmos.tsx index f1ea3565a3..76693c91e5 100644 --- a/apps/cowswap-frontend/src/common/pure/InlineBanner/index.cosmos.tsx +++ b/apps/cowswap-frontend/src/common/pure/InlineBanner/index.cosmos.tsx @@ -12,14 +12,14 @@ const Fixtures = { ), alert: ( - - This is an alert banner (explicitly passed type). + + This is an alert banner (explicitly passed bannerType). ), information: ( - + Token approval bundling

For your convenience, token approval and order placement will be bundled into a single transaction, @@ -30,14 +30,14 @@ const Fixtures = { ), success: ( - + Operation completed successfully! ), danger: ( - + Something went wrong! Please try again. diff --git a/apps/cowswap-frontend/src/common/pure/InlineBanner/index.tsx b/apps/cowswap-frontend/src/common/pure/InlineBanner/index.tsx index 64bc0f1cc4..816b5e2f4d 100644 --- a/apps/cowswap-frontend/src/common/pure/InlineBanner/index.tsx +++ b/apps/cowswap-frontend/src/common/pure/InlineBanner/index.tsx @@ -1,55 +1,74 @@ import { ReactNode } from 'react' -import { lighten, darken, transparentize } from 'polished' -import SVG from 'react-inlinesvg' -import styled, { useTheme } from 'styled-components/macro' // import useTheme +import styled from 'styled-components/macro' -import iconInformation from 'legacy/assets/cow-swap/alert-circle.svg' -import iconAlert from 'legacy/assets/cow-swap/alert.svg' -import iconDanger from 'legacy/assets/cow-swap/alert.svg' -import iconSuccess from 'legacy/assets/cow-swap/check.svg' +import { UI } from 'common/constants/theme' +import { Icon, IconType } from 'common/pure/Icon' +import { BannerOrientation } from 'common/pure/InlineBanner/banners' -type BannerType = 'alert' | 'information' | 'success' | 'danger' | 'savings' +export type BannerType = 'alert' | 'information' | 'success' | 'danger' | 'savings' -interface BannerConfig { - colorKey: Exclude - icon?: string +interface ColorEnums { + icon?: IconType iconText?: string + color: UI + bg: string + text: string } -const BANNER_CONFIG: Record = { +const colorEnumsMap: Record = { alert: { - icon: iconAlert, - colorKey: 'alert', + icon: IconType.ALERT, + color: UI.COLOR_ALERT, + bg: UI.COLOR_ALERT_BG, + text: UI.COLOR_ALERT_TEXT, }, information: { - icon: iconInformation, - colorKey: 'information', + icon: IconType.INFORMATION, + color: UI.COLOR_INFORMATION, + bg: UI.COLOR_INFORMATION_BG, + text: UI.COLOR_INFORMATION_TEXT, }, success: { - icon: iconSuccess, - colorKey: 'success', + icon: IconType.SUCCESS, + color: UI.COLOR_SUCCESS, + bg: UI.COLOR_SUCCESS_BG, + text: UI.COLOR_SUCCESS_TEXT, + }, + danger: { + icon: IconType.DANGER, + color: UI.COLOR_DANGER, + bg: UI.COLOR_DANGER_BG, + text: UI.COLOR_DANGER_TEXT, }, savings: { iconText: '💸', - colorKey: 'success', - }, - danger: { - icon: iconDanger, - colorKey: 'danger', + color: UI.COLOR_SUCCESS, + bg: UI.COLOR_SUCCESS_BG, + text: UI.COLOR_SUCCESS_TEXT, }, } -const Wrapper = styled.span<{ color: string }>` +function getColorEnums(bannerType: BannerType): ColorEnums { + return colorEnumsMap[bannerType] || colorEnumsMap.alert +} + +const Wrapper = styled.span<{ + colorEnums: ColorEnums + borderRadius?: string + orientation?: BannerOrientation + iconSize?: number + padding?: string +}>` display: flex; align-items: center; justify-content: center; - background: ${({ theme, color }) => (theme.darkMode ? transparentize(0.9, color) : transparentize(0.85, color))}; - color: ${({ theme, color }) => (theme.darkMode ? lighten(0.1, color) : darken(0.2, color))}; + background: ${({ colorEnums }) => `var(${colorEnums.bg})`}; + color: ${({ colorEnums }) => `var(${colorEnums.text})`}; gap: 24px 10px; - border-radius: 16px; + border-radius: ${({ borderRadius = '16px' }) => borderRadius}; margin: auto; - padding: 16px; + padding: ${({ padding = '16px' }) => padding}; font-size: 14px; font-weight: 400; line-height: 1.2; @@ -59,29 +78,10 @@ const Wrapper = styled.span<{ color: string }>` display: flex; justify-content: center; align-items: center; - flex-flow: column wrap; + flex-flow: ${({ orientation = BannerOrientation.Vertical }) => + orientation === BannerOrientation.Horizontal ? 'row' : 'column wrap'}; gap: 10px; width: 100%; - } - - > span > svg { - --size: 32px; - display: block; - min-width: var(--size); - min-height: var(--size); - width: var(--size); - height: var(--size); - object-fit: contain; - stroke: none !important; - } - - > span > svg > path { - fill: ${({ color }) => color}; - } - - > span { - display: flex; - flex-flow: row wrap; ${({ theme }) => theme.mediaWidth.upToSmall` flex-flow: column wrap; @@ -93,7 +93,7 @@ const Wrapper = styled.span<{ color: string }>` display: flex; align-items: center; gap: 6px; - color: ${({ theme, color }) => (theme.darkMode ? lighten(0.2, color) : darken(0.2, color))}; + color: ${({ colorEnums }) => `var(${colorEnums.text})`}; } > span > p { @@ -101,7 +101,8 @@ const Wrapper = styled.span<{ color: string }>` margin: auto; padding: 0; width: 100%; - text-align: center; + text-align: ${({ orientation = BannerOrientation.Vertical }) => + orientation === BannerOrientation.Horizontal ? 'left' : 'center'}; } > span > i { @@ -115,19 +116,46 @@ export type InlineBannerProps = { children?: ReactNode className?: string hideIcon?: boolean - type?: BannerType + bannerType?: BannerType + borderRadius?: string + orientation?: BannerOrientation + iconSize?: number + iconPadding?: string + padding?: string } -export function InlineBanner({ children, className, hideIcon, type = 'alert' }: InlineBannerProps) { - const theme = useTheme() - const config = BANNER_CONFIG[type] - const color = theme[config.colorKey] +export function InlineBanner({ + children, + className, + hideIcon, + bannerType = 'alert', + borderRadius, + orientation, + iconSize, + iconPadding, + padding, +}: InlineBannerProps) { + const colorEnums = getColorEnums(bannerType) return ( - + - {!hideIcon && config.icon && } - {!hideIcon && config.iconText && {config.iconText}} + {!hideIcon && colorEnums.icon && ( + + )} + {!hideIcon && colorEnums.iconText && {colorEnums.iconText}} {children} diff --git a/apps/cowswap-frontend/src/common/pure/Modal/index.cosmos.tsx b/apps/cowswap-frontend/src/common/pure/Modal/index.cosmos.tsx new file mode 100644 index 0000000000..f07e58e4a5 --- /dev/null +++ b/apps/cowswap-frontend/src/common/pure/Modal/index.cosmos.tsx @@ -0,0 +1,46 @@ +import styled from 'styled-components/macro' + +import { CowModal, Modal } from './index' + +const Wrapper = styled.div` + width: 100vw; + height: 100vh; +` + +const ModalFixtures = { + 'default modal': ( + + console.log('Dismissed')}> + Default modal content here + + + ), + 'modal with minHeight and maxHeight': ( + + console.log('Dismissed')} minHeight={50} maxHeight={80}> + Modal with minHeight and maxHeight + + + ), + 'cow modal': ( + + console.log('Cow Modal Dismissed')} maxWidth={400}> + Cow Modal Content + + + ), + 'cow modal with background color': ( + + console.log('Cow Modal Dismissed')} + maxWidth={400} + backgroundColor="pink" + > + Cow Modal with Pink Background + + + ), +} + +export default ModalFixtures diff --git a/apps/cowswap-frontend/src/common/pure/Modal/index.tsx b/apps/cowswap-frontend/src/common/pure/Modal/index.tsx index b0aec21d42..bc01d75991 100644 --- a/apps/cowswap-frontend/src/common/pure/Modal/index.tsx +++ b/apps/cowswap-frontend/src/common/pure/Modal/index.tsx @@ -1,10 +1,12 @@ import React from 'react' +import { isMobile } from '@cowprotocol/common-utils' + import { useSpringValue, useTransition } from '@react-spring/web' import { useGesture } from '@use-gesture/react' import styled from 'styled-components/macro' -import { isMobile } from 'legacy/utils/userAgent' +import { UI } from 'common/constants/theme' import { CloseIcon, ContentWrapper, HeaderRow, HoverText, StyledDialogContent, StyledDialogOverlay } from './styled' @@ -20,6 +22,9 @@ interface ModalProps { children?: React.ReactNode } +/** + * @deprecated use common/pure/NewModal instead + */ export function Modal({ isOpen, onDismiss, @@ -90,7 +95,7 @@ export const CowModal = styled(Modal)<{ padding?: string }>` > [data-reach-dialog-content] { - color: ${({ theme }) => theme.text1}; + color: var(${UI.COLOR_TEXT1}); width: 100%; max-width: ${({ maxWidth = 500 }) => `${maxWidth}px`}; border: ${({ border = 'inherit' }) => `${border}`}; @@ -98,8 +103,9 @@ export const CowModal = styled(Modal)<{ padding: ${({ padding = '0px' }) => `${padding}`}; margin: auto; transition: max-width 0.4s ease; - background-color: ${({ theme }) => theme.bg1}; + background-color: var(${UI.COLOR_CONTAINER_BG_01}); overflow: hidden; + border-radius: var(${UI.BORDER_RADIUS_NORMAL}); ${({ theme }) => theme.mediaWidth.upToSmall` max-height: 100vh; @@ -116,7 +122,7 @@ export const CowModal = styled(Modal)<{ left: 0; width: 100%; padding: 16px; - background: ${({ theme }) => theme.bg1}; + background: var(${UI.COLOR_CONTAINER_BG_01}); z-index: 20; `} } @@ -141,3 +147,8 @@ export const CowModal = styled(Modal)<{ } } ` + +export const NewCowModal = styled(Modal)` + width: 100vw; + height: 100vh; +` \ No newline at end of file diff --git a/apps/cowswap-frontend/src/common/pure/Modal/styled.tsx b/apps/cowswap-frontend/src/common/pure/Modal/styled.tsx index 29ef71105b..a6e8b4e8e7 100644 --- a/apps/cowswap-frontend/src/common/pure/Modal/styled.tsx +++ b/apps/cowswap-frontend/src/common/pure/Modal/styled.tsx @@ -5,6 +5,8 @@ import { animated } from '@react-spring/web' import { transparentize } from 'polished' import styled, { css } from 'styled-components/macro' +import { UI } from 'common/constants/theme' + export const HeaderRow = styled.div` ${({ theme }) => theme.flexRowNoWrap}; padding: 1rem 1rem; @@ -27,7 +29,7 @@ export const CloseIcon = styled.div` export const HoverText = styled.div` text-decoration: none; - color: ${({ theme }) => theme.text1}; + color: var(${UI.COLOR_TEXT1}); display: flex; align-items: center; @@ -38,7 +40,7 @@ export const HoverText = styled.div` export const ContentWrapper = styled.div` /* background-color: ${({ theme }) => theme.bg0}; */ - background-color: ${({ theme }) => theme.bg1}; + background-color: var(${UI.COLOR_CONTAINER_BG_01}); padding: 0 1rem 1rem 1rem; border-bottom-left-radius: 20px; border-bottom-right-radius: 20px; @@ -57,6 +59,7 @@ export const StyledDialogOverlay = styled(AnimatedDialogOverlay)` justify-content: center; background-color: ${({ theme }) => theme.modalBG}; + backdrop-filter: blur(5px); } ` diff --git a/apps/cowswap-frontend/src/common/pure/NetworksList/index.tsx b/apps/cowswap-frontend/src/common/pure/NetworksList/index.tsx index a2ae882e45..04880fef18 100644 --- a/apps/cowswap-frontend/src/common/pure/NetworksList/index.tsx +++ b/apps/cowswap-frontend/src/common/pure/NetworksList/index.tsx @@ -1,12 +1,11 @@ +import { getChainInfo } from '@cowprotocol/common-const' +import { getExplorerBaseUrl } from '@cowprotocol/common-utils' import { SupportedChainId } from '@cowprotocol/cow-sdk' +import { ALL_SUPPORTED_CHAIN_IDS } from '@cowprotocol/cow-sdk' +import { ExternalLink } from '@cowprotocol/ui' import { Trans } from '@lingui/macro' -import { getChainInfo } from 'legacy/constants/chainInfo' -import { ALL_SUPPORTED_CHAIN_IDS } from 'legacy/constants/chains' -import { ExternalLink } from 'legacy/theme' -import { getExplorerBaseUrl } from 'legacy/utils/explorer' - import * as styledEl from './styled' export interface NetworksListProps { diff --git a/apps/cowswap-frontend/src/common/pure/NetworksList/styled.tsx b/apps/cowswap-frontend/src/common/pure/NetworksList/styled.tsx index 9b85e9d168..e79310176b 100644 --- a/apps/cowswap-frontend/src/common/pure/NetworksList/styled.tsx +++ b/apps/cowswap-frontend/src/common/pure/NetworksList/styled.tsx @@ -2,6 +2,8 @@ import { transparentize } from 'polished' import { ArrowDownCircle } from 'react-feather' import styled from 'styled-components/macro' +import { UI } from 'common/constants/theme' + export const ActiveRowWrapper = styled.div` background-color: ${({ theme }) => transparentize(0.4, theme.bg4)}; border-radius: 8px; @@ -17,7 +19,7 @@ export const ActiveRowLinkList = styled.div` & > a { align-items: center; - color: ${({ theme }) => theme.text1}; + color: var(${UI.COLOR_TEXT1}); display: flex; flex-direction: row; font-size: 14px; diff --git a/apps/cowswap-frontend/src/common/pure/NewModal/index.cosmos.tsx b/apps/cowswap-frontend/src/common/pure/NewModal/index.cosmos.tsx new file mode 100644 index 0000000000..72d1966d76 --- /dev/null +++ b/apps/cowswap-frontend/src/common/pure/NewModal/index.cosmos.tsx @@ -0,0 +1,85 @@ +import ICON_ARROW from 'assets/icon/arrow.svg' +import SVG from 'react-inlinesvg' +import styled from 'styled-components/macro' + +import { IMAGE_ACCOUNT, MOCK_TOKEN } from 'common/constants/cosmos' +import { UI } from 'common/constants/theme' +import { IconSpinner } from 'common/pure/IconSpinner' +import { Stepper } from 'common/pure/Stepper' + +import { NewModal, NewModalContentBottom, NewModalContentTop } from './index' + +const Wrapper = styled.div` + width: 100vw; + height: 100vh; +` + +const ArrowRight = styled(SVG)` + --size: 12px; + width: var(--size); + height: var(--size); + margin: auto; + + > path { + fill: var(${UI.COLOR_TEXT2}); + } +` + +const ModalFixtures = { + 'new modal + content top/bottom': ( + + + + +

+ Approve spending AAVE
on CoW Swap +

+ + + +

Sign (gas-free!) in your wallet...

+ +
+ + + ), + 'new modal + content top/bottom 2': ( + + + + + +

Confirm Swap

+

+ 10 AAVE 564.7202 DAI +

+
+
+ + +

Sign (gas-free!) in your wallet...

+ +
+
+
+ ), + 'new modal + heading title': ( + + - New Modal - + + ), +} + +export default ModalFixtures diff --git a/apps/cowswap-frontend/src/common/pure/NewModal/index.tsx b/apps/cowswap-frontend/src/common/pure/NewModal/index.tsx new file mode 100644 index 0000000000..090f5b9e5d --- /dev/null +++ b/apps/cowswap-frontend/src/common/pure/NewModal/index.tsx @@ -0,0 +1,163 @@ +import React from 'react' + +import CLOSE_ICON from 'assets/icon/x.svg' +import SVG from 'react-inlinesvg' +import styled from 'styled-components/macro' + +import { UI } from 'common/constants/theme' + +const ModalInner = styled.div` + display: flex; + flex-direction: column; + width: 100%; + height: auto; + margin: auto; + background: transparent; + padding: 0; + position: relative; +` + +const Wrapper = styled.div<{ maxWidth?: number | string; minHeight?: number | string }>` + display: flex; + width: 100%; + height: 100%; + margin: auto; + overflow-y: auto; + background: var(${UI.COLOR_CONTAINER_BG_01}); + border-radius: var(${UI.BORDER_RADIUS_NORMAL}); + box-shadow: var(${UI.BOX_SHADOW_NORMAL}); + + ${({ theme }) => theme.mediaWidth.upToSmall` + margin: 0; + border-radius: 0; + border-top-left-radius: var(${UI.BORDER_RADIUS_NORMAL}); + border-top-right-radius: var(${UI.BORDER_RADIUS_NORMAL}); + box-shadow: none; + `} + + ${ModalInner} { + max-width: ${({ maxWidth }) => (maxWidth ? `${maxWidth}px` : '100%')}; + min-height: ${({ minHeight }) => (minHeight ? `${minHeight}px` : '100%')}; + + ${({ theme }) => theme.mediaWidth.upToSmall` + max-width: 100%; + height: 100%; + `} + } +` + +const Heading = styled.h2` + display: flex; + justify-content: space-between; + width: 100%; + height: auto; + padding: 18px; + margin: 0; + font-size: var(${UI.FONT_SIZE_MEDIUM}); + + ${({ theme }) => theme.mediaWidth.upToSmall` + position: sticky; + top: 0; + `} +` + +const IconX = styled.div` + position: absolute; + top: 16px; + right: 10px; + cursor: pointer; + opacity: 0.7; + transition: opacity 0.2s ease-in-out; + margin: 0 0 0 auto; + + > svg { + width: var(${UI.ICON_SIZE_NORMAL}); + height: var(${UI.ICON_SIZE_NORMAL}); + color: var(${UI.ICON_COLOR_NORMAL}); + } + + &:hover { + opacity: 1; + } +` + +const NewModalContent = styled.div<{ paddingTop?: number }>` + display: flex; + align-items: center; + justify-content: center; + flex-flow: column wrap; + flex: 1; + width: 100%; + height: 100%; + padding: 0 var(${UI.PADDING_NORMAL}) var(${UI.PADDING_NORMAL}); + + h1, + h2, + h3 { + width: 100%; + font-size: var(${UI.FONT_SIZE_LARGER}); + font-weight: var(${UI.FONT_WEIGHT_BOLD}); + text-align: center; + line-height: 1.4; + margin: 0 auto; + } + + p { + font-size: var(${UI.FONT_SIZE_NORMAL}); + font-weight: var(${UI.FONT_WEIGHT_NORMAL}); + color: var(${UI.COLOR_TEXT2}); + margin: 0 auto; + padding: 0; + } +` + +export const NewModalContentTop = styled.div<{ paddingTop?: number }>` + display: flex; + flex-flow: column wrap; + align-items: center; + justify-content: center; + width: 100%; + margin: 0 0 auto; + padding: ${({ paddingTop = 0 }) => `${paddingTop}px`} 0 0; + gap: 24px; + + > span { + gap: 6px; + display: flex; + flex-flow: column wrap; + } + + p { + font-size: var(${UI.FONT_SIZE_MEDIUM}); + } +` + +export const NewModalContentBottom = styled(NewModalContentTop)` + margin: auto 0 0; + + p { + font-size: var(${UI.FONT_SIZE_NORMAL}); + } +` +export interface NewModalProps { + maxWidth?: number + minHeight?: number + title?: string + onDismiss?: () => void + children?: React.ReactNode +} + +export function NewModal({ maxWidth = 450, minHeight = 450, title, children, onDismiss }: NewModalProps) { + return ( + + + {title && {title}} + onDismiss && onDismiss()}> + + + + {children} + + + ) +} diff --git a/apps/cowswap-frontend/src/common/pure/OrderExecutionStatusList/RateTooltipHeader.tsx b/apps/cowswap-frontend/src/common/pure/OrderExecutionStatusList/RateTooltipHeader.tsx index bd2ee27daf..6da6a4630e 100644 --- a/apps/cowswap-frontend/src/common/pure/OrderExecutionStatusList/RateTooltipHeader.tsx +++ b/apps/cowswap-frontend/src/common/pure/OrderExecutionStatusList/RateTooltipHeader.tsx @@ -1,5 +1,7 @@ import styled from 'styled-components/macro' +import { UI } from 'common/constants/theme' + import { OrderExecutionStatusList } from './index' const Content = styled.div` @@ -16,7 +18,7 @@ const Content = styled.div` line-height: 1.5; padding: 0; margin: 0; - color: ${({ theme }) => theme.text1}; + color: var(${UI.COLOR_TEXT1}); } > h3 { diff --git a/apps/cowswap-frontend/src/common/pure/OrderSubmittedContent/index.tsx b/apps/cowswap-frontend/src/common/pure/OrderSubmittedContent/index.tsx index 371e4e54d3..d8551b7e69 100644 --- a/apps/cowswap-frontend/src/common/pure/OrderSubmittedContent/index.tsx +++ b/apps/cowswap-frontend/src/common/pure/OrderSubmittedContent/index.tsx @@ -1,12 +1,12 @@ +import { isCowOrder } from '@cowprotocol/common-utils' import { SupportedChainId } from '@cowprotocol/cow-sdk' +import { ButtonPrimary } from '@cowprotocol/ui' import { Trans } from '@lingui/macro' import styled from 'styled-components/macro' -import { ButtonPrimary } from 'legacy/components/Button' import { EnhancedTransactionLink } from 'legacy/components/EnhancedTransactionLink' import { HashType } from 'legacy/state/enhancedTransactions/reducer' -import { isCowOrder } from 'legacy/utils' import AnimatedConfirmation from 'common/pure/AnimatedConfirmation' diff --git a/apps/cowswap-frontend/src/common/pure/PermitModal/index.cosmos.tsx b/apps/cowswap-frontend/src/common/pure/PermitModal/index.cosmos.tsx new file mode 100644 index 0000000000..c209c2aea0 --- /dev/null +++ b/apps/cowswap-frontend/src/common/pure/PermitModal/index.cosmos.tsx @@ -0,0 +1,83 @@ +import { USDC_MAINNET, WBTC } from '@cowprotocol/common-const' +import { Identicon } from '@cowprotocol/wallet' +import { CurrencyAmount } from '@uniswap/sdk-core' + +import styled from 'styled-components/macro' + +import { IconSpinner } from '../IconSpinner' + +import { PermitModal } from './index' + +const Wrapper = styled.div` + width: 100vw; + height: 100vh; +` + +const INPUT_AMOUNT = CurrencyAmount.fromRawAmount(USDC_MAINNET, 500_000 * 10 ** USDC_MAINNET.decimals) +const OUTPUT_AMOUNT = CurrencyAmount.fromRawAmount(WBTC, 1.2 * 10 ** WBTC.decimals) + +const WALLET_ICON = ( + + + +) + +const PermitModalFixtures = { + 'SWAP: Pending permit signature': ( + + + + ), + 'SWAP: Pending order signature': ( + + + + ), + 'LIMIT: Pending permit signature': ( + + + + ), + 'LIMIT: Pending order signature': ( + + + + ), + // These two cases should happen, but including for completeness as the parameters allow it + 'Missing amounts on approve': ( + + + + ), + 'Missing amounts on submit': ( + + + + ), +} + +export default PermitModalFixtures diff --git a/apps/cowswap-frontend/src/common/pure/PermitModal/index.tsx b/apps/cowswap-frontend/src/common/pure/PermitModal/index.tsx new file mode 100644 index 0000000000..0157dacdc9 --- /dev/null +++ b/apps/cowswap-frontend/src/common/pure/PermitModal/index.tsx @@ -0,0 +1,103 @@ +import { useMemo } from 'react' + +import { TokenAmount, TokenSymbol } from '@cowprotocol/ui' +import { Currency, CurrencyAmount } from '@uniswap/sdk-core' + +import ICON_ARROW from 'assets/icon/arrow.svg' +import SVG from 'react-inlinesvg' +import styled from 'styled-components/macro' +import { Nullish } from 'types' + +import { UI } from '../../constants/theme' +import { IconSpinner } from '../IconSpinner' +import { NewModal, NewModalContentBottom, NewModalContentTop, NewModalProps } from '../NewModal' +import { Stepper, StepProps } from '../Stepper' + +export type PermitModalProps = NewModalProps & { + inputAmount: Nullish> + outputAmount: Nullish> + step: 'approve' | 'submit' + orderType: 'Swap' | 'Limit Order' + icon?: React.ReactNode +} + +/** + * You probably want to use containers/PermitModal instead + * This is the pure component for cosmos + */ +export function PermitModal(props: PermitModalProps) { + const { inputAmount, outputAmount, step, icon: inputIcon, orderType, ...rest } = props + + const steps: StepProps[] = useMemo( + () => [ + { + stepState: step === 'approve' ? 'loading' : 'finished', + stepNumber: 1, + label: 'Approve' + (step === 'approve' ? '' : 'd'), + }, + { stepState: step === 'submit' ? 'loading' : 'active', stepNumber: 2, label: 'Submit' }, + ], + [step] + ) + const icon = useMemo( + () => + step === 'approve' ? ( + + ) : ( + {inputIcon} + ), + [inputAmount?.currency, inputIcon, step] + ) + + const title = useMemo( + () => + step === 'approve' ? ( + <> + Approve spending
+ on CoW Swap + + ) : ( + `Confirm ${orderType}` + ), + [inputAmount?.currency, orderType, step] + ) + + const body = useMemo( + () => + step === 'approve' ? null : ( +

+ {' '} + +

+ ), + [inputAmount, outputAmount, step] + ) + + return ( + + + {icon} + +

{title}

+ {body} +
+
+ + +

Sign (gas-free!) in your wallet...

+ +
+
+ ) +} + +const ArrowRight = styled(SVG)` + --size: 12px; + width: var(--size); + height: var(--size); + margin: auto; + + > path { + fill: var(${UI.COLOR_TEXT2}); + } +` diff --git a/apps/cowswap-frontend/src/common/pure/PriceImpactIndicator/index.tsx b/apps/cowswap-frontend/src/common/pure/PriceImpactIndicator/index.tsx index 0fe2fc1de7..4d18915b0d 100644 --- a/apps/cowswap-frontend/src/common/pure/PriceImpactIndicator/index.tsx +++ b/apps/cowswap-frontend/src/common/pure/PriceImpactIndicator/index.tsx @@ -1,15 +1,14 @@ +import { formatPercent } from '@cowprotocol/common-utils' +import { Loader } from '@cowprotocol/ui' +import { MouseoverTooltip } from '@cowprotocol/ui' import { Percent } from '@uniswap/sdk-core' import { t } from '@lingui/macro' import styled, { DefaultTheme } from 'styled-components/macro' -import Loader from 'legacy/components/Loader' -import { MouseoverTooltip } from 'legacy/components/Tooltip' import { PriceImpact } from 'legacy/hooks/usePriceImpact' import { warningSeverity } from 'legacy/utils/prices' -import { formatPercent } from 'utils/amountFormat' - export interface PriceImpactIndicatorProps { priceImpactParams?: PriceImpact } diff --git a/apps/cowswap-frontend/src/common/pure/RateInfo/index.cosmos.tsx b/apps/cowswap-frontend/src/common/pure/RateInfo/index.cosmos.tsx index b21ff58f99..8d54cde44c 100644 --- a/apps/cowswap-frontend/src/common/pure/RateInfo/index.cosmos.tsx +++ b/apps/cowswap-frontend/src/common/pure/RateInfo/index.cosmos.tsx @@ -1,13 +1,10 @@ +import { COW, GNO, DAI_GOERLI, USDT_GOERLI, WETH_GOERLI } from '@cowprotocol/common-const' import { SupportedChainId } from '@cowprotocol/cow-sdk' +import { TokenSymbol } from '@cowprotocol/ui' import { CurrencyAmount, Token } from '@uniswap/sdk-core' import styled from 'styled-components/macro' -import { COW, GNO } from 'legacy/constants/tokens' -import { DAI_GOERLI, USDT_GOERLI, WETH_GOERLI } from 'legacy/utils/goerli/constants' - -import { TokenSymbol } from 'common/pure/TokenSymbol' - import { RateInfoParams, RateInfo } from './index' const inputCurrency = WETH_GOERLI diff --git a/apps/cowswap-frontend/src/common/pure/RateInfo/index.tsx b/apps/cowswap-frontend/src/common/pure/RateInfo/index.tsx index 9f84c1d116..7ea915715a 100644 --- a/apps/cowswap-frontend/src/common/pure/RateInfo/index.tsx +++ b/apps/cowswap-frontend/src/common/pure/RateInfo/index.tsx @@ -1,6 +1,8 @@ import React, { Dispatch, SetStateAction, useEffect, useMemo, useState } from 'react' +import { getAddress } from '@cowprotocol/common-utils' import { SupportedChainId } from '@cowprotocol/cow-sdk' +import { FiatAmount, TokenAmount, TokenSymbol } from '@cowprotocol/ui' import { Currency, CurrencyAmount } from '@uniswap/sdk-core' import { Trans } from '@lingui/macro' @@ -9,12 +11,9 @@ import { Repeat } from 'react-feather' import styled from 'styled-components/macro' import { Nullish } from 'types' +import { UI } from 'common/constants/theme' import { usePrice } from 'common/hooks/usePrice' -import { FiatAmount } from 'common/pure/FiatAmount' -import { TokenAmount } from 'common/pure/TokenAmount' -import { TokenSymbol } from 'common/pure/TokenSymbol' import { getQuoteCurrency } from 'common/services/getQuoteCurrency' -import { getAddress } from 'utils/getAddress' const DEFAULT_DECIMALS = 4 @@ -60,7 +59,7 @@ const RateLabel = styled.div` color: ${({ theme }) => transparentize(0.2, theme.text1)}; &:hover { - color: ${({ theme }) => theme.text1}; + color: var(${UI.COLOR_TEXT1}); } ` @@ -68,7 +67,7 @@ const InvertIcon = styled.div` --size: 17px; cursor: pointer; background: ${({ theme }) => transparentize(0.9, theme.text1)}; - color: ${({ theme }) => theme.text1}; + color: var(${UI.COLOR_TEXT1}); width: var(--size); height: var(--size); min-width: var(--size); diff --git a/apps/cowswap-frontend/src/common/pure/SafeWalletLink/index.tsx b/apps/cowswap-frontend/src/common/pure/SafeWalletLink/index.tsx index 864694ae96..2df9622fa3 100644 --- a/apps/cowswap-frontend/src/common/pure/SafeWalletLink/index.tsx +++ b/apps/cowswap-frontend/src/common/pure/SafeWalletLink/index.tsx @@ -1,6 +1,5 @@ -import { ExternalLink } from 'legacy/theme' - -import { getSafeWebUrl } from 'api/gnosisSafe' +import { getSafeWebUrl } from '@cowprotocol/core' +import { ExternalLink } from '@cowprotocol/ui' export function SafeWalletLink(props: { chainId: number diff --git a/apps/cowswap-frontend/src/common/pure/Stepper/index.cosmos.tsx b/apps/cowswap-frontend/src/common/pure/Stepper/index.cosmos.tsx new file mode 100644 index 0000000000..9b62a26e3f --- /dev/null +++ b/apps/cowswap-frontend/src/common/pure/Stepper/index.cosmos.tsx @@ -0,0 +1,62 @@ +import styled from 'styled-components/macro'; + +import { UI } from 'common/constants/theme' + +import { Stepper } from './index'; + +const Wrapper = styled.div` + width: 90%; + height: 120px; + background: var(${UI.COLOR_CONTAINER_BG_01}); + border-radius: var(${UI.BORDER_RADIUS_NORMAL}); + display: flex; + align-items: center; + justify-content: center; +`; + +const StepperFixtures = { + 'Stepper start': ( + + + + ), + '2 Stepper with active step': ( + + + + ), + 'Stepper with error state': ( + + + + ), + 'Stepper with loading state': ( + + + + ), +}; + +export default StepperFixtures; diff --git a/apps/cowswap-frontend/src/common/pure/Stepper/index.tsx b/apps/cowswap-frontend/src/common/pure/Stepper/index.tsx new file mode 100644 index 0000000000..b1673895b8 --- /dev/null +++ b/apps/cowswap-frontend/src/common/pure/Stepper/index.tsx @@ -0,0 +1,142 @@ +import ICON_CHECK from 'assets/icon/check.svg' +import SVG from 'react-inlinesvg' +import styled from 'styled-components/macro' + +import { UI } from 'common/constants/theme' +import { IconSpinner } from 'common/pure/IconSpinner' + +type StepState = 'active' | 'finished' | 'disabled' | 'error' | 'loading' | 'open' + +export interface StepProps { + stepState: StepState + stepNumber: number + label: string + dotSize?: number + dotBorderColor?: UI +} + +interface StepStyles { + dotBackground: UI + dotColor: UI + labelColor: UI +} + +const stateStyles: Record = { + active: { dotBackground: UI.COLOR_LINK, dotColor: UI.COLOR_CONTAINER_BG_01, labelColor: UI.COLOR_TEXT1 }, + finished: { dotBackground: UI.COLOR_LINK_OPACITY_10, dotColor: UI.COLOR_LINK, labelColor: UI.COLOR_TEXT1 }, + disabled: { + dotBackground: UI.COLOR_TEXT1_OPACITY_25, + dotColor: UI.COLOR_TEXT1_OPACITY_25, + labelColor: UI.COLOR_TEXT1_OPACITY_25, + }, + error: { dotBackground: UI.COLOR_DANGER_BG, dotColor: UI.COLOR_DANGER, labelColor: UI.COLOR_DANGER }, + loading: { dotBackground: UI.COLOR_LINK, dotColor: UI.COLOR_CONTAINER_BG_01, labelColor: UI.COLOR_LINK }, + open: { dotBackground: UI.COLOR_TEXT1_OPACITY_10, dotColor: UI.COLOR_TEXT2, labelColor: UI.COLOR_TEXT2 }, +} + +const Step = styled.div` + display: flex; + position: relative; + align-items: center; + margin: 0; + padding: 0; + font-size: var(${UI.FONT_SIZE_SMALL}); + background: transparent; + color: ${({ stepState }) => `var(${stateStyles[stepState].labelColor})`}; + gap: 8px; + flex: 1 0 auto; + + i { + display: flex; + align-items: center; + justify-content: center; + width: var(--dotSize); + height: var(--dotSize); + max-width: var(--dotSize); + max-height: var(--dotSize); + border-radius: var(--dotSize); + border: 1px solid ${({ dotBorderColor = UI.COLOR_CONTAINER_BG_01 }) => `var(${dotBorderColor})`}; + background: ${({ stepState }) => `var(${stateStyles[stepState].dotBackground})`}; + color: ${({ stepState }) => `var(${stateStyles[stepState].dotColor})`}; + flex: 0 0 auto; + z-index: 1; + position: relative; + font-style: normal; + font-size: inherit; + line-height: 1; + + > svg { + width: 50%; + height: 50%; + margin: auto; + } + + > svg > path { + fill: var(${UI.COLOR_LINK}); + } + } + + > small { + flex: 0 0 auto; + font-size: inherit; + } + + > hr { + width: 100%; + height: 1px; + border: 0; + background: ${({ stepState }) => + stepState === 'error' + ? `var(${stateStyles['error'].dotBackground})` + : stepState === 'finished' + ? `var(${stateStyles['finished'].dotBackground})` + : `var(${UI.COLOR_TEXT1_OPACITY_25})`}; + border-radius: var(${UI.BORDER_RADIUS_NORMAL}); + } + + &&:last-child { + flex: 0; + } + + &:last-child > hr { + display: none; + } +` + +const Wrapper = styled.div<{ maxWidth?: string; dotSize?: number }>` + --dotSize: ${({ dotSize }) => `${dotSize}px`}; + width: ${({ maxWidth }) => (maxWidth ? maxWidth : '100%')}; + display: flex; + align-items: center; + justify-content: space-between; + position: relative; + gap: 10px; + padding: 24px; + margin: 0 auto; +` + +interface StepperProps { + steps: StepProps[] + maxWidth?: string + dotSize?: number +} + +export function Stepper({ steps, maxWidth, dotSize = 21 }: StepperProps) { + return ( + + {steps.map((step, index) => ( + + {step.stepState === 'loading' ? ( + + {step.stepNumber} + + ) : ( + {step.stepState === 'finished' ? : step.stepNumber} + )} + {step.label} +
+
+ ))} +
+ ) +} diff --git a/apps/cowswap-frontend/src/common/pure/TradeLoadingButton/index.tsx b/apps/cowswap-frontend/src/common/pure/TradeLoadingButton/index.tsx index 790066f67a..0ef6a6110e 100644 --- a/apps/cowswap-frontend/src/common/pure/TradeLoadingButton/index.tsx +++ b/apps/cowswap-frontend/src/common/pure/TradeLoadingButton/index.tsx @@ -1,10 +1,11 @@ import { useEffect, useState } from 'react' +import { LONG_LOAD_THRESHOLD } from '@cowprotocol/common-const' + import { Text } from 'rebass' import styled from 'styled-components/macro' import { Dots } from 'legacy/components/swap/styleds' -import { LONG_LOAD_THRESHOLD } from 'legacy/constants' import { ThemedText } from 'legacy/theme' const fadeIn = ` diff --git a/apps/cowswap-frontend/src/common/pure/TransactionErrorContent/index.cosmos.tsx b/apps/cowswap-frontend/src/common/pure/TransactionErrorContent/index.cosmos.tsx index 990d8e3e55..1d221cf1a3 100644 --- a/apps/cowswap-frontend/src/common/pure/TransactionErrorContent/index.cosmos.tsx +++ b/apps/cowswap-frontend/src/common/pure/TransactionErrorContent/index.cosmos.tsx @@ -1,11 +1,13 @@ import styled from 'styled-components/macro' +import { UI } from 'common/constants/theme' + import { TransactionErrorContent } from './index' const Wrapper = styled.div` width: 560px; margin: 0 auto; - background: ${({ theme }) => theme.bg1}; + background: var(${UI.COLOR_CONTAINER_BG_01}); ` const fixtures = { diff --git a/apps/cowswap-frontend/src/common/pure/TransactionErrorContent/index.tsx b/apps/cowswap-frontend/src/common/pure/TransactionErrorContent/index.tsx index 44491b0cc3..63aeeb57c7 100644 --- a/apps/cowswap-frontend/src/common/pure/TransactionErrorContent/index.tsx +++ b/apps/cowswap-frontend/src/common/pure/TransactionErrorContent/index.tsx @@ -1,8 +1,9 @@ +import { ButtonPrimary } from '@cowprotocol/ui' + import { Trans } from '@lingui/macro' import { AlertTriangle } from 'react-feather' import styled from 'styled-components/macro' -import { ButtonPrimary } from 'legacy/components/Button' import { CloseIcon } from 'legacy/theme' const Wrapper = styled.div` diff --git a/apps/cowswap-frontend/src/common/pure/TransactionSubmittedContent/SurplusModal.tsx b/apps/cowswap-frontend/src/common/pure/TransactionSubmittedContent/SurplusModal.tsx index 487ecf1fe9..a0bf0e18cf 100644 --- a/apps/cowswap-frontend/src/common/pure/TransactionSubmittedContent/SurplusModal.tsx +++ b/apps/cowswap-frontend/src/common/pure/TransactionSubmittedContent/SurplusModal.tsx @@ -1,22 +1,21 @@ import React, { useCallback } from 'react' +import { sendEvent } from '@cowprotocol/analytics' +import CheckSingular from '@cowprotocol/assets/cow-swap/check-singular.svg' +import SurplusCow from '@cowprotocol/assets/cow-swap/surplus-cow.svg' +import twitterImage from '@cowprotocol/assets/cow-swap/twitter.svg' import { OrderKind } from '@cowprotocol/cow-sdk' +import { FiatAmount, TokenAmount, SymbolElement } from '@cowprotocol/ui' +import { ExternalLink } from '@cowprotocol/ui' import { transparentize } from 'polished' import SVG from 'react-inlinesvg' import styled from 'styled-components/macro' -import CheckSingular from 'legacy/assets/cow-swap/check-singular.svg' -import SurplusCow from 'legacy/assets/cow-swap/surplus-cow.svg' -import twitterImage from 'legacy/assets/cow-swap/twitter.svg' import { Order } from 'legacy/state/orders/actions' -import { ExternalLink } from 'legacy/theme' +import { UI } from 'common/constants/theme' import { useGetSurplusData } from 'common/hooks/useGetSurplusFiatValue' -import { FiatAmount } from 'common/pure/FiatAmount' -import { TokenAmount, SymbolElement } from 'common/pure/TokenAmount' - -import { sendEvent } from '../../../legacy/components/analytics/googleAnalytics' const SELL_SURPLUS_WORD = 'got' const BUY_SURPLUS_WORD = 'saved' @@ -59,7 +58,7 @@ export const Wrapper = styled.div` --size: 28px; width: var(--size); height: var(--size); - background: ${({ theme }) => theme.bg1}; + background: var(${UI.COLOR_CONTAINER_BG_01}); border-radius: 50%; width: var(--size); height: var(--size); @@ -121,7 +120,7 @@ export const Wrapper = styled.div` width: 70%; margin: 34px auto; padding: 0; - color: ${({ theme }) => theme.text2}; + color: var(${UI.COLOR_TEXT2}); } ` diff --git a/apps/cowswap-frontend/src/common/pure/TransactionSubmittedContent/index.tsx b/apps/cowswap-frontend/src/common/pure/TransactionSubmittedContent/index.tsx index e234c0603d..a39747a3d9 100644 --- a/apps/cowswap-frontend/src/common/pure/TransactionSubmittedContent/index.tsx +++ b/apps/cowswap-frontend/src/common/pure/TransactionSubmittedContent/index.tsx @@ -1,5 +1,6 @@ import React from 'react' +import GameIcon from '@cowprotocol/assets/cow-swap/game.gif' import { SupportedChainId as ChainId } from '@cowprotocol/cow-sdk' import { Currency } from '@uniswap/sdk-core' @@ -7,7 +8,6 @@ import { Link } from 'react-router-dom' import { Text } from 'rebass' import { Nullish } from 'types' -import GameIcon from 'legacy/assets/cow-swap/game.gif' import { OrderProgressBar } from 'legacy/components/OrderProgressBar' import { DisplayLink } from 'legacy/components/TransactionConfirmationModal/DisplayLink' import { getActivityState } from 'legacy/hooks/useActivityDerivedState' @@ -15,7 +15,7 @@ import { ActivityStatus } from 'legacy/hooks/useRecentActivity' import { ActivityDerivedState } from 'modules/account/containers/Transaction' import { EthFlowStepper } from 'modules/swap/containers/EthFlowStepper' -import AddToMetamask from 'modules/wallet/web3-react/containers/AddToMetamask' +import { AddToMetamask } from 'modules/wallet/containers/AddToMetamask' import { Routes } from 'common/constants/routes' diff --git a/apps/cowswap-frontend/src/common/pure/TransactionSubmittedContent/styled.tsx b/apps/cowswap-frontend/src/common/pure/TransactionSubmittedContent/styled.tsx index 6e0fedede7..ac318fc56c 100644 --- a/apps/cowswap-frontend/src/common/pure/TransactionSubmittedContent/styled.tsx +++ b/apps/cowswap-frontend/src/common/pure/TransactionSubmittedContent/styled.tsx @@ -2,6 +2,8 @@ import styled from 'styled-components/macro' import { CloseIcon } from 'legacy/theme' +import { UI } from 'common/constants/theme' + export const ButtonCustom = styled.button` display: flex; flex: 1 1 auto; @@ -11,7 +13,7 @@ export const ButtonCustom = styled.button` border-radius: 16px; min-height: 52px; border: 1px solid ${({ theme }) => theme.border2}; - color: ${({ theme }) => theme.text1}; + color: var(${UI.COLOR_TEXT1}); background: transparent; outline: 0; padding: 8px 16px; diff --git a/apps/cowswap-frontend/src/common/services/getQuoteCurrency/index.ts b/apps/cowswap-frontend/src/common/services/getQuoteCurrency/index.ts index 4f528f1a19..524e2e4749 100644 --- a/apps/cowswap-frontend/src/common/services/getQuoteCurrency/index.ts +++ b/apps/cowswap-frontend/src/common/services/getQuoteCurrency/index.ts @@ -1,13 +1,12 @@ +import { DAI, USDC_MAINNET, USDT } from '@cowprotocol/common-const' +import { NATIVE_CURRENCY_BUY_ADDRESS } from '@cowprotocol/common-const' +import { DAI_GOERLI, USDT_GOERLI, USDC_GOERLI } from '@cowprotocol/common-const' +import { USDC_GNOSIS_CHAIN, USDT_GNOSIS_CHAIN, WXDAI } from '@cowprotocol/common-const' import { SupportedChainId } from '@cowprotocol/cow-sdk' import { Currency, CurrencyAmount } from '@uniswap/sdk-core' import { Nullish } from 'types' -import { NATIVE_CURRENCY_BUY_ADDRESS } from 'legacy/constants' -import { DAI, USDC_MAINNET, USDT } from 'legacy/constants/tokens' -import { USDC_GNOSIS_CHAIN, USDT_GNOSIS_CHAIN, WXDAI } from 'legacy/utils/gnosis_chain/constants' -import { DAI_GOERLI, USDT_GOERLI, USDC_GOERLI } from 'legacy/utils/goerli/constants' - // TODO: Find a solution for using API: https://www.coingecko.com/en/categories/stablecoins const STABLE_COINS: { [key in SupportedChainId]: string[] } = { [SupportedChainId.MAINNET]: [USDC_MAINNET, USDT, DAI].map((token) => token.address.toLowerCase()), diff --git a/apps/cowswap-frontend/src/common/state/receiverWalletBannerVisibility/atom.ts b/apps/cowswap-frontend/src/common/state/receiverWalletBannerVisibility/atom.ts new file mode 100644 index 0000000000..d6288955d7 --- /dev/null +++ b/apps/cowswap-frontend/src/common/state/receiverWalletBannerVisibility/atom.ts @@ -0,0 +1,21 @@ +import { atom } from 'jotai' +import { atomWithStorage } from 'jotai/utils' + +export type WarningBannerVisibility = string[] + +const WARNING_BANNER_VISIBILITY_KEY = 'warningBannerVisibility:v0' + +export const hiddenReceiverWalletBannersAtom = atomWithStorage( + WARNING_BANNER_VISIBILITY_KEY, + [] +) + +export const hideReceiverWalletBannerAtom = atom(null, (get, set, orderId: string) => { + const hiddenBanners = get(hiddenReceiverWalletBannersAtom) + + if (hiddenBanners.includes(orderId)) { + return + } + + set(hiddenReceiverWalletBannersAtom, [...hiddenBanners, orderId]) +}) diff --git a/apps/cowswap-frontend/src/common/state/receiverWalletBannerVisibility/hooks.ts b/apps/cowswap-frontend/src/common/state/receiverWalletBannerVisibility/hooks.ts new file mode 100644 index 0000000000..369e794ac8 --- /dev/null +++ b/apps/cowswap-frontend/src/common/state/receiverWalletBannerVisibility/hooks.ts @@ -0,0 +1,14 @@ +import { useAtomValue, useSetAtom } from 'jotai' +import { useMemo } from 'react' + +import { hiddenReceiverWalletBannersAtom, hideReceiverWalletBannerAtom } from './atom' + +export function useIsReceiverWalletBannerHidden(orderId?: string): boolean { + const hiddenBanners = useAtomValue(hiddenReceiverWalletBannersAtom) + + return useMemo(() => !!orderId && hiddenBanners.includes(orderId), [hiddenBanners, orderId]) +} + +export function useHideReceiverWalletBanner() { + return useSetAtom(hideReceiverWalletBannerAtom) +} diff --git a/apps/cowswap-frontend/src/common/state/receiverWalletBannerVisibility/index.ts b/apps/cowswap-frontend/src/common/state/receiverWalletBannerVisibility/index.ts new file mode 100644 index 0000000000..64c191af4c --- /dev/null +++ b/apps/cowswap-frontend/src/common/state/receiverWalletBannerVisibility/index.ts @@ -0,0 +1 @@ +export { useHideReceiverWalletBanner, useIsReceiverWalletBannerHidden } from './hooks' diff --git a/apps/cowswap-frontend/src/common/state/totalSurplusState/updaters.ts b/apps/cowswap-frontend/src/common/state/totalSurplusState/updaters.ts index 7bbd484135..b5993a80ff 100644 --- a/apps/cowswap-frontend/src/common/state/totalSurplusState/updaters.ts +++ b/apps/cowswap-frontend/src/common/state/totalSurplusState/updaters.ts @@ -1,12 +1,11 @@ import { useSetAtom } from 'jotai' import { useCallback, useEffect } from 'react' +import { useWalletInfo } from '@cowprotocol/wallet' import { Currency, CurrencyAmount } from '@uniswap/sdk-core' import useSWR from 'swr' -import { useWalletInfo } from 'modules/wallet' - import { getSurplusData } from 'api/gnosisProtocol/api' import useNativeCurrency from 'lib/hooks/useNativeCurrency' diff --git a/apps/cowswap-frontend/src/legacy/state/application/updater.ts b/apps/cowswap-frontend/src/common/updaters/ApplicationUpdater.ts similarity index 79% rename from apps/cowswap-frontend/src/legacy/state/application/updater.ts rename to apps/cowswap-frontend/src/common/updaters/ApplicationUpdater.ts index fffdf17284..343dd108e7 100644 --- a/apps/cowswap-frontend/src/legacy/state/application/updater.ts +++ b/apps/cowswap-frontend/src/common/updaters/ApplicationUpdater.ts @@ -1,18 +1,14 @@ import { useEffect, useState } from 'react' +import { usePrevious, useIsWindowVisible, useDebounce } from '@cowprotocol/common-hooks' +import { useWalletInfo } from '@cowprotocol/wallet' import { useWeb3React } from '@web3-react/core' -import useDebounce from 'legacy/hooks/useDebounce' -import useIsWindowVisible from 'legacy/hooks/useIsWindowVisible' -import usePrevious from 'legacy/hooks/usePrevious' +import { updateChainId } from 'legacy/state/application/reducer' import { useAppDispatch } from 'legacy/state/hooks' import { updateSelectedWallet } from 'legacy/state/user/reducer' -import { useWalletInfo } from 'modules/wallet' - -import { updateChainId } from './reducer' - -export default function Updater(): null { +export function ApplicationUpdater(): null { const { chainId } = useWalletInfo() const { provider, account } = useWeb3React() const dispatch = useAppDispatch() diff --git a/apps/cowswap-frontend/src/legacy/state/enhancedTransactions/updater/CancelReplaceTxUpdater.tsx b/apps/cowswap-frontend/src/common/updaters/CancelReplaceTxUpdater.tsx similarity index 94% rename from apps/cowswap-frontend/src/legacy/state/enhancedTransactions/updater/CancelReplaceTxUpdater.tsx rename to apps/cowswap-frontend/src/common/updaters/CancelReplaceTxUpdater.tsx index 97ab21e5d9..46a31bc723 100644 --- a/apps/cowswap-frontend/src/legacy/state/enhancedTransactions/updater/CancelReplaceTxUpdater.tsx +++ b/apps/cowswap-frontend/src/common/updaters/CancelReplaceTxUpdater.tsx @@ -1,5 +1,6 @@ import { useEffect } from 'react' +import { useWalletInfo } from '@cowprotocol/wallet' import { useWeb3React } from '@web3-react/core' import { Dispatch } from 'redux' @@ -7,9 +8,8 @@ import { Dispatch } from 'redux' import { replaceTransaction } from 'legacy/state/enhancedTransactions/actions' import { useAllTransactionHashes } from 'legacy/state/enhancedTransactions/hooks' import { useAppDispatch } from 'legacy/state/hooks' -import { sdk } from 'legacy/utils/blocknative' -import { useWalletInfo } from 'modules/wallet' +import { sdk } from 'api/blocknative' function watchTxChanges(pendingHashes: string[], chainId: number, dispatch: Dispatch) { for (const hash of pendingHashes) { @@ -60,7 +60,7 @@ function unwatchTxChanges(pendingHashes: string[], chainId: number) { } } -export default function CancelReplaceTxUpdater(): null { +export function CancelReplaceTxUpdater(): null { const { provider } = useWeb3React() const { chainId, account } = useWalletInfo() const dispatch = useAppDispatch() diff --git a/apps/cowswap-frontend/src/legacy/state/price/updater.ts b/apps/cowswap-frontend/src/common/updaters/FeesUpdater.ts similarity index 88% rename from apps/cowswap-frontend/src/legacy/state/price/updater.ts rename to apps/cowswap-frontend/src/common/updaters/FeesUpdater.ts index dd7b2553f0..dfaf831e1b 100644 --- a/apps/cowswap-frontend/src/legacy/state/price/updater.ts +++ b/apps/cowswap-frontend/src/common/updaters/FeesUpdater.ts @@ -1,38 +1,36 @@ import { useEffect, useMemo } from 'react' +import { DEFAULT_DECIMALS } from '@cowprotocol/common-const' +import { useDebounce, useIsOnline, useIsWindowVisible } from '@cowprotocol/common-hooks' +import { isAddress, tryParseCurrencyAmount } from '@cowprotocol/common-utils' import { OrderKind } from '@cowprotocol/cow-sdk' +import { useENSAddress } from '@cowprotocol/ens' +import { useWalletInfo } from '@cowprotocol/wallet' -import { DEFAULT_DECIMALS } from 'legacy/constants' -import useDebounce from 'legacy/hooks/useDebounce' -import useENSAddress from 'legacy/hooks/useENSAddress' -import useIsOnline from 'legacy/hooks/useIsOnline' -import useIsWindowVisible from 'legacy/hooks/useIsWindowVisible' import { useRefetchQuoteCallback } from 'legacy/hooks/useRefetchPriceCallback' import { useIsUnsupportedTokenGp } from 'legacy/state/lists/hooks' -import { Field } from 'legacy/state/swap/actions' -import { useDerivedSwapInfo, useSwapState } from 'legacy/state/swap/hooks' +import { useAllQuotes, useIsBestQuoteLoading, useSetQuoteError } from 'legacy/state/price/hooks' +import { QuoteInformationObject } from 'legacy/state/price/reducer' +import { LegacyFeeQuoteParams } from 'legacy/state/price/types' import { isWrappingTrade } from 'legacy/state/swap/utils' +import { Field } from 'legacy/state/types' import { useOrderValidTo } from 'legacy/state/user/hooks' -import { isAddress } from 'legacy/utils' +import { useAppData } from 'modules/appData' import { useIsEoaEthFlow } from 'modules/swap/hooks/useIsEoaEthFlow' +import { useDerivedSwapInfo, useSwapState } from 'modules/swap/hooks/useSwapState' import { useEnoughBalanceAndAllowance } from 'modules/tokens' -import { useWalletInfo } from 'modules/wallet' import { getPriceQuality } from 'api/gnosisProtocol/api' -import { LegacyFeeQuoteParams as LegacyFeeQuoteParamsFull } from 'api/gnosisProtocol/legacy/types' -import { useVerifiedQuotesEnabled } from 'common/hooks/featureFlags/useVerifiedQuotesEnabled' -import tryParseCurrencyAmount from 'lib/utils/tryParseCurrencyAmount' -import { useAllQuotes, useIsBestQuoteLoading, useSetQuoteError } from './hooks' -import { QuoteInformationObject } from './reducer' +import { useVerifiedQuotesEnabled } from '../hooks/featureFlags/useVerifiedQuotesEnabled' export const TYPED_VALUE_DEBOUNCE_TIME = 350 const REFETCH_CHECK_INTERVAL = 10000 // Every 10s const RENEW_FEE_QUOTES_BEFORE_EXPIRATION_TIME = 30000 // Will renew the quote if there's less than 30 seconds left for the quote to expire const WAITING_TIME_BETWEEN_EQUAL_REQUESTS = 5000 // Prevents from sending the same request to often (max, every 5s) -type FeeQuoteParams = Omit +type FeeQuoteParams = Omit /** * Returns if the quote has been recently checked @@ -66,8 +64,9 @@ function quoteUsingSameParameters(currentParams: FeeQuoteParams, quoteInfo: Quot kind: currentKind, userAddress: currentUserAddress, receiver: currentReceiver, + appData: currentAppData, } = currentParams - const { amount, buyToken, sellToken, kind, userAddress, receiver } = quoteInfo + const { amount, buyToken, sellToken, kind, userAddress, receiver, appData } = quoteInfo const hasSameReceiver = currentReceiver && receiver ? currentReceiver === receiver : true // cache the base quote params without quoteInfo user address to check @@ -76,6 +75,7 @@ function quoteUsingSameParameters(currentParams: FeeQuoteParams, quoteInfo: Quot buyToken === currentBuyToken && amount === currentAmount && kind === currentKind && + appData === currentAppData && hasSameReceiver // 2 checks: if there's a quoteInfo user address (meaning quote was already calculated once) and one without // in case user is not connected @@ -119,7 +119,7 @@ function isRefetchQuoteRequired( return false } -export default function FeesUpdater(): null { +export function FeesUpdater(): null { const { chainId, account } = useWalletInfo() const verifiedQuotesEnabled = useVerifiedQuotesEnabled(chainId) @@ -130,7 +130,7 @@ export default function FeesUpdater(): null { parsedAmount, } = useDerivedSwapInfo() - const enoughBalance = useEnoughBalanceAndAllowance({ account, amount: parsedAmount }) + const { enoughBalance } = useEnoughBalanceAndAllowance({ account, amount: parsedAmount }) const { address: ensRecipientAddress } = useENSAddress(recipient) const receiver = ensRecipientAddress || recipient @@ -150,6 +150,8 @@ export default function FeesUpdater(): null { const isUnsupportedTokenGp = useIsUnsupportedTokenGp() + const appData = useAppData() + const refetchQuote = useRefetchQuoteCallback() const setQuoteError = useSetQuoteError() @@ -208,6 +210,8 @@ export default function FeesUpdater(): null { validTo, isEthFlow, priceQuality: getPriceQuality({ verifyQuote: verifiedQuotesEnabled && enoughBalance }), + appData: appData?.fullAppData, + appDataHash: appData?.appDataKeccak256, } // Don't refetch if offline. @@ -280,6 +284,8 @@ export default function FeesUpdater(): null { sellTokenAddressInvalid, enoughBalance, verifiedQuotesEnabled, + appData?.fullAppData, + appData?.appDataKeccak256, ]) return null diff --git a/apps/cowswap-frontend/src/legacy/state/enhancedTransactions/updater/FinalizeTxUpdater.tsx b/apps/cowswap-frontend/src/common/updaters/FinalizeTxUpdater.tsx similarity index 95% rename from apps/cowswap-frontend/src/legacy/state/enhancedTransactions/updater/FinalizeTxUpdater.tsx rename to apps/cowswap-frontend/src/common/updaters/FinalizeTxUpdater.tsx index cc7c7ebf4d..fcedf226cd 100644 --- a/apps/cowswap-frontend/src/legacy/state/enhancedTransactions/updater/FinalizeTxUpdater.tsx +++ b/apps/cowswap-frontend/src/common/updaters/FinalizeTxUpdater.tsx @@ -1,30 +1,32 @@ import { useSetAtom } from 'jotai' import { useEffect, useMemo } from 'react' +import { GetReceipt, useBlockNumber, useGetReceipt } from '@cowprotocol/common-hooks' +import { useWalletInfo } from '@cowprotocol/wallet' import { TransactionReceipt } from '@ethersproject/abstract-provider' import { useWeb3React } from '@web3-react/core' import ms from 'ms.macro' -import { GetReceipt, useGetReceipt } from 'legacy/hooks/useGetReceipt' import { GetSafeInfo, useGetSafeInfo } from 'legacy/hooks/useGetSafeInfo' import { AppDispatch } from 'legacy/state' import { useAddPopup } from 'legacy/state/application/hooks' +import { + checkedTransaction, + finalizeTransaction, + updateSafeTransaction, +} from 'legacy/state/enhancedTransactions/actions' import { useAllTransactionsDetails } from 'legacy/state/enhancedTransactions/hooks' +import { EnhancedTransactionDetails, HashType } from 'legacy/state/enhancedTransactions/reducer' import { useAppDispatch } from 'legacy/state/hooks' import { invalidateOrdersBatch } from 'legacy/state/orders/actions' +import { CancelOrdersBatchCallback, useCancelOrdersBatch } from 'legacy/state/orders/hooks' import { partialOrderUpdate } from 'legacy/state/orders/utils' import { removeInFlightOrderIdAtom } from 'modules/swap/state/EthFlow/ethFlowInFlightOrderIdsAtom' -import { useWalletInfo } from 'modules/wallet' -import useBlockNumber from 'lib/hooks/useBlockNumber' import useNativeCurrency from 'lib/hooks/useNativeCurrency' -import { CancelOrdersBatchCallback, useCancelOrdersBatch } from '../../orders/hooks' -import { checkedTransaction, finalizeTransaction, updateSafeTransaction } from '../actions' -import { EnhancedTransactionDetails, HashType } from '../reducer' - const DELAY_REMOVAL_ETH_FLOW_ORDER_ID_MILLISECONDS = ms`2m` // Delay removing the order ID since the creation time its mined (minor precaution just to avoid edge cases of delay in indexing times affect the collision detection type TxInterface = Pick< @@ -252,7 +254,7 @@ function checkEthereumTransactions(params: CheckEthereumTransactions): Cancel[] }) } -export default function Updater(): null { +export function FinalizeTxUpdater(): null { const { provider } = useWeb3React() const { chainId, account } = useWalletInfo() const lastBlockNumber = useBlockNumber() @@ -260,7 +262,7 @@ export default function Updater(): null { const dispatch = useAppDispatch() const cancelOrdersBatch = useCancelOrdersBatch() - const getReceipt = useGetReceipt() + const getReceipt = useGetReceipt(chainId) const getSafeInfo = useGetSafeInfo() const addPopup = useAddPopup() const removeInFlightOrderId = useSetAtom(removeInFlightOrderIdAtom) diff --git a/apps/cowswap-frontend/src/legacy/state/gas/updater.tsx b/apps/cowswap-frontend/src/common/updaters/GasUpdater.tsx similarity index 55% rename from apps/cowswap-frontend/src/legacy/state/gas/updater.tsx rename to apps/cowswap-frontend/src/common/updaters/GasUpdater.tsx index 7b41d0f02c..0c8cef160d 100644 --- a/apps/cowswap-frontend/src/legacy/state/gas/updater.tsx +++ b/apps/cowswap-frontend/src/common/updaters/GasUpdater.tsx @@ -1,19 +1,37 @@ -import { useEffect } from 'react' +import { useSetAtom } from 'jotai/index' +import { useCallback, useEffect } from 'react' -import { GAS_PRICE_UPDATE_THRESHOLD } from 'legacy/constants' +import { GAS_PRICE_UPDATE_THRESHOLD } from '@cowprotocol/common-const' +import { useBlockNumber } from '@cowprotocol/common-hooks' +import { gasPriceAtom } from '@cowprotocol/core' +import { useWalletInfo } from '@cowprotocol/wallet' -import { useWalletInfo } from 'modules/wallet' +import { useDispatch } from 'react-redux' -import { gasFeeApi } from 'api/gasPrices' -import useBlockNumber from 'lib/hooks/useBlockNumber' +import { AppDispatch } from 'legacy/state' +import { updateGasPrices, UpdateGasPrices } from 'legacy/state/gas/actions' +import { useGasPrices } from 'legacy/state/gas/hooks' -import { useGasPrices, useUpdateGasPrices } from './hooks' +import { gasFeeApi } from 'api/gasPrices' function needsGasUpdate(now: number, lastUpdated: number, threshold: number) { return now - lastUpdated > threshold } -export default function GasUpdater(): null { +function useUpdateGasPrices() { + const dispatch = useDispatch() + const setGasPrice = useSetAtom(gasPriceAtom) + + return useCallback( + (gasParams: UpdateGasPrices) => { + dispatch(updateGasPrices(gasParams)) + setGasPrice(gasParams) + }, + [dispatch, setGasPrice] + ) +} + +export function GasUpdater(): null { const { chainId } = useWalletInfo() const gas = useGasPrices(chainId) const updateGasPrices = useUpdateGasPrices() diff --git a/apps/cowswap-frontend/src/modules/wallet/api/updaters/HwAccountIndexUpdater.tsx b/apps/cowswap-frontend/src/common/updaters/HwAccountIndexUpdater.tsx similarity index 89% rename from apps/cowswap-frontend/src/modules/wallet/api/updaters/HwAccountIndexUpdater.tsx rename to apps/cowswap-frontend/src/common/updaters/HwAccountIndexUpdater.tsx index 3430a75b4e..9a74887a6b 100644 --- a/apps/cowswap-frontend/src/modules/wallet/api/updaters/HwAccountIndexUpdater.tsx +++ b/apps/cowswap-frontend/src/common/updaters/HwAccountIndexUpdater.tsx @@ -1,14 +1,11 @@ import { useAtom } from 'jotai' import { useEffect, useMemo, useRef } from 'react' +import { getIsHardWareWallet, getWeb3ReactConnection, hwAccountIndexAtom, useWalletInfo } from '@cowprotocol/wallet' import { useWeb3React } from '@web3-react/core' import { useAppSelector } from 'legacy/state/hooks' -import { getIsHardWareWallet, getWeb3ReactConnection } from '../../web3-react/connection' -import { useWalletInfo } from '../hooks' -import { hwAccountIndexAtom } from '../state' - const indexChanged = true export function HwAccountIndexUpdater() { diff --git a/apps/cowswap-frontend/src/legacy/state/lists/updater.ts b/apps/cowswap-frontend/src/common/updaters/ListsUpdater.ts similarity index 93% rename from apps/cowswap-frontend/src/legacy/state/lists/updater.ts rename to apps/cowswap-frontend/src/common/updaters/ListsUpdater.ts index 133d4a27bb..4998458b55 100644 --- a/apps/cowswap-frontend/src/legacy/state/lists/updater.ts +++ b/apps/cowswap-frontend/src/common/updaters/ListsUpdater.ts @@ -1,22 +1,19 @@ import { useCallback, useEffect } from 'react' +import { UNSUPPORTED_LIST_URLS } from '@cowprotocol/common-const' +import { useInterval, useIsWindowVisible } from '@cowprotocol/common-hooks' +import { useWalletInfo } from '@cowprotocol/wallet' import { getVersionUpgrade, minVersionBump, VersionUpgrade } from '@uniswap/token-lists' import { useWeb3React } from '@web3-react/core' -import { UNSUPPORTED_LIST_URLS } from 'legacy/constants/lists' import { useFetchListCallback } from 'legacy/hooks/useFetchListCallback' -import useIsWindowVisible from 'legacy/hooks/useIsWindowVisible' import { updateVersion } from 'legacy/state/global/actions' import { useAppDispatch } from 'legacy/state/hooks' import { acceptListUpdate } from 'legacy/state/lists/actions' import { useAllLists } from 'legacy/state/lists/hooks' import { useActiveListUrls } from 'legacy/state/lists/hooks' -import { useWalletInfo } from 'modules/wallet' - -import useInterval from 'lib/hooks/useInterval' - -export default function Updater(): null { +export function ListsUpdater(): null { const { provider } = useWeb3React() const { chainId } = useWalletInfo() const dispatch = useAppDispatch() diff --git a/apps/cowswap-frontend/src/legacy/state/logs/updater.ts b/apps/cowswap-frontend/src/common/updaters/LogsUpdater.ts similarity index 86% rename from apps/cowswap-frontend/src/legacy/state/logs/updater.ts rename to apps/cowswap-frontend/src/common/updaters/LogsUpdater.ts index 70240a597b..ef12aecdff 100644 --- a/apps/cowswap-frontend/src/legacy/state/logs/updater.ts +++ b/apps/cowswap-frontend/src/common/updaters/LogsUpdater.ts @@ -1,18 +1,15 @@ import { useEffect, useMemo } from 'react' +import { useBlockNumber } from '@cowprotocol/common-hooks' +import { useWalletInfo } from '@cowprotocol/wallet' import { Filter } from '@ethersproject/providers' import { useWeb3React } from '@web3-react/core' -import { useWalletInfo } from 'modules/wallet' +import { useAppDispatch, useAppSelector } from 'legacy/state/hooks' +import { fetchedLogs, fetchedLogsError, fetchingLogs } from 'legacy/state/logs/slice' +import { isHistoricalLog, keyToFilter } from 'legacy/state/logs/utils' -import useBlockNumber from 'lib/hooks/useBlockNumber' - -import { fetchedLogs, fetchedLogsError, fetchingLogs } from './slice' -import { isHistoricalLog, keyToFilter } from './utils' - -import { useAppDispatch, useAppSelector } from '../hooks' - -export default function Updater(): null { +export function LogsUpdater(): null { const dispatch = useAppDispatch() const state = useAppSelector((state) => state.logs) const { provider } = useWeb3React() diff --git a/apps/cowswap-frontend/src/legacy/state/sentry/updater/index.ts b/apps/cowswap-frontend/src/common/updaters/SentryUpdater.ts similarity index 71% rename from apps/cowswap-frontend/src/legacy/state/sentry/updater/index.ts rename to apps/cowswap-frontend/src/common/updaters/SentryUpdater.ts index e2893d1220..0b1d6faf3f 100644 --- a/apps/cowswap-frontend/src/legacy/state/sentry/updater/index.ts +++ b/apps/cowswap-frontend/src/common/updaters/SentryUpdater.ts @@ -1,13 +1,14 @@ import { useEffect } from 'react' +import { useIsWindowVisible } from '@cowprotocol/common-hooks' +import { SentryTag } from '@cowprotocol/common-utils' +import { useWalletDetails, useWalletInfo } from '@cowprotocol/wallet' + import * as Sentry from '@sentry/browser' -import useIsWindowVisible from 'legacy/hooks/useIsWindowVisible' import { useAppSelector } from 'legacy/state/hooks' -import { useDerivedSwapInfo } from 'legacy/state/swap/hooks' -import { SentryTag } from 'legacy/utils/logging' -import { useWalletDetails, useWalletInfo } from 'modules/wallet' +import { useTradeState } from 'modules/trade/hooks/useTradeState' /** * _getSentryChainId @@ -32,20 +33,16 @@ function _getSentryChainIdAndConnectionStatus(appChainId: number | null, connect return sentryChainId?.toString() || SentryTag.DISCONNECTED } -export default function Updater(): null { +export function SentryUpdater(): null { const { account, chainId: connectedChainId } = useWalletInfo() const { walletName } = useWalletDetails() // app chain id maintains state for users disconnected but browsing app const disconnectedChainId = useAppSelector((state) => state.application.chainId) const windowVisible = useIsWindowVisible() - const { - currencies: { INPUT: sellCurrency, OUTPUT: buyCurrency }, - currenciesIds: { INPUT: sellCurrencyId, OUTPUT: buyCurrencyId }, - } = useDerivedSwapInfo() + const { state } = useTradeState() - const { symbol: buySymbol, name: buyName } = buyCurrency || {} - const { symbol: sellSymbol, name: sellName } = sellCurrency || {} + const { inputCurrencyId, outputCurrencyId } = state || {} useEffect(() => { if (windowVisible) { @@ -55,8 +52,8 @@ export default function Updater(): null { // setup a context scope.setContext('user', { user: account || SentryTag.DISCONNECTED, - sellToken: `${sellCurrencyId} <${sellSymbol || sellName}>`, - buyToken: `${buyCurrencyId} <${buySymbol || buyName}>`, + sellToken: inputCurrencyId, + buyToken: outputCurrencyId, }) // also set tags for each session scope.setTag('chainId', chainId) @@ -73,12 +70,8 @@ export default function Updater(): null { disconnectedChainId, walletName, // tokens - sellSymbol, - sellName, - buySymbol, - buyName, - sellCurrencyId, - buyCurrencyId, + inputCurrencyId, + outputCurrencyId, // window visibility check windowVisible, ]) diff --git a/apps/cowswap-frontend/src/legacy/state/user/updater.tsx b/apps/cowswap-frontend/src/common/updaters/UserUpdater.tsx similarity index 89% rename from apps/cowswap-frontend/src/legacy/state/user/updater.tsx rename to apps/cowswap-frontend/src/common/updaters/UserUpdater.tsx index 1b73711638..20db1f7b2f 100644 --- a/apps/cowswap-frontend/src/legacy/state/user/updater.tsx +++ b/apps/cowswap-frontend/src/common/updaters/UserUpdater.tsx @@ -1,10 +1,9 @@ import { useEffect } from 'react' import { useAppDispatch } from 'legacy/state/hooks' +import { updateMatchesDarkMode } from 'legacy/state/user/reducer' -import { updateMatchesDarkMode } from './reducer' - -export default function Updater(): null { +export function UserUpdater(): null { const dispatch = useAppDispatch() // keep dark mode in sync with the system diff --git a/apps/cowswap-frontend/src/legacy/state/orders/updaters/CancelledOrdersUpdater.ts b/apps/cowswap-frontend/src/common/updaters/orders/CancelledOrdersUpdater.ts similarity index 95% rename from apps/cowswap-frontend/src/legacy/state/orders/updaters/CancelledOrdersUpdater.ts rename to apps/cowswap-frontend/src/common/updaters/orders/CancelledOrdersUpdater.ts index 6ce50042c0..ef9920e84d 100644 --- a/apps/cowswap-frontend/src/legacy/state/orders/updaters/CancelledOrdersUpdater.ts +++ b/apps/cowswap-frontend/src/common/updaters/orders/CancelledOrdersUpdater.ts @@ -1,16 +1,17 @@ import { useCallback, useEffect, useRef } from 'react' +import { CANCELLED_ORDERS_PENDING_TIME } from '@cowprotocol/common-const' import { SupportedChainId as ChainId } from '@cowprotocol/cow-sdk' +import { useWalletInfo } from '@cowprotocol/wallet' -import { CANCELLED_ORDERS_PENDING_TIME } from 'legacy/constants' import { OrderFulfillmentData } from 'legacy/state/orders/actions' import { MARKET_OPERATOR_API_POLL_INTERVAL } from 'legacy/state/orders/consts' import { useCancelledOrders, useFulfillOrdersBatch } from 'legacy/state/orders/hooks' -import { fetchOrderPopupData, OrderLogPopupMixData } from 'legacy/state/orders/updaters/utils' import { OrderTransitionStatus } from 'legacy/state/orders/utils' import { useAddOrderToSurplusQueue } from 'modules/swap/state/surplusModal' -import { useWalletInfo } from 'modules/wallet' + +import { fetchOrderPopupData, OrderLogPopupMixData } from './utils' /** * Updater for cancelled orders. diff --git a/apps/cowswap-frontend/src/legacy/state/orders/updaters/ExpiredOrdersUpdater.ts b/apps/cowswap-frontend/src/common/updaters/orders/ExpiredOrdersUpdater.ts similarity index 74% rename from apps/cowswap-frontend/src/legacy/state/orders/updaters/ExpiredOrdersUpdater.ts rename to apps/cowswap-frontend/src/common/updaters/orders/ExpiredOrdersUpdater.ts index 5d823a8254..006c88b659 100644 --- a/apps/cowswap-frontend/src/legacy/state/orders/updaters/ExpiredOrdersUpdater.ts +++ b/apps/cowswap-frontend/src/common/updaters/orders/ExpiredOrdersUpdater.ts @@ -1,14 +1,13 @@ import { useEffect, useCallback, useRef } from 'react' +import { NATIVE_CURRENCY_BUY_ADDRESS } from '@cowprotocol/common-const' import { SupportedChainId as ChainId } from '@cowprotocol/cow-sdk' +import { useWalletInfo } from '@cowprotocol/wallet' -import { EXPIRED_ORDERS_PENDING_TIME } from 'legacy/constants' import { SetIsOrderRefundedBatch } from 'legacy/state/orders/actions' import { EXPIRED_ORDERS_CHECK_POLL_INTERVAL } from 'legacy/state/orders/consts' import { useExpiredOrders, useSetIsOrderRefundedBatch } from 'legacy/state/orders/hooks' -import { useWalletInfo } from 'modules/wallet' - import { getOrder } from 'api/gnosisProtocol' export function ExpiredOrdersUpdater(): null { @@ -25,7 +24,6 @@ export function ExpiredOrdersUpdater(): null { const updateOrders = useCallback( async (chainId: ChainId, account: string) => { const lowerCaseAccount = account.toLowerCase() - const now = Date.now() if (isUpdating.current) { return @@ -34,26 +32,24 @@ export function ExpiredOrdersUpdater(): null { try { isUpdating.current = true - // Filter orders: + // Filter expired orders: + // - Only eth-flow orders // - Owned by the current connected account - // - Created in the last 5 min, no further // - Not yet refunded - const pending = expiredRef.current.filter(({ owner, creationTime: creationTimeString, refundHash }) => { - const creationTime = new Date(creationTimeString).getTime() + const orderWithoutRefund = expiredRef.current.filter(({ owner, refundHash, sellToken }) => { + const isEthFlowOrder = sellToken === NATIVE_CURRENCY_BUY_ADDRESS - return ( - owner.toLowerCase() === lowerCaseAccount && now - creationTime < EXPIRED_ORDERS_PENDING_TIME && !refundHash - ) + return isEthFlowOrder && owner.toLowerCase() === lowerCaseAccount && !refundHash }) - if (pending.length === 0) { + if (orderWithoutRefund.length === 0) { // console.debug(`[CancelledOrdersUpdater] No orders are being expired`) return } else { - console.debug(`[ExpiredOrdersUpdater] Checking ${pending.length} recently expired orders...`) + console.debug(`[ExpiredOrdersUpdater] Checking ${orderWithoutRefund.length} recently expired orders...`) } - const ordersPromises = pending.map(({ id }) => getOrder(chainId, id)) + const ordersPromises = orderWithoutRefund.map(({ id }) => getOrder(chainId, id)) const resolvedPromises = await Promise.allSettled(ordersPromises) diff --git a/apps/cowswap-frontend/src/legacy/state/orders/updaters/GpOrdersUpdater.ts b/apps/cowswap-frontend/src/common/updaters/orders/GpOrdersUpdater.ts similarity index 96% rename from apps/cowswap-frontend/src/legacy/state/orders/updaters/GpOrdersUpdater.ts rename to apps/cowswap-frontend/src/common/updaters/orders/GpOrdersUpdater.ts index 18dcae9e3b..c2cc7923c4 100644 --- a/apps/cowswap-frontend/src/legacy/state/orders/updaters/GpOrdersUpdater.ts +++ b/apps/cowswap-frontend/src/common/updaters/orders/GpOrdersUpdater.ts @@ -1,23 +1,24 @@ import { useSetAtom } from 'jotai' import { useCallback, useEffect, useMemo, useRef } from 'react' +import { NATIVE_CURRENCY_BUY_TOKEN } from '@cowprotocol/common-const' import { EnrichedOrder, EthflowData, OrderClass, SupportedChainId as ChainId } from '@cowprotocol/cow-sdk' +import { useWalletInfo } from '@cowprotocol/wallet' import { Token } from '@uniswap/sdk-core' -import { NATIVE_CURRENCY_BUY_TOKEN } from 'legacy/constants' import { useAllTokens } from 'legacy/hooks/Tokens' import { Order, OrderStatus } from 'legacy/state/orders/actions' import { useAddOrUpdateOrders, useClearOrdersStorage } from 'legacy/state/orders/hooks' -import { computeOrderSummary } from 'legacy/state/orders/updaters/utils' import { classifyOrder, OrderTransitionStatus } from 'legacy/state/orders/utils' -import { useTokensForOrdersList, getTokensListFromOrders } from 'modules/orders' +import { getTokensListFromOrders, useTokensForOrdersList } from 'modules/orders' import { apiOrdersAtom } from 'modules/orders/state/apiOrdersAtom' -import { useWalletInfo } from 'modules/wallet' import { useGpOrders } from 'api/gnosisProtocol/hooks' import { getTokenFromMapping } from 'utils/orderUtils/getTokenFromMapping' +import { computeOrderSummary } from './utils' + // TODO: update this for ethflow states const statusMapping: Record = { cancelled: OrderStatus.CANCELLED, @@ -79,6 +80,7 @@ function _transformGpOrderToStoreOrder( summary: '', status, receiver: receiver || '', + fullAppData: order.fullAppData, apiAdditionalInfo: order, isCancelling: apiStatus === 'pending' && order.invalidated, // already cancelled in the API, not yet in the UI // EthFlow related diff --git a/apps/cowswap-frontend/src/legacy/state/orders/updaters/PendingOrdersUpdater.ts b/apps/cowswap-frontend/src/common/updaters/orders/PendingOrdersUpdater.ts similarity index 95% rename from apps/cowswap-frontend/src/legacy/state/orders/updaters/PendingOrdersUpdater.ts rename to apps/cowswap-frontend/src/common/updaters/orders/PendingOrdersUpdater.ts index 6db86d83fe..154a24b889 100644 --- a/apps/cowswap-frontend/src/legacy/state/orders/updaters/PendingOrdersUpdater.ts +++ b/apps/cowswap-frontend/src/common/updaters/orders/PendingOrdersUpdater.ts @@ -1,7 +1,14 @@ import { useSetAtom } from 'jotai' import { useCallback, useEffect, useRef } from 'react' +import { + getExplorerOrderLink, + isOrderInPendingTooLong, + openNpsAppziSometimes, + timeSinceInSeconds, +} from '@cowprotocol/common-utils' import { EthflowData, OrderClass, SupportedChainId as ChainId } from '@cowprotocol/cow-sdk' +import { useWalletInfo } from '@cowprotocol/wallet' import { GetSafeInfo, useGetSafeInfo } from 'legacy/hooks/useGetSafeInfo' import { FulfillOrdersBatchParams, Order, OrderFulfillmentData, OrderStatus } from 'legacy/state/orders/actions' @@ -21,18 +28,16 @@ import { usePresignOrders, useUpdatePresignGnosisSafeTx, } from 'legacy/state/orders/hooks' -import { fetchOrderPopupData, OrderLogPopupMixData } from 'legacy/state/orders/updaters/utils' import { OrderTransitionStatus } from 'legacy/state/orders/utils' -import { isOrderInPendingTooLong, openNpsAppziSometimes } from 'legacy/utils/appzi' -import { getExplorerOrderLink } from 'legacy/utils/explorer' import { useAddOrderToSurplusQueue } from 'modules/swap/state/surplusModal' -import { useWalletInfo } from 'modules/wallet' import { getOrder, OrderID } from 'api/gnosisProtocol' -import { removeOrdersToCancelAtom } from 'common/hooks/useMultipleOrdersCancellation/state' -import { useTriggerTotalSurplusUpdateCallback } from 'common/state/totalSurplusState' -import { timeSinceInSeconds } from 'utils/time' + +import { fetchOrderPopupData, OrderLogPopupMixData } from './utils' + +import { removeOrdersToCancelAtom } from '../../hooks/useMultipleOrdersCancellation/state' +import { useTriggerTotalSurplusUpdateCallback } from '../../state/totalSurplusState' /** * Return the ids of the orders that we are not yet aware that are signed. diff --git a/apps/cowswap-frontend/src/legacy/state/orders/updaters/SpotPricesUpdater.ts b/apps/cowswap-frontend/src/common/updaters/orders/SpotPricesUpdater.ts similarity index 93% rename from apps/cowswap-frontend/src/legacy/state/orders/updaters/SpotPricesUpdater.ts rename to apps/cowswap-frontend/src/common/updaters/orders/SpotPricesUpdater.ts index 1bc75801b0..9f09e4af74 100644 --- a/apps/cowswap-frontend/src/legacy/state/orders/updaters/SpotPricesUpdater.ts +++ b/apps/cowswap-frontend/src/common/updaters/orders/SpotPricesUpdater.ts @@ -1,20 +1,20 @@ import { useSetAtom } from 'jotai' import { useCallback, useEffect, useRef } from 'react' +import { useIsWindowVisible } from '@cowprotocol/common-hooks' +import { FractionUtils } from '@cowprotocol/common-utils' import { OrderClass, SupportedChainId } from '@cowprotocol/cow-sdk' +import { useWalletInfo } from '@cowprotocol/wallet' import { Token } from '@uniswap/sdk-core' -import useIsWindowVisible from 'legacy/hooks/useIsWindowVisible' import { SPOT_PRICE_CHECK_POLL_INTERVAL } from 'legacy/state/orders/consts' import { useCombinedPendingOrders } from 'legacy/state/orders/hooks' import { requestPrice } from 'modules/limitOrders/hooks/useGetInitialPrice' import { UpdateSpotPriceAtom, updateSpotPricesAtom } from 'modules/orders/state/spotPricesAtom' -import { useWalletInfo } from 'modules/wallet' -import { useSafeMemo } from 'common/hooks/useSafeMemo' -import { getCanonicalMarketChainKey } from 'common/utils/markets' -import { FractionUtils } from 'utils/fractionUtils' +import { useSafeMemo } from '../../hooks/useSafeMemo' +import { getCanonicalMarketChainKey } from '../../utils/markets' type MarketRecord = Record< string, diff --git a/apps/cowswap-frontend/src/legacy/state/orders/updaters/UnfillableOrdersUpdater.ts b/apps/cowswap-frontend/src/common/updaters/orders/UnfillableOrdersUpdater.ts similarity index 93% rename from apps/cowswap-frontend/src/legacy/state/orders/updaters/UnfillableOrdersUpdater.ts rename to apps/cowswap-frontend/src/common/updaters/orders/UnfillableOrdersUpdater.ts index c8e3080f99..20270205bc 100644 --- a/apps/cowswap-frontend/src/legacy/state/orders/updaters/UnfillableOrdersUpdater.ts +++ b/apps/cowswap-frontend/src/common/updaters/orders/UnfillableOrdersUpdater.ts @@ -1,17 +1,18 @@ import { useSetAtom } from 'jotai' import { useCallback, useEffect, useMemo, useRef } from 'react' +import { priceOutOfRangeAnalytics } from '@cowprotocol/analytics' +import { GP_VAULT_RELAYER, NATIVE_CURRENCY_BUY_ADDRESS, WRAPPED_NATIVE_CURRENCY } from '@cowprotocol/common-const' +import { useIsWindowVisible } from '@cowprotocol/common-hooks' +import { getPromiseFulfilledValue } from '@cowprotocol/common-utils' import { timestamp } from '@cowprotocol/contracts' import { OrderClass, SupportedChainId as ChainId } from '@cowprotocol/cow-sdk' +import { useWalletInfo } from '@cowprotocol/wallet' import { Currency, CurrencyAmount, Price } from '@uniswap/sdk-core' import { FeeInformation, PriceInformation } from 'types' -import { priceOutOfRangeAnalytics } from 'legacy/components/analytics' -import { GP_VAULT_RELAYER, NATIVE_CURRENCY_BUY_ADDRESS } from 'legacy/constants' -import { WRAPPED_NATIVE_CURRENCY } from 'legacy/constants/tokens' import { useGetGpPriceStrategy } from 'legacy/hooks/useGetGpPriceStrategy' -import useIsWindowVisible from 'legacy/hooks/useIsWindowVisible' import { GpPriceStrategy } from 'legacy/state/gas/atoms' import { Order } from 'legacy/state/orders/actions' import { PENDING_ORDERS_PRICE_CHECK_POLL_INTERVAL } from 'legacy/state/orders/consts' @@ -22,16 +23,15 @@ import { getRemainderAmount, isOrderUnfillable, } from 'legacy/state/orders/utils' -import { getPromiseFulfilledValue } from 'legacy/utils/misc' import { getBestQuote } from 'legacy/utils/price' import { updatePendingOrderPricesAtom } from 'modules/orders/state/pendingOrdersPricesAtom' import { hasEnoughBalanceAndAllowance, useBalancesAndAllowances } from 'modules/tokens' -import { useWalletInfo } from 'modules/wallet' import { getPriceQuality } from 'api/gnosisProtocol/api' -import { PRICE_QUOTE_VALID_TO_TIME } from 'common/constants/quote' -import { useVerifiedQuotesEnabled } from 'common/hooks/featureFlags/useVerifiedQuotesEnabled' + +import { PRICE_QUOTE_VALID_TO_TIME } from '../../constants/quote' +import { useVerifiedQuotesEnabled } from '../../hooks/featureFlags/useVerifiedQuotesEnabled' /** * Updater that checks whether pending orders are still "fillable" @@ -146,7 +146,7 @@ export function UnfillableOrdersUpdater(): null { console.debug(`[UnfillableOrdersUpdater] Check order`, order) const currencyAmount = CurrencyAmount.fromRawAmount(order.inputToken, order.sellAmount) - const enoughBalance = hasEnoughBalanceAndAllowance({ + const { enoughBalance } = hasEnoughBalanceAndAllowance({ account, amount: currencyAmount, balances: balancesRef.current, diff --git a/apps/cowswap-frontend/src/legacy/state/orders/updaters/index.ts b/apps/cowswap-frontend/src/common/updaters/orders/index.ts similarity index 100% rename from apps/cowswap-frontend/src/legacy/state/orders/updaters/index.ts rename to apps/cowswap-frontend/src/common/updaters/orders/index.ts diff --git a/apps/cowswap-frontend/src/legacy/state/orders/updaters/utils.ts b/apps/cowswap-frontend/src/common/updaters/orders/utils.ts similarity index 96% rename from apps/cowswap-frontend/src/legacy/state/orders/updaters/utils.ts rename to apps/cowswap-frontend/src/common/updaters/orders/utils.ts index e1a916ef03..7fb3f3a37c 100644 --- a/apps/cowswap-frontend/src/legacy/state/orders/updaters/utils.ts +++ b/apps/cowswap-frontend/src/common/updaters/orders/utils.ts @@ -1,14 +1,12 @@ +import { formatSymbol, formatTokenAmount, shortenAddress } from '@cowprotocol/common-utils' import { SupportedChainId as ChainId } from '@cowprotocol/cow-sdk' import { EnrichedOrder, OrderKind } from '@cowprotocol/cow-sdk' import { Order, OrderFulfillmentData, OrderStatus } from 'legacy/state/orders/actions' import { classifyOrder, OrderTransitionStatus } from 'legacy/state/orders/utils' import { stringToCurrency } from 'legacy/state/swap/extension' -import { shortenAddress } from 'legacy/utils' import { getOrder, OrderID } from 'api/gnosisProtocol' -import { formatTokenAmount } from 'utils/amountFormat' -import { formatSymbol } from 'utils/format' import { getIsComposableCowChildOrder } from 'utils/orderUtils/getIsComposableCowChildOrder' export type OrderLogPopupMixData = OrderFulfillmentData | OrderID diff --git a/apps/cowswap-frontend/src/common/utils/isOrderCancellable.test.ts b/apps/cowswap-frontend/src/common/utils/isOrderCancellable.test.ts index ac2a9a0aea..c7fbeead13 100644 --- a/apps/cowswap-frontend/src/common/utils/isOrderCancellable.test.ts +++ b/apps/cowswap-frontend/src/common/utils/isOrderCancellable.test.ts @@ -1,5 +1,6 @@ -import { NATIVE_CURRENCY_BUY_TOKEN } from 'legacy/constants' -import { COW } from 'legacy/constants/tokens' +import { COW } from '@cowprotocol/common-const' +import { NATIVE_CURRENCY_BUY_TOKEN } from '@cowprotocol/common-const' + import { Order, OrderStatus } from 'legacy/state/orders/actions' import { isOrderCancellable } from './isOrderCancellable' diff --git a/apps/cowswap-frontend/src/common/utils/markets.ts b/apps/cowswap-frontend/src/common/utils/markets.ts index ceb8728937..e977992483 100644 --- a/apps/cowswap-frontend/src/common/utils/markets.ts +++ b/apps/cowswap-frontend/src/common/utils/markets.ts @@ -1,7 +1,4 @@ import { SupportedChainId } from '@cowprotocol/cow-sdk' -import { Currency, Price } from '@uniswap/sdk-core' - -import invariant from 'tiny-invariant' /** * Convenient method to identify a market so it doesn't matter what is the sell token or buy token. @@ -51,11 +48,3 @@ export function getCanonicalMarketChainKey( marketInverted, } } - -export function assertSameMarket(price1: Price, price2: Price) { - // Assert I'm comparing apples with apples (prices should refer to market) - invariant( - price1.baseCurrency.equals(price2.baseCurrency) && price1.quoteCurrency.equals(price2.quoteCurrency), - 'Prices are not from the same market' - ) -} diff --git a/apps/cowswap-frontend/src/cosmos.decorator.tsx b/apps/cowswap-frontend/src/cosmos.decorator.tsx index 3460702d23..04bffb1c00 100644 --- a/apps/cowswap-frontend/src/cosmos.decorator.tsx +++ b/apps/cowswap-frontend/src/cosmos.decorator.tsx @@ -3,6 +3,10 @@ import './polyfills' import React, { StrictMode, useCallback, useContext, ReactNode } from 'react' +import IMAGE_MOON from '@cowprotocol/assets/cow-swap/moon.svg' +import IMAGE_SUN from '@cowprotocol/assets/cow-swap/sun.svg' +import { BlockNumberProvider } from '@cowprotocol/common-hooks' +import { WalletUpdater, injectedConnection } from '@cowprotocol/wallet' import { Web3ReactProvider } from '@web3-react/core' import { LanguageProvider } from 'i18n' @@ -13,18 +17,10 @@ import { Flex } from 'rebass' import styled from 'styled-components/macro' import { ThemeContext } from 'styled-components/macro' -import IMAGE_MOON from 'legacy/assets/cow-swap/moon.svg' -import IMAGE_SUN from 'legacy/assets/cow-swap/sun.svg' -import store from 'legacy/state' +import { cowSwapStore } from 'legacy/state' import { useDarkModeManager } from 'legacy/state/user/hooks' import ThemeProvider, { FixedGlobalStyle, ThemedGlobalStyle } from 'legacy/theme' -import { injectedConnection } from 'modules/wallet/web3-react/connection/injected' - -import { BlockNumberProvider } from 'lib/hooks/useBlockNumber' - -import { WalletUpdater } from './modules/wallet' - const DarkModeToggleButton = styled.button` display: flex; align-items: center; @@ -98,7 +94,7 @@ const Fixture = ({ children }: { children: ReactNode }) => { return ( - + diff --git a/apps/cowswap-frontend/src/cow-react/index.tsx b/apps/cowswap-frontend/src/cow-react/index.tsx index f20b500682..550ac9907f 100644 --- a/apps/cowswap-frontend/src/cow-react/index.tsx +++ b/apps/cowswap-frontend/src/cow-react/index.tsx @@ -1,12 +1,15 @@ import '@reach/dialog/styles.css' import 'inter-ui' -import 'legacy/components/analytics' -import 'utils/sentry' +import '@cowprotocol/analytics' +import './sentry' import { Provider as AtomProvider } from 'jotai' import { StrictMode } from 'react' -import { SnackbarsWidget } from '@cowswap/snackbars' +import { BlockNumberProvider } from '@cowprotocol/common-hooks' +import { nodeRemoveChildFix } from '@cowprotocol/common-utils' +import { jotaiStore } from '@cowprotocol/core' +import { SnackbarsWidget } from '@cowprotocol/snackbars' import { LanguageProvider } from 'i18n' import { createRoot } from 'react-dom/client' @@ -17,9 +20,8 @@ import * as serviceWorkerRegistration from 'serviceWorkerRegistration' import AppziButton from 'legacy/components/AppziButton' import { Popups } from 'legacy/components/Popups' import Web3Provider from 'legacy/components/Web3Provider' -import store from 'legacy/state' +import { cowSwapStore } from 'legacy/state' import ThemeProvider, { FixedGlobalStyle, ThemedGlobalStyle } from 'legacy/theme' -import { nodeRemoveChildFix } from 'legacy/utils/node' import { App } from 'modules/application/containers/App' import { Updaters } from 'modules/application/containers/App/Updaters' @@ -27,10 +29,8 @@ import { WithLDProvider } from 'modules/application/containers/WithLDProvider' import { FortuneWidget } from 'modules/fortune/containers/FortuneWidget' import { FeatureGuard } from 'common/containers/FeatureGuard' -import { BlockNumberProvider } from 'lib/hooks/useBlockNumber' import { WalletUnsupportedNetworkBanner } from '../common/containers/WalletUnsupportedNetworkBanner' -import { jotaiStore } from '../jotaiStore' // Node removeChild hackaround // based on: https://github.com/facebook/react/issues/11538#issuecomment-417504600 @@ -45,7 +45,7 @@ const root = createRoot(document.getElementById('root')!) root.render( - + diff --git a/apps/cowswap-frontend/src/utils/sentry.ts b/apps/cowswap-frontend/src/cow-react/sentry.ts similarity index 93% rename from apps/cowswap-frontend/src/utils/sentry.ts rename to apps/cowswap-frontend/src/cow-react/sentry.ts index 868867d629..43cd6d3e11 100644 --- a/apps/cowswap-frontend/src/utils/sentry.ts +++ b/apps/cowswap-frontend/src/cow-react/sentry.ts @@ -1,6 +1,6 @@ -import * as Sentry from '@sentry/react' +import { environmentName } from '@cowprotocol/common-utils' -import { environmentName } from 'legacy/utils/environments' +import * as Sentry from '@sentry/react' import { SENTRY_IGNORED_GP_QUOTE_ERRORS } from 'api/gnosisProtocol/errors/QuoteError' diff --git a/apps/cowswap-frontend/src/cowSdk.ts b/apps/cowswap-frontend/src/cowSdk.ts index 94b6582b6c..8fe22917e6 100644 --- a/apps/cowswap-frontend/src/cowSdk.ts +++ b/apps/cowswap-frontend/src/cowSdk.ts @@ -1,8 +1,7 @@ import { MetadataApi } from '@cowprotocol/app-data' +import { isBarnBackendEnv } from '@cowprotocol/common-utils' import { OrderBookApi } from '@cowprotocol/cow-sdk' -import { isBarnBackendEnv } from 'legacy/utils/environments' - const prodBaseUrls = process.env.REACT_APP_ORDER_BOOK_URLS ? JSON.parse(process.env.REACT_APP_ORDER_BOOK_URLS) : undefined diff --git a/apps/cowswap-frontend/src/i18n.tsx b/apps/cowswap-frontend/src/i18n.tsx index 43c79e78e9..bc78401fc2 100644 --- a/apps/cowswap-frontend/src/i18n.tsx +++ b/apps/cowswap-frontend/src/i18n.tsx @@ -1,6 +1,7 @@ import { ReactNode, useCallback } from 'react' -import { SupportedLocale } from 'legacy/constants/locales' +import { SupportedLocale } from '@cowprotocol/common-const' + import { initialLocale, useActiveLocale } from 'legacy/hooks/useActiveLocale' import { useUserLocaleManager } from 'legacy/state/user/hooks' diff --git a/apps/cowswap-frontend/src/legacy/assets/images/arrow-down-grey.svg b/apps/cowswap-frontend/src/legacy/assets/images/arrow-down-grey.svg deleted file mode 100644 index 886808296c..0000000000 --- a/apps/cowswap-frontend/src/legacy/assets/images/arrow-down-grey.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/apps/cowswap-frontend/src/legacy/components/AMMsLogo/index.tsx b/apps/cowswap-frontend/src/legacy/components/AMMsLogo/index.tsx index 219680b64a..eb8e1e0c3d 100644 --- a/apps/cowswap-frontend/src/legacy/components/AMMsLogo/index.tsx +++ b/apps/cowswap-frontend/src/legacy/components/AMMsLogo/index.tsx @@ -1,21 +1,20 @@ +import ZeroX from '@cowprotocol/assets/cow-swap/ammslogo/0x.png' +import Oneinch from '@cowprotocol/assets/cow-swap/ammslogo/1inch.png' +import Baoswap from '@cowprotocol/assets/cow-swap/ammslogo/baoswap.png' +import Curve from '@cowprotocol/assets/cow-swap/ammslogo/curve.png' +import Elk from '@cowprotocol/assets/cow-swap/ammslogo/elk.png' +import Honeyswap from '@cowprotocol/assets/cow-swap/ammslogo/honeyswap.png' +import Levinswap from '@cowprotocol/assets/cow-swap/ammslogo/levinswap.png' +import Matcha from '@cowprotocol/assets/cow-swap/ammslogo/matcha.png' +import Paraswap from '@cowprotocol/assets/cow-swap/ammslogo/paraswap.png' +import Sushi from '@cowprotocol/assets/cow-swap/ammslogo/sushi.png' +import Swapr from '@cowprotocol/assets/cow-swap/ammslogo/swapr.png' +import Symmetric from '@cowprotocol/assets/cow-swap/ammslogo/symmetric.png' +import Uniswap from '@cowprotocol/assets/cow-swap/ammslogo/uniswap.png' import { SupportedChainId } from '@cowprotocol/cow-sdk' import styled from 'styled-components/macro' -import ZeroX from 'legacy/assets/cow-swap/ammslogo/0x.png' -import Oneinch from 'legacy/assets/cow-swap/ammslogo/1inch.png' -import Baoswap from 'legacy/assets/cow-swap/ammslogo/baoswap.png' -import Curve from 'legacy/assets/cow-swap/ammslogo/curve.png' -import Elk from 'legacy/assets/cow-swap/ammslogo/elk.png' -import Honeyswap from 'legacy/assets/cow-swap/ammslogo/honeyswap.png' -import Levinswap from 'legacy/assets/cow-swap/ammslogo/levinswap.png' -import Matcha from 'legacy/assets/cow-swap/ammslogo/matcha.png' -import Paraswap from 'legacy/assets/cow-swap/ammslogo/paraswap.png' -import Sushi from 'legacy/assets/cow-swap/ammslogo/sushi.png' -import Swapr from 'legacy/assets/cow-swap/ammslogo/swapr.png' -import Symmetric from 'legacy/assets/cow-swap/ammslogo/symmetric.png' -import Uniswap from 'legacy/assets/cow-swap/ammslogo/uniswap.png' - import { imagesAnimationDelay, animationDelay, crossFade, fadeInOut, presentationTime } from './utils' export const Wrapper = styled.div<{ logosLength: number }>` diff --git a/apps/cowswap-frontend/src/legacy/components/AddressInputPanel/index.tsx b/apps/cowswap-frontend/src/legacy/components/AddressInputPanel/index.tsx index f75bb1abd8..a16f629887 100644 --- a/apps/cowswap-frontend/src/legacy/components/AddressInputPanel/index.tsx +++ b/apps/cowswap-frontend/src/legacy/components/AddressInputPanel/index.tsx @@ -1,23 +1,25 @@ import { ChangeEvent, Context, ReactNode, useCallback, useContext } from 'react' +import { getBlockExplorerUrl as getExplorerLink } from '@cowprotocol/common-utils' +import { useENS } from '@cowprotocol/ens' +import { RowBetween } from '@cowprotocol/ui' +import { ExternalLink } from '@cowprotocol/ui' +import { useWalletInfo } from '@cowprotocol/wallet' + import { t, Trans } from '@lingui/macro' import styled, { DefaultTheme, ThemeContext } from 'styled-components/macro' import { AutoColumn } from 'legacy/components/Column' -import { RowBetween } from 'legacy/components/Row' -import useENS from 'legacy/hooks/useENS' -import { ExternalLink, ThemedText } from 'legacy/theme' -import { getBlockExplorerUrl as getExplorerLink } from 'legacy/utils' - -import { useWalletInfo } from 'modules/wallet' +import { ThemedText } from 'legacy/theme' +import { UI } from 'common/constants/theme' import { autofocus } from 'common/utils/autofocus' const InputPanel = styled.div` ${({ theme }) => theme.flexColumnNoWrap} position: relative; border-radius: 16px; - background-color: ${({ theme }) => theme.grey1}; + background-color: var(${UI.COLOR_GREY}); z-index: 1; width: 100%; ` @@ -28,7 +30,7 @@ const ContainerRow = styled.div<{ error: boolean }>` align-items: center; border-radius: 16px; border: 0; - background-color: ${({ theme }) => theme.grey1}; + background-color: var(${UI.COLOR_GREY}); ` export const InputContainer = styled.div` @@ -50,7 +52,7 @@ const Input = styled.input<{ error?: boolean }>` width: 100%; &&::placeholder { - color: ${({ theme }) => theme.text2}; + color: var(${UI.COLOR_TEXT2}); } &:focus::placeholder { diff --git a/apps/cowswap-frontend/src/legacy/components/AmplitudeAnalytics/Trace.tsx b/apps/cowswap-frontend/src/legacy/components/AmplitudeAnalytics/Trace.tsx deleted file mode 100644 index 52fe79b8a1..0000000000 --- a/apps/cowswap-frontend/src/legacy/components/AmplitudeAnalytics/Trace.tsx +++ /dev/null @@ -1,64 +0,0 @@ -import { createContext, memo, PropsWithChildren, useContext, useEffect, useMemo } from 'react' - -import { - ElementName, - EventName, - ModalName, - PageName, - SectionName, -} from 'legacy/components/AmplitudeAnalytics/constants' // Mod - -import { sendAnalyticsEvent } from '.' - -export interface ITraceContext { - // Highest order context: eg Swap or Explore. - page?: PageName - - // Enclosed section name. For contexts with modals, refers to the - // section of the page from which the user triggered the modal. - section?: SectionName - - modal?: ModalName - - // Element name mostly used to identify events sources - // Does not need to be unique given the higher order page and section. - element?: ElementName -} - -export const TraceContext = createContext({}) - -type TraceProps = { - shouldLogImpression?: boolean // whether to log impression on mount - name?: EventName - properties?: Record -} & ITraceContext - -/** - * Sends an analytics event on mount (if shouldLogImpression is set), - * and propagates the context to child traces. - */ -export const Trace = memo( - ({ shouldLogImpression, name, children, page, section, element, properties }: PropsWithChildren) => { - const parentTrace = useContext(TraceContext) - - const combinedProps = useMemo( - () => ({ - ...parentTrace, - ...Object.fromEntries(Object.entries({ page, section, element }).filter(([_, v]) => v !== undefined)), - }), - [element, parentTrace, page, section] - ) - - useEffect(() => { - if (shouldLogImpression) { - sendAnalyticsEvent(name ?? EventName.PAGE_VIEWED, { ...combinedProps, ...properties }) - } - // Impressions should only be logged on mount. - // eslint-disable-next-line react-hooks/exhaustive-deps - }, []) - - return {children} - } -) - -Trace.displayName = 'Trace' diff --git a/apps/cowswap-frontend/src/legacy/components/AmplitudeAnalytics/TraceEvent.tsx b/apps/cowswap-frontend/src/legacy/components/AmplitudeAnalytics/TraceEvent.tsx deleted file mode 100644 index 08480d63f5..0000000000 --- a/apps/cowswap-frontend/src/legacy/components/AmplitudeAnalytics/TraceEvent.tsx +++ /dev/null @@ -1,71 +0,0 @@ -import { Children, cloneElement, isValidElement, memo, PropsWithChildren, SyntheticEvent } from 'react' - -import { Event, EventName } from './constants' -import { ITraceContext, Trace, TraceContext } from './Trace' - -import { sendAnalyticsEvent } from '.' - -type TraceEventProps = { - events: Event[] - name: EventName - properties?: Record -} & ITraceContext - -/** - * Analytics instrumentation component that wraps event callbacks with logging logic. - * - * @example - * - * - * - */ -export const TraceEvent = memo((props: PropsWithChildren) => { - const { name, properties, events, children, ...traceProps } = props - - return ( - - - {(traceContext) => - Children.map(children, (child) => { - if (!isValidElement(child)) { - return child - } - - // For each child, augment event handlers defined in `events` with event tracing. - return cloneElement(child, getEventHandlers(child, traceContext, events, name, properties)) - }) - } - - - ) -}) - -TraceEvent.displayName = 'TraceEvent' - -/** - * Given a set of child element and event props, returns a spreadable - * object of the event handlers augmented with analytics logging. - */ -function getEventHandlers( - child: React.ReactElement, - traceContext: ITraceContext, - events: Event[], - name: EventName, - properties?: Record -) { - const eventHandlers: Partial) => void>> = {} - - for (const event of events) { - eventHandlers[event] = (eventHandlerArgs: unknown) => { - // call child event handler with original arguments, must be in array - const args = Array.isArray(eventHandlerArgs) ? eventHandlerArgs : [eventHandlerArgs] - child.props[event]?.apply(child, args) - - // augment handler with analytics logging - sendAnalyticsEvent(name, { ...traceContext, ...properties, action: event }) - } - } - - // return a spreadable event handler object - return eventHandlers -} diff --git a/apps/cowswap-frontend/src/legacy/components/AmplitudeAnalytics/constants.ts b/apps/cowswap-frontend/src/legacy/components/AmplitudeAnalytics/constants.ts deleted file mode 100644 index e73d0f2ab5..0000000000 --- a/apps/cowswap-frontend/src/legacy/components/AmplitudeAnalytics/constants.ts +++ /dev/null @@ -1,79 +0,0 @@ -/** - * Event names that can occur in this application. - * - * Subject to change as new features are added and new events are defined - * and logged. - */ -export enum EventName { - PAGE_VIEWED = 'Page Viewed', - SWAP_SUBMITTED = 'Swap Submitted', - TOKEN_IMPORTED = 'Token Imported', - TOKEN_SELECTED = 'Token Selected', - TOKEN_SELECTOR_OPENED = 'Token Selector Opened', - // alphabetize additional event names. -} - -/** - * Known pages in the app. Highest order context. - */ -export const enum PageName { - EXPLORE_PAGE = 'explore-page', - POOL_PAGE = 'pool-page', - SWAP_PAGE = 'swap-page', - VOTE_PAGE = 'vote-page', - // alphabetize additional page names. - ACCOUNT_OVERVIEW_PAGE = 'account-overview-page', - ACCOUNT_TOKENS_PAGE = 'account-tokens-page', - ABOUT_PAGE = 'about-page', - FAQ_OVERVIEW_PAGE = 'faq-overview-page', - FAQ_PROTOCOL_PAGE = 'faq-protocol-page', - FAQ_TOKEN_PAGE = 'faq-token-page', - FAQ_TRADING_PAGE = 'faq-trading-page', - FAQ_AFFILIATE_PAGE = 'faq-affiliate-page', - FAQ_LIMIT_ORDERS_PAGE = 'faq-limit-orders-page', - FAQ_ETH_FLOW = 'faq-eth-flow', - TOC_PAGE = 'toc-page', -} - -/** - * Sections. Disambiguates low-level elements that may share a name. - * eg a `back` button in a modal will have the same `element`, - * but a different `section`. - */ -export const enum SectionName { - CURRENCY_INPUT_PANEL = 'swap-currency-input', - CURRENCY_OUTPUT_PANEL = 'swap-currency-output', - // alphabetize additional section names. -} - -/** Known modals for analytics purposes. */ -export const enum ModalName { - SWAP = 'swap-modal', - TOKEN_SELECTOR = 'token-selector-modal', - // alphabetize additional modal names. -} - -/** - * Known element names for analytics purposes. - * Use to identify low-level components given a TraceContext - */ -export const enum ElementName { - COMMON_BASES_CURRENCY_BUTTON = 'common-bases-currency-button', - CONFIRM_SWAP_BUTTON = 'confirm-swap-or-send', - IMPORT_TOKEN_BUTTON = 'import-token-button', - SWAP_BUTTON = 'swap-button', - TOKEN_SELECTOR_ROW = 'token-selector-row', - // alphabetize additional element names. -} - -/** - * Known events that trigger callbacks. - * @example - * - */ -export enum Event { - onClick = 'onClick', - onKeyPress = 'onKeyPress', - onSelect = 'onSelect', - // alphabetize additional events. -} diff --git a/apps/cowswap-frontend/src/legacy/components/AmplitudeAnalytics/index.ts b/apps/cowswap-frontend/src/legacy/components/AmplitudeAnalytics/index.ts deleted file mode 100644 index d6533cc94d..0000000000 --- a/apps/cowswap-frontend/src/legacy/components/AmplitudeAnalytics/index.ts +++ /dev/null @@ -1,88 +0,0 @@ -import { Identify, identify, init, track } from '@amplitude/analytics-browser' - -/** - * Initializes Amplitude with API key for project. - * - * Uniswap has two Amplitude projects: test and production. You must be a - * member of the organization on Amplitude to view details. - */ -export function initializeAnalytics(isDevEnvironment = process.env.NODE_ENV === 'development') { - if (isDevEnvironment) return - - const API_KEY = process.env.REACT_APP_AMPLITUDE_KEY - if (typeof API_KEY === 'undefined') { - throw new Error(`REACT_APP_AMPLITUDE_KEY must be a defined environment variable`) - } - - init( - API_KEY, - /* userId= */ undefined, // User ID should be undefined to let Amplitude default to Device ID - /* options= */ { - // Disable tracking of private user information by Amplitude - trackingOptions: { - ipAddress: false, - carrier: false, - city: false, - region: false, - country: false, - dma: false, // designated market area - }, - } - ) -} - -/** Sends an event to Amplitude. */ -export function sendAnalyticsEvent(eventName: string, eventProperties?: Record) { - if (process.env.NODE_ENV === 'development') { - console.log(`[amplitude(${eventName})]: ${JSON.stringify(eventProperties)}`) - return - } - - track(eventName, eventProperties) -} - -/** - * Class that exposes methods to mutate the User Model's properties in - * Amplitude that represents the current session's user. - * - * See https://help.amplitude.com/hc/en-us/articles/115002380567-User-properties-and-event-properties - * for details. - */ -class UserModel { - constructor(private isDevEnvironment = process.env.NODE_ENV === 'development') {} - - private log(method: string, ...parameters: unknown[]) { - console.debug(`[amplitude(Identify)]: ${method}(${parameters})`) - } - - private call(mutate: (event: Identify) => Identify) { - if (this.isDevEnvironment) { - const log = (_: Identify, method: string) => this.log.bind(this, method) - mutate(new Proxy(new Identify(), { get: log })) - return - } - identify(mutate(new Identify())) - } - - set(key: string, value: string | number) { - this.call((event) => event.set(key, value)) - } - - setOnce(key: string, value: string | number) { - this.call((event) => event.setOnce(key, value)) - } - - add(key: string, value: string | number) { - this.call((event) => event.add(key, typeof value === 'number' ? value : 0)) - } - - postInsert(key: string, value: string | number) { - this.call((event) => event.postInsert(key, value)) - } - - remove(key: string, value: string | number) { - this.call((event) => event.remove(key, value)) - } -} - -export const user = new UserModel() diff --git a/apps/cowswap-frontend/src/legacy/components/AppziButton/index.tsx b/apps/cowswap-frontend/src/legacy/components/AppziButton/index.tsx index 8eeb64cd96..a5070de79e 100644 --- a/apps/cowswap-frontend/src/legacy/components/AppziButton/index.tsx +++ b/apps/cowswap-frontend/src/legacy/components/AppziButton/index.tsx @@ -1,10 +1,10 @@ +import FeedbackIcon from '@cowprotocol/assets/cow-swap/feedback.svg' +import { isAppziEnabled, openFeedbackAppzi } from '@cowprotocol/common-utils' + import { transparentize } from 'polished' import SVG from 'react-inlinesvg' import styled from 'styled-components/macro' -import FeedbackIcon from 'legacy/assets/cow-swap/feedback.svg' -import { isAppziEnabled, openFeedbackAppzi } from 'legacy/utils/appzi' - const Wrapper = styled.div` background: ${({ theme }) => transparentize(0.3, theme.bg2)}; backdrop-filter: blur(5px); diff --git a/apps/cowswap-frontend/src/legacy/components/Badge/RangeBadge.tsx b/apps/cowswap-frontend/src/legacy/components/Badge/RangeBadge.tsx index a7d4bb5293..65246370ef 100644 --- a/apps/cowswap-frontend/src/legacy/components/Badge/RangeBadge.tsx +++ b/apps/cowswap-frontend/src/legacy/components/Badge/RangeBadge.tsx @@ -1,11 +1,11 @@ +import { MouseoverTooltip } from '@cowprotocol/ui' + import { Trans } from '@lingui/macro' import { AlertCircle } from 'react-feather' import styled from 'styled-components/macro' import Badge, { BadgeVariant } from 'legacy/components/Badge' -import { MouseoverTooltip } from '../Tooltip' - const BadgeWrapper = styled.div` font-size: 14px; display: flex; diff --git a/apps/cowswap-frontend/src/legacy/components/Button/__fixtures__/ButtonRadioChecked.tsx b/apps/cowswap-frontend/src/legacy/components/Button/__fixtures__/ButtonRadioChecked.tsx deleted file mode 100644 index b4d4b772b8..0000000000 --- a/apps/cowswap-frontend/src/legacy/components/Button/__fixtures__/ButtonRadioChecked.tsx +++ /dev/null @@ -1,9 +0,0 @@ -// ButtonRadioChecked.fixture.jsx -import { ButtonRadioChecked } from '../index' - -const fixtures = { - active: Active, - notActive: Not active, -} - -export default fixtures diff --git a/apps/cowswap-frontend/src/legacy/components/Card/index.tsx b/apps/cowswap-frontend/src/legacy/components/Card/index.tsx index 723d473ed2..d1bb1601c1 100644 --- a/apps/cowswap-frontend/src/legacy/components/Card/index.tsx +++ b/apps/cowswap-frontend/src/legacy/components/Card/index.tsx @@ -1,6 +1,8 @@ import { Box } from 'rebass/styled-components' import styled from 'styled-components/macro' +import { UI } from 'common/constants/theme' + const Card = styled(Box)<{ width?: string; padding?: string; border?: string; $borderRadius?: string }>` width: ${({ width }) => width ?? '100%'}; padding: ${({ padding }) => padding ?? '1rem'}; @@ -11,7 +13,7 @@ export default Card export const LightCard = styled(Card)` border: 1px solid ${({ theme }) => theme.bg2}; - background-color: ${({ theme }) => theme.bg1}; + background-color: var(${UI.COLOR_CONTAINER_BG_01}); ` export const LightGreyCard = styled(Card)` diff --git a/apps/cowswap-frontend/src/legacy/components/Confetti/index.tsx b/apps/cowswap-frontend/src/legacy/components/Confetti/index.tsx index de5837c7c1..46da1b428f 100644 --- a/apps/cowswap-frontend/src/legacy/components/Confetti/index.tsx +++ b/apps/cowswap-frontend/src/legacy/components/Confetti/index.tsx @@ -1,6 +1,6 @@ -import ReactConfetti from 'react-confetti' +import { useWindowSize } from '@cowprotocol/common-hooks' -import { useWindowSize } from '../../hooks/useWindowSize' +import ReactConfetti from 'react-confetti' // eslint-disable-next-line react/prop-types export default function Confetti({ start, variant }: { start: boolean; variant?: string }) { diff --git a/apps/cowswap-frontend/src/legacy/components/Copy/CopyMod.tsx b/apps/cowswap-frontend/src/legacy/components/Copy/CopyMod.tsx index db283a7f7c..25d9bea369 100644 --- a/apps/cowswap-frontend/src/legacy/components/Copy/CopyMod.tsx +++ b/apps/cowswap-frontend/src/legacy/components/Copy/CopyMod.tsx @@ -1,15 +1,17 @@ import React from 'react' +import { useCopyClipboard } from '@cowprotocol/common-hooks' + import { Trans } from '@lingui/macro' import { CheckCircle, Copy } from 'react-feather' import styled from 'styled-components/macro' import { TransactionStatusText } from 'legacy/components/Copy/index' -import useCopyClipboard from 'legacy/hooks/useCopyClipboard' import { LinkStyledButton } from 'legacy/theme' -// MOD imports +import { UI } from 'common/constants/theme' +// MOD imports export const CopyIcon = styled(LinkStyledButton)` color: ${({ theme }) => theme.text3}; flex-shrink: 0; @@ -27,7 +29,7 @@ export const CopyIcon = styled(LinkStyledButton)` :active, :focus { text-decoration: none; - color: ${({ theme }) => theme.text2}; + color: var(${UI.COLOR_TEXT2}); } ` diff --git a/apps/cowswap-frontend/src/legacy/components/CowBalance/index.tsx b/apps/cowswap-frontend/src/legacy/components/CowBalance/index.tsx index 9d43db3680..f9528ff5f7 100644 --- a/apps/cowswap-frontend/src/legacy/components/CowBalance/index.tsx +++ b/apps/cowswap-frontend/src/legacy/components/CowBalance/index.tsx @@ -1,10 +1,11 @@ +import { TokenAmount } from '@cowprotocol/ui' + import { Trans } from '@lingui/macro' import styled from 'styled-components/macro' import CowProtocolLogo from 'legacy/components/CowProtocolLogo' import { CowSubsidyInfoProps } from 'legacy/components/CowSubsidyModal' -import { TokenAmount } from 'common/pure/TokenAmount' import { ClaimSummaryTitle, ClaimTotal, ClaimSummary as ClaimSummaryWrapper } from 'pages/Claim/styled' const Wrapper = styled(ClaimSummaryWrapper)` diff --git a/apps/cowswap-frontend/src/legacy/components/CowBalanceButton/index.tsx b/apps/cowswap-frontend/src/legacy/components/CowBalanceButton/index.tsx index 3222ba17da..633bd9ca3e 100644 --- a/apps/cowswap-frontend/src/legacy/components/CowBalanceButton/index.tsx +++ b/apps/cowswap-frontend/src/legacy/components/CowBalanceButton/index.tsx @@ -1,16 +1,18 @@ import { SupportedChainId as ChainId } from '@cowprotocol/cow-sdk' +import { TokenAmount } from '@cowprotocol/ui' import { transparentize } from 'polished' import styled, { css } from 'styled-components/macro' import CowProtocolLogo from 'legacy/components/CowProtocolLogo' -import { useCombinedBalance } from 'legacy/state/cowToken/hooks' -import { TokenAmount } from 'common/pure/TokenAmount' +import { UI } from 'common/constants/theme' + +import { useCombinedBalance } from '../../hooks/useCombinedBalance' export const Wrapper = styled.div<{ isLoading: boolean }>` background-color: transparent; - color: ${({ theme }) => theme.text1}; + color: var(${UI.COLOR_TEXT1}); padding: 6px 12px; border: 2px solid transparent; font-weight: 500; diff --git a/apps/cowswap-frontend/src/legacy/components/CowProtocolLogo/index.tsx b/apps/cowswap-frontend/src/legacy/components/CowProtocolLogo/index.tsx index deab9db9be..dc22834552 100644 --- a/apps/cowswap-frontend/src/legacy/components/CowProtocolLogo/index.tsx +++ b/apps/cowswap-frontend/src/legacy/components/CowProtocolLogo/index.tsx @@ -1,6 +1,6 @@ -import styled from 'styled-components/macro' +import CowProtocolIcon from '@cowprotocol/assets/cow-swap/cow_v2.svg' -import CowProtocolIcon from 'legacy/assets/cow-swap/cow_v2.svg' +import styled from 'styled-components/macro' export const Icon = styled.span` --defaultSize: 24px; diff --git a/apps/cowswap-frontend/src/legacy/components/CowSubsidyModal/SubsidyTable.tsx b/apps/cowswap-frontend/src/legacy/components/CowSubsidyModal/SubsidyTable.tsx index a2b4e87679..fe3d6af20e 100644 --- a/apps/cowswap-frontend/src/legacy/components/CowSubsidyModal/SubsidyTable.tsx +++ b/apps/cowswap-frontend/src/legacy/components/CowSubsidyModal/SubsidyTable.tsx @@ -1,13 +1,14 @@ +import { V_COW } from '@cowprotocol/common-const' import { SupportedChainId } from '@cowprotocol/cow-sdk' +import { TokenAmount } from '@cowprotocol/ui' import { CurrencyAmount } from '@uniswap/sdk-core' import { transparentize, lighten } from 'polished' import styled from 'styled-components/macro' -import { V_COW } from 'legacy/constants/tokens' import { useIsDarkMode } from 'legacy/state/user/hooks' -import { TokenAmount } from 'common/pure/TokenAmount' +import { UI } from 'common/constants/theme' import { COW_SUBSIDY_DATA } from './constants' @@ -24,7 +25,7 @@ const StyledSubsidyTable = styled.table` } tbody { - background: ${({ theme }) => theme.grey1}; + background: var(${UI.COLOR_GREY}); border-radius: 16px; border: 0; } @@ -49,7 +50,7 @@ const SubsidyTr = styled.tr<{ selected?: boolean; darkMode?: boolean }>` } &:hover > td { - color: ${({ theme }) => theme.text1}; + color: var(${UI.COLOR_TEXT1}); background: ${({ theme }) => transparentize(0.9, theme.text1)}; } @@ -60,7 +61,7 @@ const SubsidyTr = styled.tr<{ selected?: boolean; darkMode?: boolean }>` > td { font-size: 15px; - color: ${({ theme }) => theme.text2}; + color: var(${UI.COLOR_TEXT2}); transition: background 0.3s ease-in-out; } diff --git a/apps/cowswap-frontend/src/legacy/components/CowSubsidyModal/index.tsx b/apps/cowswap-frontend/src/legacy/components/CowSubsidyModal/index.tsx index b31882b08b..c6d522084d 100644 --- a/apps/cowswap-frontend/src/legacy/components/CowSubsidyModal/index.tsx +++ b/apps/cowswap-frontend/src/legacy/components/CowSubsidyModal/index.tsx @@ -1,27 +1,25 @@ import { useCallback } from 'react' +import { ExternalLink, Row } from '@cowprotocol/ui' +import { useWalletInfo } from '@cowprotocol/wallet' import { Currency, CurrencyAmount } from '@uniswap/sdk-core' import { Text } from 'rebass' import { AutoColumn } from 'legacy/components/Column' -import { ExternalLink } from 'legacy/components/Link' -import Row from 'legacy/components/Row' import { ConfirmationModalProps } from 'legacy/components/TransactionConfirmationModal' -import { - ConfirmationModalContentProps, - LegacyConfirmationModalContent, -} from 'legacy/components/TransactionConfirmationModal/LegacyConfirmationModalContent' import useCowBalanceAndSubsidy from 'legacy/hooks/useCowBalanceAndSubsidy' -import { useWalletInfo } from 'modules/wallet' - import { CowModal } from 'common/pure/Modal' import { SUBSIDY_INFO_MESSAGE } from './constants' import SubsidyTable from './SubsidyTable' import CowBalance from '../CowBalance' +import { + ConfirmationModalContentProps, + LegacyConfirmationModalContent, +} from '../TransactionConfirmationModal/LegacyConfirmationModalContent' export type CowSubsidy = { tier: number; discount: number } export interface CowSubsidyInfoProps { diff --git a/apps/cowswap-frontend/src/legacy/components/ErrorBoundary/ChunkLoadError.tsx b/apps/cowswap-frontend/src/legacy/components/ErrorBoundary/ChunkLoadError.tsx index 04d8e6054e..2b97197d37 100644 --- a/apps/cowswap-frontend/src/legacy/components/ErrorBoundary/ChunkLoadError.tsx +++ b/apps/cowswap-frontend/src/legacy/components/ErrorBoundary/ChunkLoadError.tsx @@ -1,14 +1,16 @@ import React, { useCallback } from 'react' +import cowNoConnectionIMG from '@cowprotocol/assets/cow-swap/cow-no-connection.png' +import { DISCORD_LINK } from '@cowprotocol/common-const' +import { ButtonPrimary } from '@cowprotocol/ui' +import { AutoRow } from '@cowprotocol/ui' +import { ExternalLink } from '@cowprotocol/ui' + import { Trans } from '@lingui/macro' import styled from 'styled-components/macro' -import cowNoConnectionIMG from 'legacy/assets/cow-swap/cow-no-connection.png' -import { ButtonPrimary } from 'legacy/components/Button' import { AutoColumn } from 'legacy/components/Column' -import { AutoRow } from 'legacy/components/Row' -import { DISCORD_LINK } from 'legacy/constants' -import { ExternalLink, MEDIA_WIDTHS, ThemedText } from 'legacy/theme' +import { MEDIA_WIDTHS, ThemedText } from 'legacy/theme' import { Title } from 'modules/application/pure/Page' diff --git a/apps/cowswap-frontend/src/legacy/components/ErrorBoundary/ErrorWithStackTrace.tsx b/apps/cowswap-frontend/src/legacy/components/ErrorBoundary/ErrorWithStackTrace.tsx index 6d1c7999e0..13adefa7f7 100644 --- a/apps/cowswap-frontend/src/legacy/components/ErrorBoundary/ErrorWithStackTrace.tsx +++ b/apps/cowswap-frontend/src/legacy/components/ErrorBoundary/ErrorWithStackTrace.tsx @@ -1,19 +1,22 @@ import React from 'react' +import CowError from '@cowprotocol/assets/cow-swap/CowError.png' +import { CODE_LINK, DISCORD_LINK } from '@cowprotocol/common-const' +import { userAgent } from '@cowprotocol/common-utils' +import { AutoRow } from '@cowprotocol/ui' +import { ExternalLink } from '@cowprotocol/ui' + import { Trans } from '@lingui/macro' import styled from 'styled-components/macro' -import CowError from 'legacy/assets/cow-swap/CowError.png' import { AutoColumn } from 'legacy/components/Column' -import { AutoRow } from 'legacy/components/Row' -import { CODE_LINK, DISCORD_LINK } from 'legacy/constants' -import store, { AppState } from 'legacy/state' +import { cowSwapStore, AppState } from 'legacy/state' import { MEDIA_WIDTHS, ThemedText } from 'legacy/theme' -import { ExternalLink } from 'legacy/theme' -import { userAgent } from 'legacy/utils/userAgent' import { Title } from 'modules/application/pure/Page' +import { UI } from 'common/constants/theme' + const FlexContainer = styled.div` display: flex; align-items: center; @@ -37,14 +40,14 @@ const StyledParagraph = styled.p` ` const CodeBlockWrapper = styled.div` - background: ${({ theme }) => theme.bg1}; + background: var(${UI.COLOR_CONTAINER_BG_01}); overflow: auto; white-space: pre; box-shadow: 0px 0px 1px rgba(0, 0, 0, 0.01), 0px 4px 8px rgba(0, 0, 0, 0.04), 0px 16px 24px rgba(0, 0, 0, 0.04), 0px 24px 32px rgba(0, 0, 0, 0.01); border-radius: 16px; padding: 16px; - color: ${({ theme }) => theme.text2}; + color: var(${UI.COLOR_TEXT2}); /* MOD */ ${({ theme }) => theme.mediaWidth.upToSmall` @@ -143,7 +146,7 @@ ${ ? `## \`${relevantState}\` state \`\`\`json -${JSON.stringify(store.getState()[relevantState], null, 2)} +${JSON.stringify(cowSwapStore.getState()[relevantState], null, 2)} \`\`\` ` : '' diff --git a/apps/cowswap-frontend/src/legacy/components/ErrorBoundary/index.tsx b/apps/cowswap-frontend/src/legacy/components/ErrorBoundary/index.tsx index 0e6c5343ae..74d286ca67 100644 --- a/apps/cowswap-frontend/src/legacy/components/ErrorBoundary/index.tsx +++ b/apps/cowswap-frontend/src/legacy/components/ErrorBoundary/index.tsx @@ -1,5 +1,7 @@ import React, { ErrorInfo, PropsWithChildren } from 'react' +import { sendError } from '@cowprotocol/analytics' + import * as Sentry from '@sentry/react' import styled from 'styled-components/macro' @@ -13,8 +15,6 @@ import { Page } from 'modules/application/pure/Page' import { Routes } from 'common/constants/routes' -import { sendError } from '../analytics/googleAnalytics' - type ErrorBoundaryState = { error: Error | null } diff --git a/apps/cowswap-frontend/src/legacy/components/ExplorerLink/index.tsx b/apps/cowswap-frontend/src/legacy/components/ExplorerLink/index.tsx index ac4f142808..6f3974491c 100644 --- a/apps/cowswap-frontend/src/legacy/components/ExplorerLink/index.tsx +++ b/apps/cowswap-frontend/src/legacy/components/ExplorerLink/index.tsx @@ -1,13 +1,10 @@ import { PropsWithChildren } from 'react' +import { getExplorerLabel, getEtherscanLink } from '@cowprotocol/common-utils' +import { getSafeWebUrl } from '@cowprotocol/core' import { SupportedChainId } from '@cowprotocol/cow-sdk' - -import { ExternalLink } from 'legacy/theme' -import { getExplorerLabel, getEtherscanLink } from 'legacy/utils' - -import { useWalletInfo } from 'modules/wallet' - -import { getSafeWebUrl } from 'api/gnosisSafe' +import { ExternalLink } from '@cowprotocol/ui' +import { useWalletInfo } from '@cowprotocol/wallet' interface PropsBase extends PropsWithChildren { // type?: BlockExplorerLinkType diff --git a/apps/cowswap-frontend/src/legacy/components/FlashingLoading/index.tsx b/apps/cowswap-frontend/src/legacy/components/FlashingLoading/index.tsx index 68fab5b798..8658299810 100644 --- a/apps/cowswap-frontend/src/legacy/components/FlashingLoading/index.tsx +++ b/apps/cowswap-frontend/src/legacy/components/FlashingLoading/index.tsx @@ -1,8 +1,10 @@ +import CowIcon from '@cowprotocol/assets/cow-swap/cowprotocol.svg' + import { transparentize } from 'polished' import SVG from 'react-inlinesvg' import styled from 'styled-components/macro' -import CowIcon from 'legacy/assets/cow-swap/cowprotocol.svg' +import { UI } from 'common/constants/theme' export const LoadingWrapper = styled.div` display: flex; @@ -25,7 +27,7 @@ export const LoadingWrapper = styled.div` } > svg > g { - fill: ${({ theme }) => theme.text2}; + fill: var(${UI.COLOR_TEXT2}); } > span { @@ -35,7 +37,7 @@ export const LoadingWrapper = styled.div` font-weight: 500; letter-spacing: 2px; margin: 5px auto 0; - color: ${({ theme }) => theme.text2}; + color: var(${UI.COLOR_TEXT2}); } @keyframes pulse { diff --git a/apps/cowswap-frontend/src/legacy/components/Header/ChainConnectivityWarning.tsx b/apps/cowswap-frontend/src/legacy/components/Header/ChainConnectivityWarning.tsx index 69948f4085..05491ca721 100644 --- a/apps/cowswap-frontend/src/legacy/components/Header/ChainConnectivityWarning.tsx +++ b/apps/cowswap-frontend/src/legacy/components/Header/ChainConnectivityWarning.tsx @@ -1,14 +1,13 @@ +import { getChainInfo } from '@cowprotocol/common-const' import { SupportedChainId } from '@cowprotocol/cow-sdk' +import { useWalletInfo } from '@cowprotocol/wallet' import { Trans } from '@lingui/macro' import { AlertOctagon } from 'react-feather' import styled from 'styled-components/macro' -import { getChainInfo } from 'legacy/constants/chainInfo' import { MEDIA_WIDTHS } from 'legacy/theme' -import { useWalletInfo } from 'modules/wallet' - const BodyRow = styled.div` color: ${({ theme }) => theme.black}; font-size: 12px; diff --git a/apps/cowswap-frontend/src/legacy/components/Header/MobileMenuIcon/index.tsx b/apps/cowswap-frontend/src/legacy/components/Header/MobileMenuIcon/index.tsx index 393e7ffe99..b14fe517b5 100644 --- a/apps/cowswap-frontend/src/legacy/components/Header/MobileMenuIcon/index.tsx +++ b/apps/cowswap-frontend/src/legacy/components/Header/MobileMenuIcon/index.tsx @@ -1,5 +1,7 @@ import styled, { css } from 'styled-components/macro' +import { UI } from 'common/constants/theme' + const Wrapper = styled.div<{ isMobileMenuOpen: boolean; height?: number; width?: number; lineSize?: number }>` z-index: 102; display: flex; @@ -10,7 +12,7 @@ const Wrapper = styled.div<{ isMobileMenuOpen: boolean; height?: number; width?: height: ${({ height = 18 }) => `${height}px`}; span { - background-color: ${({ theme }) => theme.text1}; + background-color: var(${UI.COLOR_TEXT1}); border-radius: 3px; height: ${({ lineSize = 2 }) => `${lineSize}px`}; position: absolute; diff --git a/apps/cowswap-frontend/src/legacy/components/Header/NetworkSelector/index.tsx b/apps/cowswap-frontend/src/legacy/components/Header/NetworkSelector/index.tsx index 3b47456c5c..eb6cf28201 100644 --- a/apps/cowswap-frontend/src/legacy/components/Header/NetworkSelector/index.tsx +++ b/apps/cowswap-frontend/src/legacy/components/Header/NetworkSelector/index.tsx @@ -1,5 +1,7 @@ import { useRef } from 'react' +import { getChainInfo } from '@cowprotocol/common-const' +import { useWalletInfo, getIsTallyWallet, useIsSmartContractWallet } from '@cowprotocol/wallet' import { useWeb3React } from '@web3-react/core' import { Trans } from '@lingui/macro' @@ -7,22 +9,18 @@ import { transparentize, darken } from 'polished' import { AlertTriangle, ChevronDown } from 'react-feather' import styled from 'styled-components/macro' -import { getChainInfo } from 'legacy/constants/chainInfo' import { useMediaQuery, upToMedium } from 'legacy/hooks/useMediaQuery' import { useCloseModal, useModalIsOpen, useOpenModal, useToggleModal } from 'legacy/state/application/hooks' import { ApplicationModal } from 'legacy/state/application/reducer' import { MEDIA_WIDTHS } from 'legacy/theme' -import { useWalletInfo } from 'modules/wallet' -import { getIsTallyWallet } from 'modules/wallet/api/utils/connection' - +import { UI } from 'common/constants/theme' import { useIsProviderNetworkUnsupported } from 'common/hooks/useIsProviderNetworkUnsupported' -import { useIsSmartContractWallet } from 'common/hooks/useIsSmartContractWallet' import { useOnSelectNetwork } from 'common/hooks/useOnSelectNetwork' import { NetworksList } from 'common/pure/NetworksList' const FlyoutHeader = styled.div` - color: ${({ theme }) => theme.text1}; + color: var(${UI.COLOR_TEXT1}); font-weight: 400; ` @@ -43,7 +41,7 @@ const FlyoutMenu = styled.div` const FlyoutMenuContents = styled.div` align-items: flex-start; - background-color: ${({ theme }) => theme.bg1}; + background-color: var(${UI.COLOR_CONTAINER_BG_01}); border: 1px solid ${({ theme }) => theme.bg0}; box-shadow: 0px 0px 1px rgba(0, 0, 0, 0.01), 0px 4px 8px rgba(0, 0, 0, 0.04), 0px 16px 24px rgba(0, 0, 0, 0.04), 0px 24px 32px rgba(0, 0, 0, 0.01); @@ -82,7 +80,7 @@ const SelectorLabel = styled.div` ` const SelectorControls = styled.div<{ isChainIdUnsupported: boolean }>` align-items: center; - color: ${({ theme }) => theme.text1}; + color: var(${UI.COLOR_TEXT1}); display: flex; font-weight: 500; justify-content: space-between; diff --git a/apps/cowswap-frontend/src/legacy/components/Header/Polling.tsx b/apps/cowswap-frontend/src/legacy/components/Header/Polling.tsx index f340cda3f0..1e22b2748b 100644 --- a/apps/cowswap-frontend/src/legacy/components/Header/Polling.tsx +++ b/apps/cowswap-frontend/src/legacy/components/Header/Polling.tsx @@ -1,27 +1,25 @@ import { useEffect, useState } from 'react' +import { getChainInfo } from '@cowprotocol/common-const' +import { useBlockNumber, useMachineTimeMs, useTheme } from '@cowprotocol/common-hooks' +import { ExplorerDataType, getExplorerLink } from '@cowprotocol/common-utils' +import { RowFixed } from '@cowprotocol/ui' +import { MouseoverTooltip, ExternalLink } from '@cowprotocol/ui' +import { useWalletInfo } from '@cowprotocol/wallet' + import { Trans } from '@lingui/macro' import JSBI from 'jsbi' import ms from 'ms.macro' import styled, { keyframes } from 'styled-components/macro' -import { RowFixed } from 'legacy/components/Row' -import { getChainInfo } from 'legacy/constants/chainInfo' import useCurrentBlockTimestamp from 'legacy/hooks/useCurrentBlockTimestamp' import useGasPrice from 'legacy/hooks/useGasPrice' -import useMachineTimeMs from 'legacy/hooks/useMachineTime' -import useTheme from 'legacy/hooks/useTheme' -import { ExternalLink, ThemedText } from 'legacy/theme' -import { ExplorerDataType, getExplorerLink } from 'legacy/utils/getExplorerLink' - -import { useWalletInfo } from 'modules/wallet' +import { ThemedText } from 'legacy/theme' -import useBlockNumber from 'lib/hooks/useBlockNumber' +import { UI } from 'common/constants/theme' import { ChainConnectivityWarning } from './ChainConnectivityWarning' -import { MouseoverTooltip } from '../Tooltip' - export const StyledPolling = styled.div<{ warning: boolean }>` position: fixed; display: flex; @@ -103,7 +101,7 @@ export const Spinner = styled.div<{ warning: boolean }>` const Wrapper = styled.div` ${StyledPolling} { - color: ${({ theme }) => theme.text1}; + color: var(${UI.COLOR_TEXT1}); position: relative; margin: 0; padding: 0; @@ -113,7 +111,7 @@ const Wrapper = styled.div` opacity: 1; a { - color: ${({ theme }) => theme.text1}; + color: var(${UI.COLOR_TEXT1}); opacity: 0.5; transition: opacity 0.3s ease-in-out; text-decoration: none; @@ -130,7 +128,7 @@ const Wrapper = styled.div` ${StyledPollingNumber} > a { opacity: 1; - color: ${({ theme }) => theme.text1}; + color: var(${UI.COLOR_TEXT1}); &:hover { opacity: 1; @@ -141,7 +139,7 @@ const Wrapper = styled.div` ${StyledGasDot}, ${StyledPollingDot} { - background: ${({ theme }) => theme.text1}; + background: var(${UI.COLOR_TEXT1}); } ${StyledPollingDot} { diff --git a/apps/cowswap-frontend/src/legacy/components/Header/URLWarning/index.tsx b/apps/cowswap-frontend/src/legacy/components/Header/URLWarning/index.tsx index 83b6e26846..e55c067e71 100644 --- a/apps/cowswap-frontend/src/legacy/components/Header/URLWarning/index.tsx +++ b/apps/cowswap-frontend/src/legacy/components/Header/URLWarning/index.tsx @@ -1,15 +1,14 @@ +import { useFetchFile } from '@cowprotocol/common-hooks' +import { hashCode } from '@cowprotocol/common-utils' +import { environmentName } from '@cowprotocol/common-utils' import { SupportedChainId as ChainId } from '@cowprotocol/cow-sdk' +import { useWalletInfo } from '@cowprotocol/wallet' import { AlertTriangle } from 'react-feather' import styled from 'styled-components/macro' import { Markdown } from 'legacy/components/Markdown' -import useFetchFile from 'legacy/hooks/useFetchFile' import { useAnnouncementVisible, useCloseAnnouncement } from 'legacy/state/profile/hooks' -import { environmentName } from 'legacy/utils/environments' -import { hashCode } from 'legacy/utils/misc' - -import { useWalletInfo } from 'modules/wallet' import URLWarningUni, { PhishAlert, StyledClose } from './URLWarningMod' diff --git a/apps/cowswap-frontend/src/legacy/components/Header/index.tsx b/apps/cowswap-frontend/src/legacy/components/Header/index.tsx index 1c217fa842..ced341809e 100644 --- a/apps/cowswap-frontend/src/legacy/components/Header/index.tsx +++ b/apps/cowswap-frontend/src/legacy/components/Header/index.tsx @@ -1,32 +1,34 @@ import React, { useCallback, useEffect, useMemo, useState } from 'react' +import { toggleDarkModeAnalytics } from '@cowprotocol/analytics' +import { isInjectedWidget } from '@cowprotocol/common-utils' +import { addBodyClass, removeBodyClass } from '@cowprotocol/common-utils' import { SupportedChainId as ChainId, SupportedChainId } from '@cowprotocol/cow-sdk' +import { TokenAmount } from '@cowprotocol/ui' +import { useWalletInfo } from '@cowprotocol/wallet' import SVG from 'react-inlinesvg' import { useNavigate } from 'react-router-dom' -import { toggleDarkModeAnalytics } from 'legacy/components/analytics' import CowBalanceButton from 'legacy/components/CowBalanceButton' import { NetworkSelector } from 'legacy/components/Header/NetworkSelector' import { LargeAndUp, upToLarge, upToMedium, upToSmall, useMediaQuery } from 'legacy/hooks/useMediaQuery' import { useDarkModeManager } from 'legacy/state/user/hooks' import { cowSwapLogo } from 'legacy/theme/cowSwapAssets' -import { addBodyClass, removeBodyClass } from 'legacy/utils/toggleBodyClass' import { OrdersPanel } from 'modules/account/containers/OrdersPanel' import { useInjectedWidgetParams } from 'modules/injectedWidget' -import { MainMenuContext, useMenuItems } from 'modules/mainMenu' +import { MainMenuContext } from 'modules/mainMenu' import { MenuTree } from 'modules/mainMenu/pure/MenuTree' import { useSwapRawState } from 'modules/swap/hooks/useSwapRawState' import { useNativeCurrencyBalances } from 'modules/tokens/hooks/useCurrencyBalance' import { useTradeState } from 'modules/trade/hooks/useTradeState' import { getDefaultTradeRawState } from 'modules/trade/types/TradeRawState' -import { useWalletInfo, Web3Status } from 'modules/wallet' +import { Web3Status } from 'modules/wallet/containers/Web3Status' import { Routes } from 'common/constants/routes' +import { useCategorizeRecentActivity } from 'common/hooks/useCategorizeRecentActivity' import { useIsProviderNetworkUnsupported } from 'common/hooks/useIsProviderNetworkUnsupported' -import { TokenAmount } from 'common/pure/TokenAmount' -import { isInjectedWidget } from 'common/utils/isInjectedWidget' import MobileMenuIcon from './MobileMenuIcon' import { @@ -54,6 +56,7 @@ export default function Header() { const isChainIdUnsupported = useIsProviderNetworkUnsupported() + const { pendingActivity } = useCategorizeRecentActivity() const userEthBalance = useNativeCurrencyBalances(account ? [account] : [])?.[account ?? ''] const nativeToken = CHAIN_CURRENCY_LABELS[chainId] || 'ETH' const [darkMode, toggleDarkModeAux] = useDarkModeManager() @@ -73,8 +76,6 @@ export default function Header() { !isOrdersPanelOpen && removeBodyClass('noScroll') } - const menuItems = useMenuItems() - const navigate = useNavigate() const isUpToLarge = useMediaQuery(upToLarge) @@ -139,9 +140,7 @@ export default function Header() { )} - {!isInjectedWidgetMode && ( - - )} + {!isInjectedWidgetMode && } @@ -163,7 +162,7 @@ export default function Header() { )} - + diff --git a/apps/cowswap-frontend/src/legacy/components/Header/styled.tsx b/apps/cowswap-frontend/src/legacy/components/Header/styled.tsx index 722d706963..0bdfd8fef0 100644 --- a/apps/cowswap-frontend/src/legacy/components/Header/styled.tsx +++ b/apps/cowswap-frontend/src/legacy/components/Header/styled.tsx @@ -1,5 +1,7 @@ import { PropsWithChildren } from 'react' +import { Row, RowFixed } from '@cowprotocol/ui' + import useScrollPosition from '@react-hook/window-scroll' import { transparentize, darken } from 'polished' import { NavLink } from 'react-router-dom' @@ -7,7 +9,8 @@ import { Text } from 'rebass' import styled, { css } from 'styled-components/macro' import { MenuFlyout, MenuSection, Content as MenuContent, MenuTitle } from 'legacy/components/MenuDropdown/styled' -import Row, { RowFixed } from 'legacy/components/Row' + +import { UI } from 'common/constants/theme' const activeClassName = 'active' @@ -77,7 +80,7 @@ export const StyledNavLinkUni = styled(NavLink)` outline: none; cursor: pointer; text-decoration: none; - color: ${({ theme }) => theme.text2}; + color: var(${UI.COLOR_TEXT2}); font-size: 1rem; width: fit-content; margin: 0 12px; @@ -85,7 +88,7 @@ export const StyledNavLinkUni = styled(NavLink)` &.${activeClassName} { border-radius: 12px; font-weight: 600; - color: ${({ theme }) => theme.text1}; + color: var(${UI.COLOR_TEXT1}); } :hover, @@ -119,7 +122,7 @@ export const StyledMenuButton = styled.button` margin-top: 2px; } > * { - stroke: ${({ theme }) => theme.text1}; + stroke: var(${UI.COLOR_TEXT1}); } ` @@ -177,7 +180,7 @@ export const StyledNavLink = styled(StyledNavLinkUni)` &:hover, &:focus { - color: ${({ theme }) => theme.text1}; + color: var(${UI.COLOR_TEXT1}); } ` @@ -223,7 +226,7 @@ export const HeaderElement = styled(HeaderElementUni)` width: 100%; border-radius: 0; height: 64px; - background-color: ${({ theme }) => theme.bg1}; + background-color: var(${UI.COLOR_CONTAINER_BG_01}); border-top: 1px solid ${({ theme }) => theme.grey1}; backdrop-filter: blur(21px); padding: 10px 16px; @@ -253,7 +256,7 @@ export const Wrapper = styled.div<{ isMobileMenuOpen: boolean }>` width: 100%; display: flex; height: 60px; - background: ${({ theme }) => theme.bg1}; + background: var(${UI.COLOR_CONTAINER_BG_01}); position: fixed; top: 0; left: 0; @@ -283,7 +286,7 @@ export const HeaderModWrapper = styled(HeaderMod)`` export const Title = styled(TitleMod)<{ isMobileMenuOpen: boolean }>` margin: 0; text-decoration: none; - color: ${({ theme }) => theme.text1}; + color: var(${UI.COLOR_TEXT1}); ${({ theme, isMobileMenuOpen }) => theme.mediaWidth.upToLarge` ${ @@ -315,7 +318,7 @@ export const HeaderLinks = styled(HeaderLinksMod)<{ isMobileMenuOpen: boolean }> cursor: pointer; background: transparent; transition: background 0.15s ease-in-out, color 0.15s ease-in-out; - color: ${({ theme }) => theme.text2}; + color: var(${UI.COLOR_TEXT2}); ${({ theme }) => theme.mediaWidth.upToLarge` width: 100%; @@ -324,17 +327,17 @@ export const HeaderLinks = styled(HeaderLinksMod)<{ isMobileMenuOpen: boolean }> font-weight: 600; font-size: 17px; padding: 28px 10px; - color: ${({ theme }) => theme.text1}; + color: var(${UI.COLOR_TEXT1}); border-bottom: 1px solid ${({ theme }) => transparentize(0.9, theme.text1)}; `}; > svg > path { - fill: ${({ theme }) => theme.text2}; + fill: var(${UI.COLOR_TEXT2}); transition: fill 0.15s ease-in-out; } &:hover { - color: ${({ theme }) => theme.text1}; + color: var(${UI.COLOR_TEXT1}); background: ${({ theme }) => transparentize(0.95, theme.text1)}; ${({ theme }) => theme.mediaWidth.upToLarge` @@ -342,7 +345,7 @@ export const HeaderLinks = styled(HeaderLinksMod)<{ isMobileMenuOpen: boolean }> `}; > svg > path { - fill: ${({ theme }) => theme.text1}; + fill: var(${UI.COLOR_TEXT1}); } } @@ -357,7 +360,7 @@ export const HeaderLinks = styled(HeaderLinksMod)<{ isMobileMenuOpen: boolean }> } &.ACTIVE { - color: ${({ theme }) => theme.text1}; + color: var(${UI.COLOR_TEXT1}); font-weight: 600; } } @@ -407,7 +410,7 @@ export const HeaderLinks = styled(HeaderLinksMod)<{ isMobileMenuOpen: boolean }> left: 0; bottom: 0; z-index: 3; - background: ${({ theme }) => theme.bg1}; + background: var(${UI.COLOR_CONTAINER_BG_01}); outline: 0; padding: 60px 8px; overflow-x: hidden; @@ -447,11 +450,11 @@ export const TwitterLink = styled(StyledMenuButton)` } > a > svg > path { - fill: ${({ theme }) => theme.text1}; + fill: var(${UI.COLOR_TEXT1}); } > a:hover > svg > path { - fill: ${({ theme }) => theme.text1}; + fill: var(${UI.COLOR_TEXT1}); } ` diff --git a/apps/cowswap-frontend/src/legacy/components/HoverInlineText/index.tsx b/apps/cowswap-frontend/src/legacy/components/HoverInlineText/index.tsx index b7351ee304..1f4b44e51f 100644 --- a/apps/cowswap-frontend/src/legacy/components/HoverInlineText/index.tsx +++ b/apps/cowswap-frontend/src/legacy/components/HoverInlineText/index.tsx @@ -1,8 +1,8 @@ import { useState } from 'react' -import styled from 'styled-components/macro' +import { Tooltip } from '@cowprotocol/ui' -import Tooltip from 'legacy/components/Tooltip' +import styled from 'styled-components/macro' export const TextWrapper = styled.span<{ margin: boolean diff --git a/apps/cowswap-frontend/src/legacy/components/InfoIcon/index.tsx b/apps/cowswap-frontend/src/legacy/components/InfoIcon/index.tsx index 739716c0c2..39a7acc21e 100644 --- a/apps/cowswap-frontend/src/legacy/components/InfoIcon/index.tsx +++ b/apps/cowswap-frontend/src/legacy/components/InfoIcon/index.tsx @@ -1,19 +1,25 @@ import { ReactNode } from 'react' -import { Info } from 'react-feather' +import { MouseoverTooltipContent, TooltipContainer } from '@cowprotocol/ui' + +import { Info, HelpCircle } from 'react-feather' import styled from 'styled-components/macro' -import { MouseoverTooltipContent, TooltipContainer } from 'legacy/components/Tooltip' +import { UI } from 'common/constants/theme' + +const StyledIcon = styled.div` + display: inline-block; -const StyledInfoIcon = styled(Info)` - opacity: 0.5; - stroke: ${({ theme }) => theme.text1}; - line-height: 0; - vertical-align: middle; - transition: opacity 0.2s ease-in-out; + > svg { + opacity: 0.5; + stroke: var(${UI.COLOR_TEXT1}); + line-height: 0; + vertical-align: middle; + transition: opacity 0.2s ease-in-out; - :hover { - opacity: 1; + :hover { + opacity: 1; + } } ` @@ -26,15 +32,22 @@ const StyledTooltipContainer = styled(TooltipContainer)` export interface InfoIconProps { content: ReactNode + iconType?: 'info' | 'help' className?: string } -export function InfoIcon(props: InfoIconProps) { - const content = {props.content} +export function InfoIcon({ content, iconType = 'info', className }: InfoIconProps) { + const tooltipContent = {content} return ( - - + + + {iconType === 'info' ? ( + + ) : ( + + )} + ) } diff --git a/apps/cowswap-frontend/src/legacy/components/Link/index.tsx b/apps/cowswap-frontend/src/legacy/components/Link/index.tsx index 192a934994..ce16f3850f 100644 --- a/apps/cowswap-frontend/src/legacy/components/Link/index.tsx +++ b/apps/cowswap-frontend/src/legacy/components/Link/index.tsx @@ -1,7 +1,7 @@ +import { ExternalLink } from '@cowprotocol/ui' + import HashLink from 'legacy/components/HashLink' -import { ExternalLink } from 'legacy/theme' -export { ExternalLink } from 'legacy/theme' const SCROLL_OFFSET = 24 export interface LinkRendererProps { diff --git a/apps/cowswap-frontend/src/legacy/components/ListLogo/index.tsx b/apps/cowswap-frontend/src/legacy/components/ListLogo/index.tsx index f74c6891cc..f14a5d1def 100644 --- a/apps/cowswap-frontend/src/legacy/components/ListLogo/index.tsx +++ b/apps/cowswap-frontend/src/legacy/components/ListLogo/index.tsx @@ -2,8 +2,9 @@ import React from 'react' import styled from 'styled-components/macro' +import Logo from 'legacy/components/Loader/Logo' + import useHttpLocations from '../../hooks/useHttpLocations' -import Logo from '../Logo' export const StyledListLogo = styled(Logo)<{ size: string }>` width: ${({ size }) => size}; diff --git a/apps/cowswap-frontend/src/legacy/components/Logo/index.tsx b/apps/cowswap-frontend/src/legacy/components/Loader/Logo/index.tsx similarity index 94% rename from apps/cowswap-frontend/src/legacy/components/Logo/index.tsx rename to apps/cowswap-frontend/src/legacy/components/Loader/Logo/index.tsx index 1608d514b0..1f55d85414 100644 --- a/apps/cowswap-frontend/src/legacy/components/Logo/index.tsx +++ b/apps/cowswap-frontend/src/legacy/components/Loader/Logo/index.tsx @@ -1,10 +1,10 @@ import { useState } from 'react' +import { useTheme } from '@cowprotocol/common-hooks' + import { Slash } from 'react-feather' import { ImageProps } from 'rebass' -import useTheme from '../../hooks/useTheme' - const BAD_SRCS: { [tokenAddress: string]: true } = {} export interface LogoProps extends Pick { diff --git a/apps/cowswap-frontend/src/legacy/components/Markdown/index.tsx b/apps/cowswap-frontend/src/legacy/components/Markdown/index.tsx index 516a2f8915..5b7bc15e28 100644 --- a/apps/cowswap-frontend/src/legacy/components/Markdown/index.tsx +++ b/apps/cowswap-frontend/src/legacy/components/Markdown/index.tsx @@ -1,15 +1,13 @@ import { ReactNode } from 'react' +import { useFetchFile } from '@cowprotocol/common-hooks' + import ReactMarkdown, { ReactMarkdownPropsBase } from 'react-markdown' import ReactMarkdownHtml from 'react-markdown/with-html' import styled from 'styled-components/macro' import { WithClassName } from 'types' -// AmplitudeAnalytics -import { PageName } from 'legacy/components/AmplitudeAnalytics/constants' -import { Trace } from 'legacy/components/AmplitudeAnalytics/Trace' import { LinkScrollable, Link } from 'legacy/components/Link' -import useFetchFile from 'legacy/hooks/useFetchFile' import { Page, Title, Content } from 'modules/application/pure/Page' @@ -34,7 +32,7 @@ const MarkdownContent = (props: ReactMarkdownPropsBase & { children: string }) = export function MarkdownPage({ contentFile, title, className }: MarkdownParams) { const { error, file } = useFetchFile(contentFile) return ( - + <> {title && {title}} @@ -42,6 +40,6 @@ export function MarkdownPage({ contentFile, title, className }: MarkdownParams) {error && {error}} - + ) } diff --git a/apps/cowswap-frontend/src/legacy/components/MenuDropdown/index.tsx b/apps/cowswap-frontend/src/legacy/components/MenuDropdown/index.tsx index 55b7dd1a78..0d6f5372d3 100644 --- a/apps/cowswap-frontend/src/legacy/components/MenuDropdown/index.tsx +++ b/apps/cowswap-frontend/src/legacy/components/MenuDropdown/index.tsx @@ -1,10 +1,11 @@ import { useState, useRef } from 'react' +import IMAGE_CARRET_DOWN from '@cowprotocol/assets/cow-swap/carret-down.svg' +import { useOnClickOutside } from '@cowprotocol/common-hooks' + import SVG from 'react-inlinesvg' -import IMAGE_CARRET_DOWN from 'legacy/assets/cow-swap/carret-down.svg' import { useMediaQuery, LargeAndUp } from 'legacy/hooks/useMediaQuery' -import { useOnClickOutside } from 'legacy/hooks/useOnClickOutside' import { MenuFlyout, Content } from './styled' diff --git a/apps/cowswap-frontend/src/legacy/components/MenuDropdown/styled.ts b/apps/cowswap-frontend/src/legacy/components/MenuDropdown/styled.ts index 5ce1c5fa51..a772f40a3f 100644 --- a/apps/cowswap-frontend/src/legacy/components/MenuDropdown/styled.ts +++ b/apps/cowswap-frontend/src/legacy/components/MenuDropdown/styled.ts @@ -1,6 +1,8 @@ import { transparentize } from 'polished' import styled from 'styled-components/macro' +import { UI } from 'common/constants/theme' + export const MenuFlyout = styled.ol` display: flex; padding: 0; @@ -50,7 +52,7 @@ export const Content = styled.div` left: 0; border-radius: 16px; border: 1px solid ${({ theme }) => transparentize(0.6, theme.white)}; - background: ${({ theme }) => theme.bg1}; + background: var(${UI.COLOR_CONTAINER_BG_01}); box-shadow: ${({ theme }) => theme.boxShadow2}; padding: 32px; gap: 62px; @@ -107,7 +109,7 @@ export const MenuSection = styled.div` font-weight: 500; margin: 0; padding: 0; - color: ${({ theme }) => theme.text1}; + color: var(${UI.COLOR_TEXT1}); opacity: 0.8; transition: opacity 0.15s ease-in-out; @@ -118,11 +120,11 @@ export const MenuSection = styled.div` max-height: 21px; margin: 0 7px 0 0; object-fit: contain; - color: ${({ theme }) => theme.text1}; + color: var(${UI.COLOR_TEXT1}); } > svg > path { - fill: ${({ theme }) => theme.text1}; + fill: var(${UI.COLOR_TEXT1}); } &:hover { diff --git a/apps/cowswap-frontend/src/legacy/components/NetworkAlert/NetworkAlert.tsx b/apps/cowswap-frontend/src/legacy/components/NetworkAlert/NetworkAlert.tsx index c277515592..42fc0b07ea 100644 --- a/apps/cowswap-frontend/src/legacy/components/NetworkAlert/NetworkAlert.tsx +++ b/apps/cowswap-frontend/src/legacy/components/NetworkAlert/NetworkAlert.tsx @@ -1,17 +1,19 @@ +import { getChainInfo } from '@cowprotocol/common-const' +import { useTheme } from '@cowprotocol/common-hooks' import { SupportedChainId } from '@cowprotocol/cow-sdk' +import { AutoRow } from '@cowprotocol/ui' +import { ExternalLink } from '@cowprotocol/ui' +import { useWalletInfo } from '@cowprotocol/wallet' import { Trans } from '@lingui/macro' import { transparentize } from 'polished' import { ArrowUpRight } from 'react-feather' import styled from 'styled-components/macro' -import { AutoRow } from 'legacy/components/Row' -import { getChainInfo } from 'legacy/constants/chainInfo' -import useTheme from 'legacy/hooks/useTheme' import { useDarkModeManager } from 'legacy/state/user/hooks' -import { ExternalLink, HideSmall } from 'legacy/theme' +import { HideSmall } from 'legacy/theme' -import { useWalletInfo } from 'modules/wallet' +import { UI } from 'common/constants/theme' const L2Icon = styled.img` width: 24px; @@ -74,19 +76,19 @@ const ContentWrapper = styled.div<{ chainId: NetworkAlertChains; darkMode: boole ${BodyText}, ${StyledArrowUpRight} { - color: ${({ theme }) => theme.text2}; - stroke: ${({ theme }) => theme.text2}; + color: var(${UI.COLOR_TEXT2}); + stroke: var(${UI.COLOR_TEXT2}); text-decoration: none; transition: transform 0.2s ease-in-out, stroke 0.2s ease-in-out, color 0.2s ease-in-out; } &:hover { - background: ${({ theme }) => theme.bg1}; + background: var(${UI.COLOR_CONTAINER_BG_01}); ${BodyText}, ${StyledArrowUpRight} { - color: ${({ theme }) => theme.text1}; - stroke: ${({ theme }) => theme.text1}; + color: var(${UI.COLOR_TEXT1}); + stroke: var(${UI.COLOR_TEXT1}); transform: rotate(0); } diff --git a/apps/cowswap-frontend/src/legacy/components/NetworkAlert/styles.ts b/apps/cowswap-frontend/src/legacy/components/NetworkAlert/styles.ts index 9241855a54..3e9a04a57d 100644 --- a/apps/cowswap-frontend/src/legacy/components/NetworkAlert/styles.ts +++ b/apps/cowswap-frontend/src/legacy/components/NetworkAlert/styles.ts @@ -1,8 +1,10 @@ +import { ExternalLink } from '@cowprotocol/ui' + import styled from 'styled-components/macro' -import { ExternalLink } from 'legacy/theme' +import { UI } from 'common/constants/theme' export const ReadMoreLink = styled(ExternalLink)` - color: ${({ theme }) => theme.text1}; + color: var(${UI.COLOR_TEXT1}); text-decoration: underline; ` diff --git a/apps/cowswap-frontend/src/legacy/components/NumericalInput/index.tsx b/apps/cowswap-frontend/src/legacy/components/NumericalInput/index.tsx index 6d63de857e..40f25d7239 100644 --- a/apps/cowswap-frontend/src/legacy/components/NumericalInput/index.tsx +++ b/apps/cowswap-frontend/src/legacy/components/NumericalInput/index.tsx @@ -1,11 +1,12 @@ import React from 'react' +import { escapeRegExp } from '@cowprotocol/common-utils' + import styled from 'styled-components/macro' +import { UI } from 'common/constants/theme' import { autofocus } from 'common/utils/autofocus' -import { escapeRegExp } from '../../utils' - const StyledInput = styled.input<{ error?: boolean; fontSize?: string; align?: string }>` color: ${({ error, theme }) => (error ? theme.red1 : theme.text1)}; width: 0; @@ -14,7 +15,7 @@ const StyledInput = styled.input<{ error?: boolean; fontSize?: string; align?: s outline: none; border: none; flex: 1 1 auto; - background-color: ${({ theme }) => theme.bg1}; + background-color: var(${UI.COLOR_CONTAINER_BG_01}); font-size: ${({ fontSize }) => fontSize ?? '28px'}; text-align: ${({ align }) => align && align}; white-space: nowrap; diff --git a/apps/cowswap-frontend/src/legacy/components/OrderProgressBar/index.tsx b/apps/cowswap-frontend/src/legacy/components/OrderProgressBar/index.tsx index b277aec583..c92a266a40 100644 --- a/apps/cowswap-frontend/src/legacy/components/OrderProgressBar/index.tsx +++ b/apps/cowswap-frontend/src/legacy/components/OrderProgressBar/index.tsx @@ -1,24 +1,24 @@ import { useEffect, useMemo, useState } from 'react' +import loadingCowWebp from '@cowprotocol/assets/cow-swap/cow-load.webp' +import ammsGraphGC from '@cowprotocol/assets/images/amms-graph-gc.svg' +import ammsGraphEth from '@cowprotocol/assets/images/amms-graph.svg' +import cowGraph from '@cowprotocol/assets/images/cow-graph.svg' +import cowMeditatingSmooth from '@cowprotocol/assets/images/cow-meditating-smoooth.svg' +import cowMeditatingGraph from '@cowprotocol/assets/images/cow-meditating.svg' +import { getExplorerOrderLink } from '@cowprotocol/common-utils' import { SupportedChainId } from '@cowprotocol/cow-sdk' +import { useIsSmartContractWallet } from '@cowprotocol/wallet' import { useTransition } from '@react-spring/web' import ms from 'ms.macro' -import loadingCowWebp from 'legacy/assets/cow-swap/cow-load.webp' -import ammsGraphGC from 'legacy/assets/images/amms-graph-gc.svg' -import ammsGraphEth from 'legacy/assets/images/amms-graph.svg' -import cowGraph from 'legacy/assets/images/cow-graph.svg' -import cowMeditatingSmooth from 'legacy/assets/images/cow-meditating-smoooth.svg' -import cowMeditatingGraph from 'legacy/assets/images/cow-meditating.svg' import { AMMsLogo } from 'legacy/components/AMMsLogo' import { EXPECTED_EXECUTION_TIME, getPercentage } from 'legacy/components/OrderProgressBar/utils' -import { getExplorerOrderLink } from 'legacy/utils/explorer' import { ActivityDerivedState } from 'modules/account/containers/Transaction' import { useCancelOrder } from 'common/hooks/useCancelOrder' -import { useIsSmartContractWallet } from 'common/hooks/useIsSmartContractWallet' import { CancelButton } from 'common/pure/CancelButton' import { diff --git a/apps/cowswap-frontend/src/legacy/components/OrderProgressBar/styled.ts b/apps/cowswap-frontend/src/legacy/components/OrderProgressBar/styled.ts index b0d1f9cf8d..365aba86da 100644 --- a/apps/cowswap-frontend/src/legacy/components/OrderProgressBar/styled.ts +++ b/apps/cowswap-frontend/src/legacy/components/OrderProgressBar/styled.ts @@ -1,9 +1,11 @@ +import CowProtocolLogo from '@cowprotocol/assets/cow-swap/cowprotocol.svg' +import { ExternalLink } from '@cowprotocol/ui' + import { animated } from '@react-spring/web' import { CheckCircle, Clock } from 'react-feather' import styled from 'styled-components/macro' -import CowProtocolLogo from 'legacy/assets/cow-swap/cowprotocol.svg' -import { ExternalLink } from 'legacy/theme' +import { UI } from 'common/constants/theme' export const ProgressBarWrapper = animated(styled.div` display: flex; @@ -16,8 +18,8 @@ export const ProgressBarWrapper = animated(styled.div` flex-flow: column wrap; border-radius: 12px; padding: 20px 20px 0; - color: ${({ theme }) => theme.text1}; - background-color: ${({ theme }) => theme.grey1}; + color: var(${UI.COLOR_TEXT1}); + background-color: var(${UI.COLOR_GREY}); transition: height 0.2s ease; ${({ theme }) => theme.mediaWidth.upToSmall` @@ -205,7 +207,7 @@ export const StatusWrapper = styled.div` export const StatusMsg = styled.p` font-size: 0.85rem; - color: ${({ theme }) => theme.text1}; + color: var(${UI.COLOR_TEXT1}); margin: 0; ${({ theme }) => theme.mediaWidth.upToSmall` font-size: 0.835rem; @@ -217,7 +219,7 @@ export const StatusMsg = styled.p` ` export const StyledCoWLink = styled(ExternalLink)` - color: ${({ theme }) => theme.text1}; + color: var(${UI.COLOR_TEXT1}); text-decoration: underline; opacity: 1 !important; diff --git a/apps/cowswap-frontend/src/legacy/components/Popups/FailedNetworkSwitchPopup.tsx b/apps/cowswap-frontend/src/legacy/components/Popups/FailedNetworkSwitchPopup.tsx index 0825bcd3d7..9f84c557de 100644 --- a/apps/cowswap-frontend/src/legacy/components/Popups/FailedNetworkSwitchPopup.tsx +++ b/apps/cowswap-frontend/src/legacy/components/Popups/FailedNetworkSwitchPopup.tsx @@ -1,14 +1,14 @@ import { useContext } from 'react' +import { getChainInfo } from '@cowprotocol/common-const' import { SupportedChainId } from '@cowprotocol/cow-sdk' +import { AutoRow } from '@cowprotocol/ui' import { Trans } from '@lingui/macro' import { AlertCircle } from 'react-feather' import styled, { ThemeContext } from 'styled-components/macro' import { AutoColumn } from 'legacy/components/Column' -import { AutoRow } from 'legacy/components/Row' -import { getChainInfo } from 'legacy/constants/chainInfo' const RowNoFlex = styled(AutoRow)` flex-wrap: nowrap; diff --git a/apps/cowswap-frontend/src/legacy/components/Popups/PopupItem.tsx b/apps/cowswap-frontend/src/legacy/components/Popups/PopupItem.tsx index 9042d107ca..6004c1f7da 100644 --- a/apps/cowswap-frontend/src/legacy/components/Popups/PopupItem.tsx +++ b/apps/cowswap-frontend/src/legacy/components/Popups/PopupItem.tsx @@ -12,7 +12,7 @@ import { AnimatedFader, PopupWrapper, StyledClose } from './styled' import { TransactionPopup } from './TransactionPopup' /** - * @deprecated use @cowswap/snackbars instead + * @deprecated use @cowprotocol/snackbars instead */ export function PopupItem({ removeAfterMs, diff --git a/apps/cowswap-frontend/src/legacy/components/Popups/TransactionPopup.tsx b/apps/cowswap-frontend/src/legacy/components/Popups/TransactionPopup.tsx index 69a30c03f1..43e2611136 100644 --- a/apps/cowswap-frontend/src/legacy/components/Popups/TransactionPopup.tsx +++ b/apps/cowswap-frontend/src/legacy/components/Popups/TransactionPopup.tsx @@ -1,15 +1,15 @@ import { useContext } from 'react' +import { BlockExplorerLinkType } from '@cowprotocol/common-utils' +import { AutoRow } from '@cowprotocol/ui' +import { useWalletInfo } from '@cowprotocol/wallet' + import { AlertCircle, CheckCircle } from 'react-feather' import styled, { ThemeContext } from 'styled-components/macro' import { AutoColumn } from 'legacy/components/Column' import { ExplorerLink } from 'legacy/components/ExplorerLink' -import { AutoRow } from 'legacy/components/Row' import { ThemedText } from 'legacy/theme' -import { BlockExplorerLinkType } from 'legacy/utils' - -import { useWalletInfo } from 'modules/wallet' const RowNoFlex = styled(AutoRow)` flex-wrap: nowrap; diff --git a/apps/cowswap-frontend/src/legacy/components/Popups/WarningPopup.tsx b/apps/cowswap-frontend/src/legacy/components/Popups/WarningPopup.tsx index cce6f893ca..38b94a90ec 100644 --- a/apps/cowswap-frontend/src/legacy/components/Popups/WarningPopup.tsx +++ b/apps/cowswap-frontend/src/legacy/components/Popups/WarningPopup.tsx @@ -1,10 +1,11 @@ import { useContext } from 'react' +import { AutoRow } from '@cowprotocol/ui' + import { AlertCircle } from 'react-feather' import styled, { ThemeContext } from 'styled-components/macro' import { AutoColumn } from 'legacy/components/Column' -import { AutoRow } from 'legacy/components/Row' import { ThemedText } from 'legacy/theme' const RowNoFlex = styled(AutoRow)` diff --git a/apps/cowswap-frontend/src/legacy/components/Popups/index.tsx b/apps/cowswap-frontend/src/legacy/components/Popups/index.tsx index 3ba3b376d0..35a1a41892 100644 --- a/apps/cowswap-frontend/src/legacy/components/Popups/index.tsx +++ b/apps/cowswap-frontend/src/legacy/components/Popups/index.tsx @@ -1,6 +1,7 @@ import { MouseEvent, useCallback, useRef } from 'react' import { SupportedChainId } from '@cowprotocol/cow-sdk' +import { useWalletInfo } from '@cowprotocol/wallet' import { transparentize } from 'polished' import styled from 'styled-components/macro' @@ -11,8 +12,6 @@ import { useActivePopups, useRemovePopup } from 'legacy/state/application/hooks' import { useURLWarningVisible } from 'legacy/state/user/hooks' import { MEDIA_WIDTHS } from 'legacy/theme' -import { useWalletInfo } from 'modules/wallet' - export const MobilePopupInner = styled.div` height: 99%; overflow-x: auto; @@ -75,7 +74,7 @@ const FixedPopupColumn = styled(AutoColumn)<{ extraPadding: boolean; xlPadding: ` /** - * @deprecated use @cowswap/snackbars instead + * @deprecated use @cowprotocol/snackbars instead */ export function Popups() { // get all popups diff --git a/apps/cowswap-frontend/src/legacy/components/Popups/styled.ts b/apps/cowswap-frontend/src/legacy/components/Popups/styled.ts index e2c42b455d..c730ac9988 100644 --- a/apps/cowswap-frontend/src/legacy/components/Popups/styled.ts +++ b/apps/cowswap-frontend/src/legacy/components/Popups/styled.ts @@ -2,6 +2,8 @@ import { animated } from '@react-spring/web' import { X } from 'react-feather' import styled, { DefaultTheme, FlattenInterpolation, ThemeProps } from 'styled-components/macro' +import { UI } from 'common/constants/theme' + const Fader = styled.div` position: absolute; bottom: 0px; @@ -15,7 +17,7 @@ export const PopupWrapper = styled.div<{ css?: FlattenInterpolation theme.bg1}; + background-color: var(${UI.COLOR_CONTAINER_BG_01}); position: relative; border-radius: 10px; padding: 20px 35px 20px 20px; diff --git a/apps/cowswap-frontend/src/legacy/components/QuestionHelper/QuestionHelperMod.tsx b/apps/cowswap-frontend/src/legacy/components/QuestionHelper/QuestionHelperMod.tsx index 1d92e7e479..9fb689e300 100644 --- a/apps/cowswap-frontend/src/legacy/components/QuestionHelper/QuestionHelperMod.tsx +++ b/apps/cowswap-frontend/src/legacy/components/QuestionHelper/QuestionHelperMod.tsx @@ -1,38 +1,11 @@ import { useCallback, useState } from 'react' -import styled from 'styled-components/macro' +import { Tooltip, TooltipProps, renderTooltip } from '@cowprotocol/ui' -import Tooltip, { renderTooltip } from 'legacy/components/Tooltip' -import { TooltipProps } from 'legacy/components/Tooltip' +import styled from 'styled-components/macro' import { QuestionWrapper } from './index' -/* const QuestionWrapper = styled.div` - display: flex; - align-items: center; - justify-content: center; - padding: 0px; - width: 18px; - height: 18px; - border: none; - background: none; - outline: none; - cursor: default; - border-radius: 36px; - font-size: 12px; - background-color: ${({ theme }) => theme.bg2}; - color: ${({ theme }) => theme.text2}; - - :hover, - :focus { - opacity: 0.7; - } -` */ - -/* const QuestionMark = styled.span` - font-size: 14px; -` */ - const QuestionHelperContainer = styled.span` margin-left: 4px; display: flex; @@ -73,7 +46,6 @@ export default function QuestionHelper({ text, className, QuestionMark, ...toolt - {/* ? */} diff --git a/apps/cowswap-frontend/src/legacy/components/QuestionHelper/index.tsx b/apps/cowswap-frontend/src/legacy/components/QuestionHelper/index.tsx index cabd13ed59..9597b3f168 100644 --- a/apps/cowswap-frontend/src/legacy/components/QuestionHelper/index.tsx +++ b/apps/cowswap-frontend/src/legacy/components/QuestionHelper/index.tsx @@ -1,10 +1,12 @@ import { ReactNode } from 'react' +import QuestionImage from '@cowprotocol/assets/svg/question.svg' +import { renderTooltip } from '@cowprotocol/ui' + import SVG from 'react-inlinesvg' import styled from 'styled-components/macro' -import QuestionImage from 'legacy/assets/svg/question.svg' -import { renderTooltip } from 'legacy/components/Tooltip' +import { UI } from 'common/constants/theme' import QuestionHelperMod, { QuestionHelperProps } from './QuestionHelperMod' @@ -24,7 +26,7 @@ export const QuestionWrapper = styled.div` background-color: transparent; > svg > path { - stroke: ${({ theme }) => theme.text1}; + stroke: var(${UI.COLOR_TEXT1}); } ` diff --git a/apps/cowswap-frontend/src/legacy/components/SearchModal/CommonBases/CommonBasesMod.tsx b/apps/cowswap-frontend/src/legacy/components/SearchModal/CommonBases/CommonBasesMod.tsx index b059f3410a..5843ee98a6 100644 --- a/apps/cowswap-frontend/src/legacy/components/SearchModal/CommonBases/CommonBasesMod.tsx +++ b/apps/cowswap-frontend/src/legacy/components/SearchModal/CommonBases/CommonBasesMod.tsx @@ -1,20 +1,17 @@ -import { Currency, Token } from '@uniswap/sdk-core' +import { currencyId } from '@cowprotocol/common-utils' +import { TokenSymbol, AutoRow } from '@cowprotocol/ui' +import { Currency } from '@uniswap/sdk-core' import { Trans } from '@lingui/macro' import { Text } from 'rebass' import styled from 'styled-components/macro' -import { ElementName, Event, EventName } from 'legacy/components/AmplitudeAnalytics/constants' -import { TraceEvent } from 'legacy/components/AmplitudeAnalytics/TraceEvent' import QuestionHelper from 'legacy/components/QuestionHelper' -import { AutoRow } from 'legacy/components/Row' import { useFavouriteOrCommonTokens } from 'legacy/hooks/useFavouriteOrCommonTokens' -import { currencyId } from 'legacy/utils/currencyId' import { CurrencyLogo } from 'common/pure/CurrencyLogo' -import { TokenSymbol } from 'common/pure/TokenSymbol' -import { BaseWrapper, CommonBasesRow, MobileWrapper } from './index' // mod +import { BaseWrapper, CommonBasesRow, MobileWrapper } from './index' export const StyledScrollarea = styled.div` overflow-y: auto; // fallback for 'overlay' @@ -28,35 +25,16 @@ export const StyledScrollarea = styled.div` `} ` -const formatAnalyticsEventProperties = ( - currency: Currency, - tokenAddress: string | undefined, - searchQuery: string, - isAddressSearch: string | false -) => ({ - token_symbol: currency?.symbol, - token_chain_id: currency?.chainId, - ...(tokenAddress ? { token_address: tokenAddress } : {}), - is_suggested_token: true, - is_selected_from_list: false, - is_imported_by_user: false, - ...(isAddressSearch === false - ? { search_token_symbol_input: searchQuery } - : { search_token_address_input: isAddressSearch }), -}) - const MAX_LENGTH_OVERFLOW = 12 export default function CommonBases({ onSelect, selectedCurrency, - searchQuery, - isAddressSearch, }: { chainId?: number selectedCurrency?: Currency | null onSelect: (currency: Currency) => void - searchQuery: string - isAddressSearch: string | false + searchQuery?: string + isAddressSearch?: string | false }) { const tokens = useFavouriteOrCommonTokens() @@ -72,16 +50,9 @@ export default function CommonBases({ {tokens.map((currency: Currency) => { const isSelected = selectedCurrency?.equals(currency) - const tokenAddress = currency instanceof Token ? currency?.address : undefined return ( - + <> !isSelected && e.key === 'Enter' && onSelect(currency)} @@ -94,7 +65,7 @@ export default function CommonBases({ - + ) })} diff --git a/apps/cowswap-frontend/src/legacy/components/SearchModal/CommonBases/index.ts b/apps/cowswap-frontend/src/legacy/components/SearchModal/CommonBases/index.ts index c8f4cc0ac5..269b7f262b 100644 --- a/apps/cowswap-frontend/src/legacy/components/SearchModal/CommonBases/index.ts +++ b/apps/cowswap-frontend/src/legacy/components/SearchModal/CommonBases/index.ts @@ -1,10 +1,10 @@ +import { AutoRow } from '@cowprotocol/ui' import { Currency } from '@uniswap/sdk-core' import { transparentize } from 'polished' import styled from 'styled-components/macro' import { AutoColumn as AutoColumnUni } from 'legacy/components/Column' -import { AutoRow } from 'legacy/components/Row' export { default } from './CommonBasesMod' diff --git a/apps/cowswap-frontend/src/legacy/components/SearchModal/CurrencyList/CurrencyListMod.tsx b/apps/cowswap-frontend/src/legacy/components/SearchModal/CurrencyList/CurrencyListMod.tsx index 1f3ccbb4e5..354a7510c1 100644 --- a/apps/cowswap-frontend/src/legacy/components/SearchModal/CurrencyList/CurrencyListMod.tsx +++ b/apps/cowswap-frontend/src/legacy/components/SearchModal/CurrencyList/CurrencyListMod.tsx @@ -1,5 +1,10 @@ import { CSSProperties, MutableRefObject, useCallback, useMemo } from 'react' +import TokenListLogo from '@cowprotocol/assets/svg/tokenlist.svg' +import { useTheme } from '@cowprotocol/common-hooks' +import { TokenAmount, TokenSymbol, Loader, RowBetween, RowFixed } from '@cowprotocol/ui' +import { MouseoverTooltip } from '@cowprotocol/ui' +import { useWalletInfo } from '@cowprotocol/wallet' import { Currency, CurrencyAmount, Token } from '@uniswap/sdk-core' import { Trans } from '@lingui/macro' @@ -7,29 +12,19 @@ import { FixedSizeList } from 'react-window' import { Text } from 'rebass' import styled from 'styled-components/macro' -import TokenListLogo from 'legacy/assets/svg/tokenlist.svg' -import { ElementName, Event, EventName } from 'legacy/components/AmplitudeAnalytics/constants' -import { TraceEvent } from 'legacy/components/AmplitudeAnalytics/TraceEvent' import { LightGreyCard } from 'legacy/components/Card' import Column from 'legacy/components/Column' -import Loader from 'legacy/components/Loader' import QuestionHelper from 'legacy/components/QuestionHelper' -import { RowBetween, RowFixed } from 'legacy/components/Row' import ImportRow from 'legacy/components/SearchModal/ImportRow' import { LoadingRows } from 'legacy/components/SearchModal/styleds' -import { MouseoverTooltip } from 'legacy/components/Tooltip' import { useAllTokens, useIsUserAddedToken } from 'legacy/hooks/Tokens' -import useTheme from 'legacy/hooks/useTheme' import { useIsUnsupportedTokenGp } from 'legacy/state/lists/hooks' import { WrappedTokenInfo } from 'legacy/state/lists/wrappedTokenInfo' import { ThemedText } from 'legacy/theme' import useCurrencyBalance from 'modules/tokens/hooks/useCurrencyBalance' -import { useWalletInfo } from 'modules/wallet' import { CurrencyLogo } from 'common/pure/CurrencyLogo' -import { TokenAmount } from 'common/pure/TokenAmount' -import { TokenSymbol } from 'common/pure/TokenSymbol' import { Tag } from './styled' // mod @@ -65,6 +60,7 @@ function Balance({ balance }: { balance: CurrencyAmount }) { export const TagContainer = styled.div` display: flex; justify-content: flex-end; + flex-flow: row wrap; ` export const TokenListLogoWrapper = styled.img` @@ -92,8 +88,13 @@ function TokenTags({ currency }: { currency: Currency }) { return ( - {tag.name} + + {tag.icon && {tag.name}} + {tag.name} + + + {/* If there are more than one tag, show the first one and a '...' tag */} {tags.length > 1 ? ( isUnsupported: boolean // gp-added + isPermitCompatible: boolean // gp-added allTokens: { [address: string]: Token } // gp-added BalanceComponent?: (params: { balance: CurrencyAmount }) => JSX.Element // gp-swap added - TokenTagsComponent?: (params: { currency: Currency; isUnsupported: boolean }) => JSX.Element // gp-swap added + TokenTagsComponent?: (params: { + currency: Currency + isUnsupported: boolean + isPermitCompatible: boolean + }) => JSX.Element // gp-swap added }) { const { account } = useWalletInfo() const key = currencyKey(currency) @@ -141,12 +146,7 @@ function CurrencyRow({ // only show add or remove buttons if not on selected list return ( - + <> {/* */} - + {showCurrencyAmount && ( {balance ? : account ? : null} )} - + ) } @@ -231,25 +231,6 @@ interface TokenRowProps { style: CSSProperties } -const formatAnalyticsEventProperties = ( - token: Token, - index: number, - data: any[], - searchQuery: string, - isAddressSearch: string | false -) => ({ - token_symbol: token?.symbol, - token_address: token?.address, - is_suggested_token: false, - is_selected_from_list: true, - scroll_position: '', - token_list_index: index, - token_list_length: data.length, - ...(isAddressSearch === false - ? { search_token_symbol_input: searchQuery } - : { search_token_address_input: isAddressSearch }), -}) - // TODO: refactor the component export default function CurrencyList({ height, @@ -263,8 +244,6 @@ export default function CurrencyList({ setImportToken, showCurrencyAmount, isLoading, - searchQuery, - isAddressSearch, additionalTokens, BalanceComponent = Balance, // gp-swap added TokenTagsComponent = TokenTags, // gp-swap added @@ -280,8 +259,8 @@ export default function CurrencyList({ setImportToken: (token: Token) => void showCurrencyAmount?: boolean isLoading: boolean - searchQuery: string - isAddressSearch: string | false + searchQuery?: string + isAddressSearch?: string | false additionalTokens?: Currency[] BalanceComponent?: (params: { balance: CurrencyAmount }) => JSX.Element // gp-swap added TokenTagsComponent?: (params: { currency: Currency; isUnsupported: boolean }) => JSX.Element // gp-swap added @@ -336,6 +315,7 @@ export default function CurrencyList({ const showImport = index > currencies.length const isUnsupported = !!isUnsupportedToken(token?.address) + const isPermitCompatible = false // TODO: Make dynamic if (isLoading) { return ( @@ -361,8 +341,8 @@ export default function CurrencyList({ BalanceComponent={BalanceComponent} // gp-swap added TokenTagsComponent={TokenTagsComponent} // gp-swap added isUnsupported={isUnsupported} + isPermitCompatible={isPermitCompatible} // gp-swap added showCurrencyAmount={showCurrencyAmount} - eventProperties={formatAnalyticsEventProperties(token, index, data, searchQuery, isAddressSearch)} /> ) } else { @@ -378,8 +358,6 @@ export default function CurrencyList({ showImportView, showCurrencyAmount, isLoading, - isAddressSearch, - searchQuery, isUnsupportedToken, BalanceComponent, TokenTagsComponent, diff --git a/apps/cowswap-frontend/src/legacy/components/SearchModal/CurrencyList/index.tsx b/apps/cowswap-frontend/src/legacy/components/SearchModal/CurrencyList/index.tsx index 22c4363b78..43987756c4 100644 --- a/apps/cowswap-frontend/src/legacy/components/SearchModal/CurrencyList/index.tsx +++ b/apps/cowswap-frontend/src/legacy/components/SearchModal/CurrencyList/index.tsx @@ -1,153 +1,84 @@ +import { UNSUPPORTED_TOKENS_FAQ_URL } from '@cowprotocol/common-const' +import { TokenAmount } from '@cowprotocol/ui' +import { MouseoverTooltip } from '@cowprotocol/ui' import { Currency, CurrencyAmount } from '@uniswap/sdk-core' -// eslint-disable-next-line no-restricted-imports -import { t } from '@lingui/macro' -import { transparentize } from 'polished' +import ICON_GAS_FREE from 'assets/icon/gas-free.svg' import { HashLink } from 'react-router-hash-link' import styled from 'styled-components/macro' -import { LightGreyCard } from 'legacy/components/Card' -import Column from 'legacy/components/Column' -import { RowFixed } from 'legacy/components/Row' import { MenuItem as MenuItemMod } from 'legacy/components/SearchModal/styleds' -import { MouseoverTooltip } from 'legacy/components/Tooltip' -import { UNSUPPORTED_TOKENS_FAQ_URL } from 'legacy/constants' import { TagInfo } from 'legacy/state/lists/wrappedTokenInfo' -import { StyledLogo } from 'common/pure/CurrencyLogo' -import { TokenAmount } from 'common/pure/TokenAmount' - import CurrencyListMod, { StyledBalanceText, TagContainer } from './CurrencyListMod' -import { Tag as TagMod } from './styled' +import { Wrapper, Tag, TagLink } from './styled' + +enum Tags { + UNSUPPORTED = '0', + GAS_FREE = '1', +} -const UNSUPPORTED_TOKEN_TAG = [ - { +const TOKEN_TAGS: Record = { + [Tags.UNSUPPORTED]: { name: 'Unsupported', description: 'This token is unsupported as it does not operate optimally with CoW Protocol. Please refer to the FAQ for more information.', id: '0', }, -] - -const Tag = styled(TagMod)<{ tag?: TagInfo }>` - // Todo: Prevent usage of !important - background: ${({ tag, theme }) => (tag?.id === '0' ? transparentize(0.85, theme.danger) : theme.grey1)}; - color: ${({ tag, theme }) => (tag?.id === '0' ? theme.danger : theme.text1)}!important; - max-width: 6.1rem; -` + [Tags.GAS_FREE]: { + name: 'Gas-free approval', + icon: ICON_GAS_FREE, + description: 'This token can be approved without spending gas, using the token Permit.', + id: '1', + }, +} -const TagLink = styled(Tag)` - display: flex; - align-items: center; - font-size: x-small; - a { - color: inherit; - font-weight: bold; +export const MenuItem = styled(MenuItemMod)` + &:hover { + background-color: ${({ theme, disabled }) => !disabled && theme.grey1}; } ` -const Wrapper = styled.div` - ${Column} { - > div { - overflow: hidden; - white-space: nowrap; - text-overflow: ellipsis; - max-width: 220px; - width: 100%; - - // Token symbol name - &:first-of-type { - color: ${({ theme }) => theme.text1}; - } - - // Token full name - &:last-of-type { - color: ${({ theme }) => theme.text2}; - font-weight: 400; - } - - ${({ theme }) => theme.mediaWidth.upToSmall` - max-width: 140px; - `}; - } - } - - ${StyledLogo} { - height: 36px; - width: 36px; - border-radius: 36px; - } - - ${TagMod} { - color: ${({ theme }) => theme.text2}; - } - - ${TagLink} { - color: ${({ theme }) => theme.text1}; - } +function TokenTags({ isUnsupported, isPermitCompatible }: { isUnsupported: boolean; isPermitCompatible?: boolean }) { + const tagsToShow: TagInfo[] = [] - ${LightGreyCard} { - background: ${({ theme }) => theme.bg1}; - } - - ${LightGreyCard} ${RowFixed} > div { - color: ${({ theme }) => theme.text1}; + if (isUnsupported) { + tagsToShow.push(TOKEN_TAGS[Tags.UNSUPPORTED]) + } else if (isPermitCompatible) { + tagsToShow.push(TOKEN_TAGS[Tags.GAS_FREE]) } -` -export const MenuItem = styled(MenuItemMod)` - &:hover { - background-color: ${({ theme, disabled }) => !disabled && theme.grey1}; + if (tagsToShow.length === 0) { + return } -` -function TagDescriptor({ tags, children }: { children?: React.ReactNode; tags: TagInfo[]; bg?: string }) { - const tag = tags[0] return ( - - - - {tag.name} - - - {tags.length > 1 ? ( - t`${name}: ${description}`) - .join('; \n')} - > - ... - - ) : null} - {children} - - ) -} - -function TokenTags({ /* currency, */ isUnsupported }: { /* currency: Currency; */ isUnsupported: boolean }) { - if (isUnsupported) { - return ( - + + {isUnsupported && ( e.stopPropagation()}> FAQ - - ) - } - - return // MOD: return only UnsupportedToken tags - - /* if (!(currency instanceof WrappedTokenInfo)) { - return - } - - const tags = currency.tags - if (!tags || tags.length === 0) return + )} + + ) +} - return */ +function TagDescriptor({ tags, children }: { children?: React.ReactNode; tags: TagInfo[] }) { + return ( + + {tags.map((tag) => ( + + + {tag.icon ? {tag.name} : null} + {tag.name} + + + ))} + {children} + + ) } export function Balance({ balance }: { balance: CurrencyAmount }) { diff --git a/apps/cowswap-frontend/src/legacy/components/SearchModal/CurrencyList/styled.ts b/apps/cowswap-frontend/src/legacy/components/SearchModal/CurrencyList/styled.ts index 83165c1e07..610ead735d 100644 --- a/apps/cowswap-frontend/src/legacy/components/SearchModal/CurrencyList/styled.ts +++ b/apps/cowswap-frontend/src/legacy/components/SearchModal/CurrencyList/styled.ts @@ -1,15 +1,92 @@ +import { RowFixed } from '@cowprotocol/ui' + import styled from 'styled-components/macro' -export const Tag = styled.div` - background-color: ${({ theme }) => theme.bg3}; - color: ${({ theme }) => theme.text2}; - font-size: 14px; +import { LightGreyCard } from 'legacy/components/Card' +import Column from 'legacy/components/Column' +import { TagInfo } from 'legacy/state/lists/wrappedTokenInfo' + +import { UI } from 'common/constants/theme' +import { StyledLogo } from 'common/pure/CurrencyLogo' + +export const Tag = styled.div<{ tag?: TagInfo }>` + display: flex; + align-items: center; + background: ${({ tag }) => + tag?.id === '0' + ? `var(${UI.COLOR_DANGER_BG})` + : tag?.id === '1' + ? `var(${UI.COLOR_SUCCESS_BG})` + : `var(${UI.COLOR_GREY})`}; + color: ${({ tag }) => + tag?.id === '0' + ? `var(${UI.COLOR_DANGER_TEXT})` + : tag?.id === '1' + ? `var(${UI.COLOR_SUCCESS_TEXT})` + : `var(${UI.COLOR_TEXT1})`}; + font-size: 12px; + font-weight: var(${UI.FONT_WEIGHT_MEDIUM}); border-radius: 4px; - padding: 0.25rem 0.3rem 0.25rem 0.3rem; - max-width: 6rem; + padding: 4px 6px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; justify-self: flex-end; - margin-right: 4px; + margin: 0 4px 0 0; + + > img { + --size: 14px; + display: inline-block; + margin: 0 5px 0 0; + width: var(--size); + height: var(--size); + } +` + +export const TagLink = styled(Tag)` + a { + color: inherit; + font-weight: inherit; + } +` + +export const Wrapper = styled.div` + ${Column} { + > div { + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; + max-width: 220px; + width: 100%; + + // Token symbol name + &:first-of-type { + color: var(${UI.COLOR_TEXT1}); + } + + // Token full name + &:last-of-type { + color: var(${UI.COLOR_TEXT2}); + font-weight: 400; + } + + ${({ theme }) => theme.mediaWidth.upToSmall` + max-width: 140px; + `}; + } + } + ${StyledLogo} { + height: 36px; + width: 36px; + border-radius: 36px; + } + ${TagLink} { + color: var(${UI.COLOR_TEXT1}); + } + ${LightGreyCard} { + background: var(${UI.COLOR_CONTAINER_BG_01}); + } + ${LightGreyCard} ${RowFixed} > div { + color: var(${UI.COLOR_TEXT1}); + } ` diff --git a/apps/cowswap-frontend/src/legacy/components/SearchModal/CurrencySearch/CurrencySearchMod.tsx b/apps/cowswap-frontend/src/legacy/components/SearchModal/CurrencySearch/CurrencySearchMod.tsx index 500ca4483c..693e2efdfa 100644 --- a/apps/cowswap-frontend/src/legacy/components/SearchModal/CurrencySearch/CurrencySearchMod.tsx +++ b/apps/cowswap-frontend/src/legacy/components/SearchModal/CurrencySearch/CurrencySearchMod.tsx @@ -1,5 +1,10 @@ import { ChangeEvent, KeyboardEvent, RefObject, useCallback, useEffect, useMemo, useRef, useState } from 'react' +import { searchByAddressAnalytics } from '@cowprotocol/analytics' +import { useTheme, useDebounce, useNetworkName, useOnClickOutside, useToggle } from '@cowprotocol/common-hooks' +import { isAddress } from '@cowprotocol/common-utils' +import { Row } from '@cowprotocol/ui' +import { useWalletInfo } from '@cowprotocol/wallet' import { Currency, Token } from '@uniswap/sdk-core' import { t, Trans } from '@lingui/macro' @@ -8,27 +13,21 @@ import { FixedSizeList } from 'react-window' import { Text } from 'rebass' import styled, { DefaultTheme } from 'styled-components/macro' -import { EventName, ModalName } from 'legacy/components/AmplitudeAnalytics/constants' -import { Trace } from 'legacy/components/AmplitudeAnalytics/Trace' -import { searchByAddressAnalytics } from 'legacy/components/analytics' import Column from 'legacy/components/Column' -import Row /* RowBetween , RowFixed */ from 'legacy/components/Row' import CommonBases from 'legacy/components/SearchModal/CommonBases' import CurrencyList from 'legacy/components/SearchModal/CurrencyList' import ImportRow from 'legacy/components/SearchModal/ImportRow' import { PaddedColumn, SearchInput, Separator, PaddedRow } from 'legacy/components/SearchModal/styleds' -import { useAllTokens, useIsUserAddedToken, useSearchInactiveTokenLists, useToken } from 'legacy/hooks/Tokens' -import useDebounce from 'legacy/hooks/useDebounce' -import useNetworkName from 'legacy/hooks/useNetworkName' -import { useOnClickOutside } from 'legacy/hooks/useOnClickOutside' -import useTheme from 'legacy/hooks/useTheme' -import useToggle from 'legacy/hooks/useToggle' -import { useAllTokenBalances } from 'legacy/state/connection/hooks' +import { + useAllTokenBalances, + useAllTokens, + useIsUserAddedToken, + useSearchInactiveTokenLists, + useToken, +} from 'legacy/hooks/Tokens' import { ButtonText, CloseIcon, ThemedText } from 'legacy/theme' -import { isAddress } from 'legacy/utils' - -import { useWalletInfo } from 'modules/wallet' +import { UI } from 'common/constants/theme' import { useExternalTokenSearch } from 'common/hooks/useExternalTokenSearch' import useNativeCurrency from 'lib/hooks/useNativeCurrency' import { getTokenFilter } from 'lib/hooks/useTokenList/filtering' @@ -42,7 +41,7 @@ export const Footer = styled.div` padding: 20px; border-top-left-radius: 0; border-top-right-radius: 0; - background-color: ${({ theme }) => theme.bg1}; + background-color: var(${UI.COLOR_CONTAINER_BG_01}); ` export interface CurrencySearchProps { @@ -207,7 +206,7 @@ export function CurrencySearch({ }, []) return ( - + <> @@ -287,6 +286,6 @@ export function CurrencySearch({ - + ) } diff --git a/apps/cowswap-frontend/src/legacy/components/SearchModal/CurrencySearch/index.tsx b/apps/cowswap-frontend/src/legacy/components/SearchModal/CurrencySearch/index.tsx index 7174b3c087..568b8c912b 100644 --- a/apps/cowswap-frontend/src/legacy/components/SearchModal/CurrencySearch/index.tsx +++ b/apps/cowswap-frontend/src/legacy/components/SearchModal/CurrencySearch/index.tsx @@ -1,3 +1,5 @@ +import { RowFixed } from '@cowprotocol/ui' + import { Trans } from '@lingui/macro' import { transparentize } from 'polished' import { Edit } from 'react-feather' @@ -5,10 +7,11 @@ import styled from 'styled-components/macro' import { DefaultTheme } from 'styled-components/macro' import Column from 'legacy/components/Column' -import { RowFixed } from 'legacy/components/Row' import { Separator } from 'legacy/components/SearchModal/styleds' import { IconWrapper, ThemedText } from 'legacy/theme' +import { UI } from 'common/constants/theme' + import { CurrencySearch as CurrencySearchMod, CurrencySearchProps } from './CurrencySearchMod' export const ContentWrapper = styled(Column)` @@ -19,8 +22,8 @@ export const ContentWrapper = styled(Column)` > input { border: none; transition: background 0.3s ease-in-out; - background: ${({ theme }) => theme.bg1}; - color: ${({ theme }) => theme.text1}; + background: var(${UI.COLOR_CONTAINER_BG_01}); + color: var(${UI.COLOR_TEXT1}); } > input::placeholder { @@ -33,7 +36,7 @@ export const ContentWrapper = styled(Column)` } ${Separator} { - background: ${({ theme }) => theme.grey1}; + background: var(${UI.COLOR_GREY}); // Target the token list container + div { diff --git a/apps/cowswap-frontend/src/legacy/components/SearchModal/CurrencySearch/sorting.ts b/apps/cowswap-frontend/src/legacy/components/SearchModal/CurrencySearch/sorting.ts index 141f362f8a..c3fb6ccc26 100644 --- a/apps/cowswap-frontend/src/legacy/components/SearchModal/CurrencySearch/sorting.ts +++ b/apps/cowswap-frontend/src/legacy/components/SearchModal/CurrencySearch/sorting.ts @@ -2,7 +2,7 @@ import { useMemo } from 'react' import { Currency, CurrencyAmount, Token } from '@uniswap/sdk-core' -import { useAllTokenBalances } from 'legacy/state/connection/hooks' +import { useAllTokenBalances } from 'legacy/hooks/Tokens' import { TokenAmounts } from 'modules/tokens' diff --git a/apps/cowswap-frontend/src/legacy/components/SearchModal/CurrencySearchModal.tsx b/apps/cowswap-frontend/src/legacy/components/SearchModal/CurrencySearchModal.tsx index 403c1540a4..3fc6e94102 100644 --- a/apps/cowswap-frontend/src/legacy/components/SearchModal/CurrencySearchModal.tsx +++ b/apps/cowswap-frontend/src/legacy/components/SearchModal/CurrencySearchModal.tsx @@ -1,20 +1,17 @@ import { useCallback, useEffect, useState } from 'react' +import { usePrevious, useLast } from '@cowprotocol/common-hooks' import { Currency, Token } from '@uniswap/sdk-core' import { TokenList } from '@uniswap/token-lists' -// import Modal from '../Modal' import { CurrencySearch } from 'legacy/components/SearchModal/CurrencySearch' import { ImportList } from 'legacy/components/SearchModal/ImportList' import { ImportToken } from 'legacy/components/SearchModal/ImportToken' import Manage from 'legacy/components/SearchModal/Manage' -import usePrevious from 'legacy/hooks/usePrevious' import { WrappedTokenInfo } from 'legacy/state/lists/wrappedTokenInfo' import { CowModal as Modal } from 'common/pure/Modal' -import useLast from '../../hooks/useLast' - export interface CurrencySearchModalProps { isOpen: boolean onDismiss: () => void diff --git a/apps/cowswap-frontend/src/legacy/components/SearchModal/ImportList/ImportListMod.tsx b/apps/cowswap-frontend/src/legacy/components/SearchModal/ImportList/ImportListMod.tsx index 3c925130d1..d047a1f786 100644 --- a/apps/cowswap-frontend/src/legacy/components/SearchModal/ImportList/ImportListMod.tsx +++ b/apps/cowswap-frontend/src/legacy/components/SearchModal/ImportList/ImportListMod.tsx @@ -1,24 +1,25 @@ import { useCallback, useState } from 'react' +import { addListAnalytics } from '@cowprotocol/analytics' +import { useTheme } from '@cowprotocol/common-hooks' +import { ButtonPrimary } from '@cowprotocol/ui' +import { AutoRow, RowBetween, RowFixed } from '@cowprotocol/ui' +import { ExternalLink } from '@cowprotocol/ui' + import { Trans } from '@lingui/macro' import { transparentize } from 'polished' import { AlertTriangle, ArrowLeft } from 'react-feather' import styled from 'styled-components/macro' -import { addListAnalytics } from 'legacy/components/analytics' -import { ButtonPrimary } from 'legacy/components/Button' import { AutoColumn } from 'legacy/components/Column' import ListLogo from 'legacy/components/ListLogo' -import { AutoRow, RowBetween, RowFixed } from 'legacy/components/Row' import { CurrencyModalView } from 'legacy/components/SearchModal/CurrencySearchModal' import { Card } from 'legacy/components/SearchModal/ManageLists' import { Checkbox, PaddedColumn, TextDot } from 'legacy/components/SearchModal/styleds' import { SectionBreak } from 'legacy/components/swap/styleds' import { useFetchListCallback } from 'legacy/hooks/useFetchListCallback' -import useTheme from 'legacy/hooks/useTheme' import { useAllLists } from 'legacy/state/lists/hooks' import { CloseIcon, ThemedText } from 'legacy/theme' -import { ExternalLink } from 'legacy/theme' import { ImportProps } from './index' diff --git a/apps/cowswap-frontend/src/legacy/components/SearchModal/ImportList/index.tsx b/apps/cowswap-frontend/src/legacy/components/SearchModal/ImportList/index.tsx index b29590c17e..031b52b50c 100644 --- a/apps/cowswap-frontend/src/legacy/components/SearchModal/ImportList/index.tsx +++ b/apps/cowswap-frontend/src/legacy/components/SearchModal/ImportList/index.tsx @@ -1,15 +1,14 @@ import { useCallback } from 'react' +import { DEFAULT_NETWORK_FOR_LISTS } from '@cowprotocol/common-const' +import { useWalletInfo } from '@cowprotocol/wallet' import { TokenList } from '@uniswap/token-lists' import { useDispatch } from 'react-redux' import { CurrencyModalView } from 'legacy/components/SearchModal/CurrencySearchModal' -import { DEFAULT_NETWORK_FOR_LISTS } from 'legacy/constants/lists' import { enableList as enableListMod, removeList as removeListMod } from 'legacy/state/lists/actions' -import { useWalletInfo } from 'modules/wallet' - import { ImportList as ImportListMod } from './ImportListMod' export interface ImportProps { diff --git a/apps/cowswap-frontend/src/legacy/components/SearchModal/ImportRow/ImportRowMod.tsx b/apps/cowswap-frontend/src/legacy/components/SearchModal/ImportRow/ImportRowMod.tsx index 710e4a5256..628055712d 100644 --- a/apps/cowswap-frontend/src/legacy/components/SearchModal/ImportRow/ImportRowMod.tsx +++ b/apps/cowswap-frontend/src/legacy/components/SearchModal/ImportRow/ImportRowMod.tsx @@ -1,17 +1,17 @@ import { CSSProperties } from 'react' +import { useTheme } from '@cowprotocol/common-hooks' +import { ButtonPrimary } from '@cowprotocol/ui' +import { AutoRow, RowFixed } from '@cowprotocol/ui' import { Token } from '@uniswap/sdk-core' import { Trans } from '@lingui/macro' import { CheckCircle } from 'react-feather' import styled from 'styled-components/macro' -import { ButtonPrimary } from 'legacy/components/Button' import { AutoColumn } from 'legacy/components/Column' import ListLogo from 'legacy/components/ListLogo' -import { AutoRow, RowFixed } from 'legacy/components/Row' import { useIsTokenActive, useIsUserAddedToken } from 'legacy/hooks/Tokens' -import useTheme from 'legacy/hooks/useTheme' import { WrappedTokenInfo } from 'legacy/state/lists/wrappedTokenInfo' import { ThemedText } from 'legacy/theme' diff --git a/apps/cowswap-frontend/src/legacy/components/SearchModal/ImportRow/index.tsx b/apps/cowswap-frontend/src/legacy/components/SearchModal/ImportRow/index.tsx index 38d8522d74..24e27be063 100644 --- a/apps/cowswap-frontend/src/legacy/components/SearchModal/ImportRow/index.tsx +++ b/apps/cowswap-frontend/src/legacy/components/SearchModal/ImportRow/index.tsx @@ -1,12 +1,14 @@ import { CSSProperties } from 'react' +import { ButtonPrimary } from '@cowprotocol/ui' +import { AutoRow } from '@cowprotocol/ui' import { Token } from '@uniswap/sdk-core' import styled from 'styled-components/macro' -import { ButtonPrimary } from 'legacy/components/Button' import { StyledListLogo } from 'legacy/components/ListLogo' -import { AutoRow } from 'legacy/components/Row' + +import { UI } from 'common/constants/theme' import ImportRowMod, { TokenSection } from './ImportRowMod' @@ -31,7 +33,7 @@ const Wrapper = styled.div` } ${TokenSection} > svg { - stroke: ${({ theme }) => theme.text2}; + stroke: var(${UI.COLOR_TEXT2}); } ${TokenSection} ${AutoRow} { @@ -40,7 +42,7 @@ const Wrapper = styled.div` } ${AutoRow} > div { - color: ${({ theme }) => theme.text1}; + color: var(${UI.COLOR_TEXT1}); margin: 0; } diff --git a/apps/cowswap-frontend/src/legacy/components/SearchModal/ImportToken/ImportTokenMod.tsx b/apps/cowswap-frontend/src/legacy/components/SearchModal/ImportToken/ImportTokenMod.tsx index 8c35abf901..f752e237ea 100644 --- a/apps/cowswap-frontend/src/legacy/components/SearchModal/ImportToken/ImportTokenMod.tsx +++ b/apps/cowswap-frontend/src/legacy/components/SearchModal/ImportToken/ImportTokenMod.tsx @@ -1,3 +1,6 @@ +import { useTheme } from '@cowprotocol/common-hooks' +import { ButtonPrimary } from '@cowprotocol/ui' +import { RowBetween } from '@cowprotocol/ui' import { Currency, Token } from '@uniswap/sdk-core' import { TokenList } from '@uniswap/token-lists' @@ -6,16 +9,11 @@ import { transparentize } from 'polished' import { AlertCircle, ArrowLeft } from 'react-feather' import styled from 'styled-components/macro' -import { ElementName, Event, EventName } from 'legacy/components/AmplitudeAnalytics/constants' -import { TraceEvent } from 'legacy/components/AmplitudeAnalytics/TraceEvent' -import { ButtonPrimary } from 'legacy/components/Button' import Card from 'legacy/components/Card' import { AutoColumn } from 'legacy/components/Column' -import { RowBetween } from 'legacy/components/Row' import { PaddedColumn } from 'legacy/components/SearchModal/styleds' import TokenImportCard from 'legacy/components/SearchModal/TokenImportCard' import { SectionBreak } from 'legacy/components/swap/styleds' -import useTheme from 'legacy/hooks/useTheme' import { useAddUserToken } from 'legacy/state/user/hooks' import { CloseIcon, ThemedText } from 'legacy/theme' @@ -50,12 +48,6 @@ export interface ImportProps { CardComponent: (props: CardComponentProps) => JSX.Element // mod } -const formatAnalyticsEventProperties = (tokens: Token[]) => ({ - token_symbols: tokens.map((token) => token?.symbol), - token_addresses: tokens.map((token) => token?.address), - token_chain_ids: tokens.map((token) => token?.chainId), -}) - export function ImportToken(props: ImportProps) { const { tokens, list, onBack, onDismiss, handleCurrencySelect } = props const theme = useTheme() @@ -87,12 +79,7 @@ export function ImportToken(props: ImportProps) { {tokens.map((token) => ( ))} - + <> Import - + ) diff --git a/apps/cowswap-frontend/src/legacy/components/SearchModal/ImportToken/index.tsx b/apps/cowswap-frontend/src/legacy/components/SearchModal/ImportToken/index.tsx index 1d2312a50b..c06016c36d 100644 --- a/apps/cowswap-frontend/src/legacy/components/SearchModal/ImportToken/index.tsx +++ b/apps/cowswap-frontend/src/legacy/components/SearchModal/ImportToken/index.tsx @@ -1,3 +1,5 @@ +import { getEtherscanLink as getExplorerLink } from '@cowprotocol/common-utils' +import { RowFixed, ExternalLink } from '@cowprotocol/ui' import { Token } from '@uniswap/sdk-core' import { Trans } from '@lingui/macro' @@ -8,12 +10,10 @@ import styled from 'styled-components/macro' import Card from 'legacy/components/Card' import { AutoColumn } from 'legacy/components/Column' import ListLogo from 'legacy/components/ListLogo' -import { RowFixed } from 'legacy/components/Row' import { PaddedColumn } from 'legacy/components/SearchModal/styleds' import { ThemedText } from 'legacy/theme' -import { ExternalLink } from 'legacy/theme/components' -import { getEtherscanLink as getExplorerLink } from 'legacy/utils' +import { UI } from 'common/constants/theme' import { CurrencyLogo } from 'common/pure/CurrencyLogo' import { AddressText, ImportProps, ImportToken as ImportTokenMod, WarningWrapper } from './ImportTokenMod' @@ -48,7 +48,7 @@ const Wrapper = styled.div` ${({ theme }) => theme.mediaWidth.upToSmall` position: sticky; top: 0; - background: ${({ theme }) => theme.bg1}; + background: var(${UI.COLOR_CONTAINER_BG_01}); `} } ` diff --git a/apps/cowswap-frontend/src/legacy/components/SearchModal/Manage/ManageMod.tsx b/apps/cowswap-frontend/src/legacy/components/SearchModal/Manage/ManageMod.tsx index 85e4791b3f..1a186824d8 100644 --- a/apps/cowswap-frontend/src/legacy/components/SearchModal/Manage/ManageMod.tsx +++ b/apps/cowswap-frontend/src/legacy/components/SearchModal/Manage/ManageMod.tsx @@ -1,10 +1,11 @@ import { useState } from 'react' +import { RowBetween } from '@cowprotocol/ui' + import { Trans } from '@lingui/macro' import { ArrowLeft } from 'react-feather' import { Text } from 'rebass' -import { RowBetween } from 'legacy/components/Row' import { CurrencyModalView } from 'legacy/components/SearchModal/CurrencySearchModal' import { ManageLists } from 'legacy/components/SearchModal/ManageLists' import ManageTokens from 'legacy/components/SearchModal/ManageTokens' diff --git a/apps/cowswap-frontend/src/legacy/components/SearchModal/Manage/index.tsx b/apps/cowswap-frontend/src/legacy/components/SearchModal/Manage/index.tsx index 51da5e661a..1c757d948d 100644 --- a/apps/cowswap-frontend/src/legacy/components/SearchModal/Manage/index.tsx +++ b/apps/cowswap-frontend/src/legacy/components/SearchModal/Manage/index.tsx @@ -1,13 +1,15 @@ +import { RowBetween } from '@cowprotocol/ui' import { Token } from '@uniswap/sdk-core' import { TokenList } from '@uniswap/token-lists' import { transparentize } from 'polished' import styled from 'styled-components/macro' -import { RowBetween } from 'legacy/components/Row' import { CurrencyModalView } from 'legacy/components/SearchModal/CurrencySearchModal' import { SearchInput, Separator } from 'legacy/components/SearchModal/styleds' +import { UI } from 'common/constants/theme' + import ManageMod from './ManageMod' export const Wrapper = styled.div` @@ -19,7 +21,7 @@ export const Wrapper = styled.div` ${SearchInput} { border: none; transition: background 0.3s ease-in-out; - background: ${({ theme }) => theme.grey1}; + background: var(${UI.COLOR_GREY}); } ${SearchInput}::placeholder { @@ -50,7 +52,7 @@ const ToggleOption = styled.div<{ active?: boolean }>` border-radius: 12px; font-weight: 600; background-color: ${({ theme, active }) => (active ? theme.bg1 : theme.bg1)}; - color: ${({ theme, active }) => (active ? theme.text1 : theme.disabled)}; + color: ${({ theme, active }) => (active ? `var(${UI.COLOR_TEXT1})` : theme.disabled)}; user-select: none; :hover { diff --git a/apps/cowswap-frontend/src/legacy/components/SearchModal/ManageLists/ManageListsMod.tsx b/apps/cowswap-frontend/src/legacy/components/SearchModal/ManageLists/ManageListsMod.tsx index b60e1a86f5..7f4cf67124 100644 --- a/apps/cowswap-frontend/src/legacy/components/SearchModal/ManageLists/ManageListsMod.tsx +++ b/apps/cowswap-frontend/src/legacy/components/SearchModal/ManageLists/ManageListsMod.tsx @@ -1,38 +1,36 @@ import { ChangeEvent, memo, useCallback, useEffect, useMemo, useRef, useState } from 'react' -import { TokenList } from '@uniswap/token-lists' +import { updateListAnalytics, removeListAnalytics, toggleListAnalytics } from '@cowprotocol/analytics' +import { useListColor, useTheme, useToggle, useOnClickOutside } from '@cowprotocol/common-hooks' +import { parseENSAddress, uriToHttp } from '@cowprotocol/common-utils' +import { Row, RowBetween, RowFixed, ButtonEmpty, ButtonPrimary, ExternalLink } from '@cowprotocol/ui' +import { useWalletInfo } from '@cowprotocol/wallet' +import { TokenList, Version } from '@uniswap/token-lists' import { t, Trans } from '@lingui/macro' import { CheckCircle, Settings } from 'react-feather' import { usePopper } from 'react-popper' import styled from 'styled-components/macro' -import { updateListAnalytics, removeListAnalytics, toggleListAnalytics } from 'legacy/components/analytics' -import { ButtonEmpty, ButtonPrimary } from 'legacy/components/Button' import Column, { AutoColumn } from 'legacy/components/Column' import ListLogo from 'legacy/components/ListLogo' -import Row, { RowBetween, RowFixed } from 'legacy/components/Row' import { CurrencyModalView } from 'legacy/components/SearchModal/CurrencySearchModal' import { PaddedColumn, SearchInput, Separator, SeparatorDark } from 'legacy/components/SearchModal/styleds' -import Toggle from 'legacy/components/Toggle' -import { useListColor } from 'legacy/hooks/useColor' +import { Toggle } from 'legacy/components/Toggle' import { useFetchListCallback } from 'legacy/hooks/useFetchListCallback' -import { useOnClickOutside } from 'legacy/hooks/useOnClickOutside' -import useTheme from 'legacy/hooks/useTheme' -import useToggle from 'legacy/hooks/useToggle' import { useAppDispatch, useAppSelector } from 'legacy/state/hooks' import { useActiveListUrls, useAllLists, useIsListActive } from 'legacy/state/lists/hooks' -import { ExternalLink, IconWrapper, LinkStyledButton, ThemedText } from 'legacy/theme' -import listVersionLabel from 'legacy/utils/listVersionLabel' - -import { useWalletInfo } from 'modules/wallet' +import { IconWrapper, LinkStyledButton, ThemedText } from 'legacy/theme' +import { UI } from 'common/constants/theme' import { useConfirmationRequest } from 'common/hooks/useConfirmationRequest' -import parseENSAddress from 'lib/utils/parseENSAddress' -import uriToHttp from 'lib/utils/uriToHttp' import { ListRowProps, RowWrapper, Card } from './index' +function listVersionLabel(version: Version): string { + return `v${version.major}.${version.minor}.${version.patch}` +} + const Wrapper = styled(Column)` width: 100%; height: 100%; @@ -53,7 +51,7 @@ export const PopoverContainer = styled.div<{ show: boolean }>` border: 1px solid ${({ theme }) => theme.bg3}; box-shadow: 0px 0px 1px rgba(0, 0, 0, 0.01), 0px 4px 8px rgba(0, 0, 0, 0.04), 0px 16px 24px rgba(0, 0, 0, 0.04), 0px 24px 32px rgba(0, 0, 0, 0.01); - color: ${({ theme }) => theme.text2}; + color: var(${UI.COLOR_TEXT2}); border-radius: 0.5rem; padding: 1rem; display: grid; diff --git a/apps/cowswap-frontend/src/legacy/components/SearchModal/ManageLists/index.tsx b/apps/cowswap-frontend/src/legacy/components/SearchModal/ManageLists/index.tsx index 04a9ea8889..b43c63e955 100644 --- a/apps/cowswap-frontend/src/legacy/components/SearchModal/ManageLists/index.tsx +++ b/apps/cowswap-frontend/src/legacy/components/SearchModal/ManageLists/index.tsx @@ -1,17 +1,18 @@ +import { UNSUPPORTED_LIST_URLS } from '@cowprotocol/common-const' +import { ButtonPrimary } from '@cowprotocol/ui' +import { Row, RowFixed, RowBetween } from '@cowprotocol/ui' +import { useWalletInfo } from '@cowprotocol/wallet' import { TokenList } from '@uniswap/token-lists' import { transparentize } from 'polished' import styled from 'styled-components/macro' -import { ButtonPrimary } from 'legacy/components/Button' import CardUni from 'legacy/components/Card' -import Row, { RowFixed, RowBetween } from 'legacy/components/Row' import { CurrencyModalView } from 'legacy/components/SearchModal/CurrencySearchModal' import { TextDot } from 'legacy/components/SearchModal/styleds' -import { UNSUPPORTED_LIST_URLS } from 'legacy/constants/lists' import { acceptListUpdate, removeList, disableList, enableList } from 'legacy/state/lists/actions' -import { useWalletInfo } from 'modules/wallet' +import { UI } from 'common/constants/theme' import { ManageLists as ManageListsMod, ListContainer, PopoverContainer } from './ManageListsMod' @@ -33,12 +34,12 @@ const Wrapper = styled.div` svg > path, svg > circle { - stroke: ${({ theme }) => theme.text1}; + stroke: var(${UI.COLOR_TEXT1}); } } ${PopoverContainer} { - background: ${({ theme }) => theme.bg1}; + background: var(${UI.COLOR_CONTAINER_BG_01}); } ` @@ -54,18 +55,18 @@ export const RowWrapper = styled(Row)<{ bgColor: string; active: boolean; hasAct ${Row}, ${RowFixed}, ${RowBetween} { > div { - color: ${({ active, theme }) => (active ? theme.text1 : theme.text2)}; + color: ${({ active, theme }) => (active ? `var(${UI.COLOR_TEXT1})` : theme.text2)}; } } ` export const Card = styled(CardUni)` - background: ${({ theme }) => theme.bg1}; + background: var(${UI.COLOR_CONTAINER_BG_01}); ${Row}, ${Row} > div > div, ${Row} > div > div > div { - color: ${({ theme }) => theme.text1}; + color: var(${UI.COLOR_TEXT1}); } ${Row} > img { @@ -76,7 +77,7 @@ export const Card = styled(CardUni)` } ${TextDot} { - background: ${({ theme }) => theme.text1}; + background: var(${UI.COLOR_TEXT1}); } ${ButtonPrimary} { diff --git a/apps/cowswap-frontend/src/legacy/components/SearchModal/ManageTokens/ManageTokensMod.tsx b/apps/cowswap-frontend/src/legacy/components/SearchModal/ManageTokens/ManageTokensMod.tsx index f288c3c4b8..5c8af0a5de 100644 --- a/apps/cowswap-frontend/src/legacy/components/SearchModal/ManageTokens/ManageTokensMod.tsx +++ b/apps/cowswap-frontend/src/legacy/components/SearchModal/ManageTokens/ManageTokensMod.tsx @@ -1,26 +1,23 @@ import { ChangeEventHandler, RefObject, useCallback, useMemo, useRef, useState } from 'react' +import { useNetworkName, useTheme } from '@cowprotocol/common-hooks' +import { getEtherscanLink as getExplorerLink, isAddress } from '@cowprotocol/common-utils' +import { TokenSymbol, Row, RowBetween, RowFixed } from '@cowprotocol/ui' +import { ExternalLink, ExternalLinkIcon } from '@cowprotocol/ui' +import { useWalletInfo } from '@cowprotocol/wallet' import { Token } from '@uniswap/sdk-core' import { Trans } from '@lingui/macro' import styled from 'styled-components/macro' import Column from 'legacy/components/Column' -import Row, { RowBetween, RowFixed } from 'legacy/components/Row' import { CurrencyModalView } from 'legacy/components/SearchModal/CurrencySearchModal' import { PaddedColumn, SearchInput, Separator } from 'legacy/components/SearchModal/styleds' import { useToken } from 'legacy/hooks/Tokens' -import useNetworkName from 'legacy/hooks/useNetworkName' -import useTheme from 'legacy/hooks/useTheme' import { useRemoveUserAddedToken, useUserAddedTokens } from 'legacy/state/user/hooks' -import { ButtonText, ExternalLink, ExternalLinkIcon, ThemedText, TrashIcon } from 'legacy/theme' -import { isAddress } from 'legacy/utils' -import { getEtherscanLink as getExplorerLink } from 'legacy/utils' - -import { useWalletInfo } from 'modules/wallet' +import { ButtonText, ThemedText, TrashIcon } from 'legacy/theme' import { CurrencyLogo } from 'common/pure/CurrencyLogo' -import { TokenSymbol } from 'common/pure/TokenSymbol' import { ImportTokensRowProps } from './index' diff --git a/apps/cowswap-frontend/src/legacy/components/SearchModal/ManageTokens/index.tsx b/apps/cowswap-frontend/src/legacy/components/SearchModal/ManageTokens/index.tsx index 5180018406..25b2642d96 100644 --- a/apps/cowswap-frontend/src/legacy/components/SearchModal/ManageTokens/index.tsx +++ b/apps/cowswap-frontend/src/legacy/components/SearchModal/ManageTokens/index.tsx @@ -1,14 +1,17 @@ +import { Row, RowFixed, RowBetween } from '@cowprotocol/ui' +import { LinkIcon } from '@cowprotocol/ui' import { Token } from '@uniswap/sdk-core' import styled, { DefaultTheme } from 'styled-components/macro' import Card from 'legacy/components/Card' import Column from 'legacy/components/Column' -import Row, { RowFixed, RowBetween } from 'legacy/components/Row' import { CurrencyModalView } from 'legacy/components/SearchModal/CurrencySearchModal' import ImportRow from 'legacy/components/SearchModal/ImportRow' import { Separator } from 'legacy/components/SearchModal/styleds' -import { ButtonText, LinkIcon } from 'legacy/theme' +import { ButtonText } from 'legacy/theme' + +import { UI } from 'common/constants/theme' import ManageTokensMod, { ManageTokensProps, Footer } from './ManageTokensMod' @@ -31,7 +34,7 @@ export const Wrapper = styled.div` } ${RowBetween} > div { - color: ${({ theme }) => theme.text1}; + color: var(${UI.COLOR_TEXT1}); } // Custom Tokens Title @@ -41,7 +44,7 @@ export const Wrapper = styled.div` // Token name ${RowBetween} > div > a > div { - color: ${({ theme }) => theme.text1}; + color: var(${UI.COLOR_TEXT1}); } ${RowFixed} > svg, diff --git a/apps/cowswap-frontend/src/legacy/components/SearchModal/TokenImportCard/TokenImportCardMod.tsx b/apps/cowswap-frontend/src/legacy/components/SearchModal/TokenImportCard/TokenImportCardMod.tsx index 97794db10d..e382e4e1da 100644 --- a/apps/cowswap-frontend/src/legacy/components/SearchModal/TokenImportCard/TokenImportCardMod.tsx +++ b/apps/cowswap-frontend/src/legacy/components/SearchModal/TokenImportCard/TokenImportCardMod.tsx @@ -1,3 +1,7 @@ +import { getEtherscanLink as getExplorerLink } from '@cowprotocol/common-utils' +import { RowFixed } from '@cowprotocol/ui' +import { ExternalLink } from '@cowprotocol/ui' +import { useWalletInfo } from '@cowprotocol/wallet' import { Token } from '@uniswap/sdk-core' import { TokenList } from '@uniswap/token-lists' @@ -9,11 +13,7 @@ import styled, { useTheme } from 'styled-components/macro' import Card from 'legacy/components/Card' import { AutoColumn } from 'legacy/components/Column' import ListLogo from 'legacy/components/ListLogo' -import { RowFixed } from 'legacy/components/Row' -import { ExternalLink, ThemedText } from 'legacy/theme' -import { getEtherscanLink as getExplorerLink } from 'legacy/utils' - -import { useWalletInfo } from 'modules/wallet' +import { ThemedText } from 'legacy/theme' import { CurrencyLogo } from 'common/pure/CurrencyLogo' diff --git a/apps/cowswap-frontend/src/legacy/components/SearchModal/styleds.tsx b/apps/cowswap-frontend/src/legacy/components/SearchModal/styleds.tsx index 814ce124a4..652b80ed9c 100644 --- a/apps/cowswap-frontend/src/legacy/components/SearchModal/styleds.tsx +++ b/apps/cowswap-frontend/src/legacy/components/SearchModal/styleds.tsx @@ -1,14 +1,15 @@ +import { LoadingRows as BaseLoadingRows, RowBetween } from '@cowprotocol/ui' + import styled from 'styled-components/macro' -import { LoadingRows as BaseLoadingRows } from 'legacy/components/Loader/styled' +import { UI } from 'common/constants/theme' import { AutoColumn } from '../Column' -import { RowBetween } from '../Row' export const TextDot = styled.div` height: 3px; width: 3px; - background-color: ${({ theme }) => theme.text2}; + background-color: var(${UI.COLOR_TEXT2}); border-radius: 50%; ` @@ -52,7 +53,7 @@ export const SearchInput = styled.input` border: none; outline: none; border-radius: 20px; - color: ${({ theme }) => theme.text1}; + color: var(${UI.COLOR_TEXT1}); border-style: solid; border: 1px solid ${({ theme }) => theme.bg3}; -webkit-appearance: none; diff --git a/apps/cowswap-frontend/src/legacy/components/Settings/SettingsMod.tsx b/apps/cowswap-frontend/src/legacy/components/Settings/SettingsMod.tsx index 63913309a9..76589bf0cb 100644 --- a/apps/cowswap-frontend/src/legacy/components/Settings/SettingsMod.tsx +++ b/apps/cowswap-frontend/src/legacy/components/Settings/SettingsMod.tsx @@ -1,26 +1,28 @@ import { useCallback, useContext, useRef, useState } from 'react' +import { + showExpertModeConfirmationAnalytics, + toggleExpertModeAnalytics, + toggleRecepientAddressAnalytics, +} from '@cowprotocol/analytics' +import { useOnClickOutside } from '@cowprotocol/common-hooks' +import { RowBetween, RowFixed } from '@cowprotocol/ui' + import { Trans } from '@lingui/macro' import { Settings } from 'react-feather' import { Text } from 'rebass' import styled, { ThemeContext } from 'styled-components/macro' -import { - showExpertModeConfirmationAnalytics, - toggleExpertModeAnalytics, - toggleRecepientAddressAnalytics, -} from 'legacy/components/analytics' import { AutoColumn } from 'legacy/components/Column' import QuestionHelper from 'legacy/components/QuestionHelper' -import { RowBetween, RowFixed } from 'legacy/components/Row' -import Toggle from 'legacy/components/Toggle' +import { Toggle } from 'legacy/components/Toggle' import TransactionSettings from 'legacy/components/TransactionSettings' -import { useOnClickOutside } from 'legacy/hooks/useOnClickOutside' import { useModalIsOpen, useToggleSettingsMenu } from 'legacy/state/application/hooks' import { ApplicationModal } from 'legacy/state/application/reducer' import { useExpertModeManager, useRecipientToggleManager } from 'legacy/state/user/hooks' import { ThemedText } from 'legacy/theme' +import { UI } from 'common/constants/theme' import { ExpertModeModal } from 'common/pure/ExpertModeModal' import { SettingsTabProp } from './index' @@ -30,7 +32,7 @@ export const StyledMenuIcon = styled(Settings)` width: 20px; > * { - stroke: ${({ theme }) => theme.text2}; + stroke: var(${UI.COLOR_TEXT2}); } :hover { diff --git a/apps/cowswap-frontend/src/legacy/components/Settings/index.tsx b/apps/cowswap-frontend/src/legacy/components/Settings/index.tsx index d3e255ac47..c166d8cf30 100644 --- a/apps/cowswap-frontend/src/legacy/components/Settings/index.tsx +++ b/apps/cowswap-frontend/src/legacy/components/Settings/index.tsx @@ -1,10 +1,11 @@ +import { RowFixed } from '@cowprotocol/ui' import { Percent } from '@uniswap/sdk-core' import { transparentize } from 'polished' import styled from 'styled-components/macro' import { WithClassName } from 'types' -import { RowFixed } from 'legacy/components/Row' +import { UI } from 'common/constants/theme' import SettingsMod, { StyledMenuButton, MenuFlyout, StyledMenuIcon, EmojiWrapper } from './SettingsMod' @@ -12,8 +13,8 @@ const Settings = styled(SettingsMod)` ${MenuFlyout} { box-shadow: ${({ theme }) => theme.boxShadow2}; border: 1px solid ${({ theme }) => transparentize(0.95, theme.white)}; - background-color: ${({ theme }) => theme.bg1}; - color: ${({ theme }) => theme.text1}; + background-color: var(${UI.COLOR_CONTAINER_BG_01}); + color: var(${UI.COLOR_TEXT1}); padding: 0; margin: 0; top: 36px; @@ -23,7 +24,7 @@ const Settings = styled(SettingsMod)` ${RowFixed} { > div { - color: ${({ theme }) => theme.text1}; + color: var(${UI.COLOR_TEXT1}); opacity: 0.85; } } @@ -42,7 +43,7 @@ const Settings = styled(SettingsMod)` &:focus { cursor: pointer; outline: none; - color: ${({ theme }) => theme.text1}; + color: var(${UI.COLOR_TEXT1}); } svg { @@ -57,7 +58,7 @@ const Settings = styled(SettingsMod)` &:hover svg > path, &:hover svg > circle { - stroke: ${({ theme }) => theme.text1}; + stroke: var(${UI.COLOR_TEXT1}); } } diff --git a/apps/cowswap-frontend/src/legacy/components/SideMenu/index.tsx b/apps/cowswap-frontend/src/legacy/components/SideMenu/index.tsx index ca314064a2..600010d723 100644 --- a/apps/cowswap-frontend/src/legacy/components/SideMenu/index.tsx +++ b/apps/cowswap-frontend/src/legacy/components/SideMenu/index.tsx @@ -1,6 +1,8 @@ import { transparentize } from 'polished' import styled from 'styled-components/macro' +import { UI } from 'common/constants/theme' + export const SideMenu = styled.div<{ isAccountPage?: boolean }>` display: flex; flex-flow: column wrap; @@ -8,7 +10,7 @@ export const SideMenu = styled.div<{ isAccountPage?: boolean }>` font-weight: 500; line-height: 1; margin: 0 24px 0 0; - color: ${({ theme }) => theme.text1}; + color: var(${UI.COLOR_TEXT1}); height: max-content; position: sticky; top: 0; diff --git a/apps/cowswap-frontend/src/legacy/components/Stepper/index.tsx b/apps/cowswap-frontend/src/legacy/components/Stepper/index.tsx index c86fdc0f68..b06c382c86 100644 --- a/apps/cowswap-frontend/src/legacy/components/Stepper/index.tsx +++ b/apps/cowswap-frontend/src/legacy/components/Stepper/index.tsx @@ -1,7 +1,9 @@ +import CheckCircle from '@cowprotocol/assets/cow-swap/check.svg' + import { transparentize } from 'polished' import styled from 'styled-components/macro' -import CheckCircle from 'legacy/assets/cow-swap/check.svg' +import { UI } from 'common/constants/theme' export const Wrapper = styled.div<{ totalSteps: number }>` width: 100%; @@ -84,7 +86,11 @@ export const Step = styled.div<{ > b { color: ${({ isActiveStep, completedStep, theme }) => - completedStep ? theme.text1 : isActiveStep ? theme.text1 : transparentize(0.4, theme.text1)}; + completedStep + ? `var(${UI.COLOR_TEXT1})` + : isActiveStep + ? `var(${UI.COLOR_TEXT1})` + : transparentize(0.4, theme.text1)}; font-weight: ${({ isActiveStep, completedStep }) => (completedStep ? '300' : isActiveStep ? 'bold' : '300')}; text-align: center; diff --git a/apps/cowswap-frontend/src/legacy/components/SwapWarnings/index.tsx b/apps/cowswap-frontend/src/legacy/components/SwapWarnings/index.tsx index 557df61a87..75ff6f23cc 100644 --- a/apps/cowswap-frontend/src/legacy/components/SwapWarnings/index.tsx +++ b/apps/cowswap-frontend/src/legacy/components/SwapWarnings/index.tsx @@ -1,17 +1,19 @@ import React, { useContext, useMemo } from 'react' +import { MouseoverTooltipContent } from '@cowprotocol/ui' import { Fraction } from '@uniswap/sdk-core' import { AlertTriangle } from 'react-feather' import styled, { ThemeContext } from 'styled-components/macro' -import { MouseoverTooltipContent } from 'legacy/components/Tooltip' -import { useHighFeeWarning } from 'legacy/state/swap/hooks' import TradeGp from 'legacy/state/swap/TradeGp' import { useIsDarkMode } from 'legacy/state/user/hooks' +import { useHighFeeWarning } from 'modules/swap/hooks/useSwapState' import { StyledInfoIcon } from 'modules/swap/pure/styled' +import { UI } from 'common/constants/theme' + import { AuxInformationContainer } from '../swap/styleds' interface HighFeeContainerProps { @@ -52,7 +54,7 @@ const WarningContainer = styled(AuxInformationContainer).attrs((props) => ({ : LOW_TIER_FEE ? theme.alert : theme.info}; - color: ${({ theme }) => theme.text1}; + color: var(${UI.COLOR_TEXT1}); padding: ${({ padding = '16px' }) => padding}; width: ${({ width = '100%' }) => width}; border-radius: 16px; diff --git a/apps/cowswap-frontend/src/legacy/components/Toggle/index.tsx b/apps/cowswap-frontend/src/legacy/components/Toggle/index.tsx index 57779b537f..2b1a82c409 100644 --- a/apps/cowswap-frontend/src/legacy/components/Toggle/index.tsx +++ b/apps/cowswap-frontend/src/legacy/components/Toggle/index.tsx @@ -4,24 +4,26 @@ import { darken, transparentize } from 'polished' import styled, { keyframes } from 'styled-components/macro' import { WithClassName } from 'types' +import { UI } from 'common/constants/theme' + const turnOnToggle = keyframes` from { - margin-left: 0em; + margin-left: 0; margin-right: 2.2em; } to { margin-left: 2.2em; - margin-right: 0em; + margin-right: 0; } ` const turnOffToggle = keyframes` from { margin-left: 2.2em; - margin-right: 0em; + margin-right: 0; } to { - margin-left: 0em; + margin-left: 0; margin-right: 2.2em; } ` @@ -54,7 +56,7 @@ export const ToggleElement = styled.span<{ isActive?: boolean; bgColor?: string; const Wrapper = styled.button<{ isActive?: boolean; activeElement?: boolean }>` align-items: center; - background: ${({ theme }) => theme.bg1}; + background: var(${UI.COLOR_CONTAINER_BG_01}); background: ${({ theme, isActive }) => (isActive ? theme.bg2 : theme.grey1)}; border: none; border-radius: 20px; @@ -97,7 +99,7 @@ export interface ToggleProps extends WithClassName { isDisabled?: boolean // Mod } -export default function Toggle({ id, bgColor, isActive, toggle, className, isDisabled }: ToggleProps) { +export function Toggle({ id, bgColor, isActive, toggle, className, isDisabled }: ToggleProps) { const [isInitialToggleLoad, setIsInitialToggleLoad] = useState(true) const switchToggle = () => { diff --git a/apps/cowswap-frontend/src/legacy/components/Tokens/BalanceCell.tsx b/apps/cowswap-frontend/src/legacy/components/Tokens/BalanceCell.tsx index 9f22e84b80..3c1029cba8 100644 --- a/apps/cowswap-frontend/src/legacy/components/Tokens/BalanceCell.tsx +++ b/apps/cowswap-frontend/src/legacy/components/Tokens/BalanceCell.tsx @@ -1,12 +1,9 @@ +import { useTheme } from '@cowprotocol/common-hooks' +import { TokenAmount } from '@cowprotocol/ui' +import { Loader } from '@cowprotocol/ui' +import { useWalletInfo } from '@cowprotocol/wallet' import { Token, CurrencyAmount } from '@uniswap/sdk-core' -import Loader from 'legacy/components/Loader' -import useTheme from 'legacy/hooks/useTheme' - -import { useWalletInfo } from 'modules/wallet' - -import { TokenAmount } from 'common/pure/TokenAmount' - import { BalanceValue } from './styled' type BalanceCellProps = { diff --git a/apps/cowswap-frontend/src/legacy/components/Tokens/FavouriteTokenButton.tsx b/apps/cowswap-frontend/src/legacy/components/Tokens/FavouriteTokenButton.tsx index fee13ac2fb..c87cbaecfb 100644 --- a/apps/cowswap-frontend/src/legacy/components/Tokens/FavouriteTokenButton.tsx +++ b/apps/cowswap-frontend/src/legacy/components/Tokens/FavouriteTokenButton.tsx @@ -1,13 +1,15 @@ import { MouseEventHandler, useCallback, useMemo } from 'react' +import { useTheme } from '@cowprotocol/common-hooks' +import { ButtonStar } from '@cowprotocol/ui' import { Token } from '@uniswap/sdk-core' import styled from 'styled-components/macro' -import { ButtonStar } from 'legacy/components/Button' -import useTheme from 'legacy/hooks/useTheme' import { useFavouriteTokens, useToggleFavouriteToken } from 'legacy/state/user/hooks' +import { UI } from 'common/constants/theme' + export const StyledButtonStar = styled(ButtonStar)` z-index: 9; ` @@ -38,7 +40,7 @@ export default function FavouriteTokenButton({ tokenData }: FavouriteTokenButton return ( ) diff --git a/apps/cowswap-frontend/src/legacy/components/Tokens/FiatBalanceCell.tsx b/apps/cowswap-frontend/src/legacy/components/Tokens/FiatBalanceCell.tsx index 09f9dd696c..a525a4d522 100644 --- a/apps/cowswap-frontend/src/legacy/components/Tokens/FiatBalanceCell.tsx +++ b/apps/cowswap-frontend/src/legacy/components/Tokens/FiatBalanceCell.tsx @@ -1,13 +1,11 @@ +import { FiatAmount } from '@cowprotocol/ui' +import { MouseoverTooltip } from '@cowprotocol/ui' import { CurrencyAmount, Token } from '@uniswap/sdk-core' import { Trans } from '@lingui/macro' -import { MouseoverTooltip } from 'legacy/components/Tooltip' - import { useUsdAmount } from 'modules/usdAmount' -import { FiatAmount } from 'common/pure/FiatAmount' - import { BalanceValue, FiatValue, InfoCircle } from './styled' type FiatBalanceCellProps = { diff --git a/apps/cowswap-frontend/src/legacy/components/Tokens/TokensTable.tsx b/apps/cowswap-frontend/src/legacy/components/Tokens/TokensTable.tsx index 71c5a5780e..e42ee2aed5 100644 --- a/apps/cowswap-frontend/src/legacy/components/Tokens/TokensTable.tsx +++ b/apps/cowswap-frontend/src/legacy/components/Tokens/TokensTable.tsx @@ -1,16 +1,15 @@ import { useCallback, useEffect, useMemo, useRef, useState } from 'react' +import { useFilterTokens, usePrevious } from '@cowprotocol/common-hooks' import { Token } from '@uniswap/sdk-core' import { Trans } from '@lingui/macro' import { balanceComparator, useTokenComparator } from 'legacy/components/SearchModal/CurrencySearch/sorting' -import { ConfirmOperationType } from 'legacy/components/TransactionConfirmationModal' import { useErrorModal } from 'legacy/hooks/useErrorMessageAndModal' -import useFilterTokens from 'legacy/hooks/useFilterTokens' -import usePrevious from 'legacy/hooks/usePrevious' import useTransactionConfirmationModal from 'legacy/hooks/useTransactionConfirmationModal' import { useToggleWalletModal } from 'legacy/state/application/hooks' +import { ConfirmOperationType } from 'legacy/state/types' import { TokenAmounts } from 'modules/tokens' diff --git a/apps/cowswap-frontend/src/legacy/components/Tokens/TokensTableRow.tsx b/apps/cowswap-frontend/src/legacy/components/Tokens/TokensTableRow.tsx index 7ac7575b74..a633cc108d 100644 --- a/apps/cowswap-frontend/src/legacy/components/Tokens/TokensTableRow.tsx +++ b/apps/cowswap-frontend/src/legacy/components/Tokens/TokensTableRow.tsx @@ -1,28 +1,24 @@ import { useCallback, useEffect, useMemo, useState } from 'react' +import EtherscanImage from '@cowprotocol/assets/cow-swap/etherscan-icon.svg' +import { GP_VAULT_RELAYER } from '@cowprotocol/common-const' +import { usePrevious, useTheme } from '@cowprotocol/common-hooks' +import { getBlockExplorerUrl } from '@cowprotocol/common-utils' import { SupportedChainId as ChainId } from '@cowprotocol/cow-sdk' +import { TokenAmount, TokenSymbol, Loader } from '@cowprotocol/ui' +import { useWalletInfo } from '@cowprotocol/wallet' import { CurrencyAmount, MaxUint256, Token } from '@uniswap/sdk-core' import SVG from 'react-inlinesvg' import { Link } from 'react-router-dom' -import EtherscanImage from 'legacy/assets/cow-swap/etherscan-icon.svg' -import Loader from 'legacy/components/Loader' -import { ConfirmOperationType } from 'legacy/components/TransactionConfirmationModal' -import { GP_VAULT_RELAYER } from 'legacy/constants' import { useErrorModal } from 'legacy/hooks/useErrorMessageAndModal' -import usePrevious from 'legacy/hooks/usePrevious' -import useTheme from 'legacy/hooks/useTheme' import { useTokenAllowance } from 'legacy/hooks/useTokenAllowance' -import { getBlockExplorerUrl } from 'legacy/utils' import { parameterizeTradeRoute } from 'modules/trade/utils/parameterizeTradeRoute' -import { useWalletInfo } from 'modules/wallet' import { Routes } from 'common/constants/routes' import { useAreThereTokensWithSameSymbol } from 'common/hooks/useAreThereTokensWithSameSymbol' -import { TokenAmount } from 'common/pure/TokenAmount' -import { TokenSymbol } from 'common/pure/TokenSymbol' import { CardsSpinner, ExtLink } from 'pages/Account/styled' import BalanceCell from './BalanceCell' @@ -40,6 +36,7 @@ import { } from './styled' import { ApprovalState, useApproveCallback } from '../../hooks/useApproveCallback/useApproveCallbackMod' +import { ConfirmOperationType } from '../../state/types' type DataRowParams = { tokenData: Token diff --git a/apps/cowswap-frontend/src/legacy/components/Tokens/styled.ts b/apps/cowswap-frontend/src/legacy/components/Tokens/styled.ts index 942abb6dae..f0eb8101d0 100644 --- a/apps/cowswap-frontend/src/legacy/components/Tokens/styled.ts +++ b/apps/cowswap-frontend/src/legacy/components/Tokens/styled.ts @@ -1,10 +1,11 @@ +import { BaseButton } from '@cowprotocol/ui' + import { transparentize } from 'polished' import { HelpCircle } from 'react-feather' import { Link } from 'react-router-dom' import styled from 'styled-components/macro' -import { BaseButton } from 'legacy/components/Button' - +import { UI } from 'common/constants/theme' import { CurrencyLogo } from 'common/pure/CurrencyLogo' export const TokenSearchInput = styled.input` @@ -14,7 +15,7 @@ export const TokenSearchInput = styled.input` width: 100%; align-self: flex-end; box-shadow: none; - background: ${({ theme }) => theme.grey1}; + background: var(${UI.COLOR_GREY}); border: 1px solid ${({ theme }) => theme.bg1}; border-radius: 21px; transition: background 0.2s ease-in-out, max-width 0.2s ease-in-out; @@ -25,7 +26,7 @@ export const TokenSearchInput = styled.input` &:focus { max-width: 500px; - background: ${({ theme }) => theme.bg1}; + background: var(${UI.COLOR_CONTAINER_BG_01}); outline: 0; ${({ theme }) => theme.mediaWidth.upToMedium` @@ -59,7 +60,7 @@ export const Wrapper = styled.div` width: 100%; border: none; padding: 0; - background: ${({ theme }) => theme.bg1}; + background: var(${UI.COLOR_CONTAINER_BG_01}); border-radius: 16px; display: grid; ` @@ -80,8 +81,8 @@ export const ResponsiveLogo = styled(CurrencyLogo)` width: 28px; height: 28px; border-radius: 28px; - background: ${({ theme }) => theme.bg1}; - color: ${({ theme }) => theme.text1}!important; // TODO: prevent styles override + background: var(${UI.COLOR_CONTAINER_BG_01}); + color: var(${UI.COLOR_TEXT1}) !important; // TODO: prevent styles override ${({ theme }) => theme.mediaWidth.upToMedium` width: 21px; @@ -166,7 +167,7 @@ export const ArrowButton = styled.button` ` export const Arrow = styled.div<{ faded: boolean }>` - color: ${({ theme }) => theme.text1}; + color: var(${UI.COLOR_TEXT1}); opacity: ${(props) => (props.faded ? 0.3 : 1)}; padding: 0 10px; user-select: none; @@ -207,7 +208,7 @@ export const Row = styled.div` `} &:hover { - background: ${({ theme }) => theme.grey1}; + background: var(${UI.COLOR_GREY}); } ` @@ -248,11 +249,11 @@ export const Cell = styled.div` transition: text-decoration-color 0.2s ease-in-out; overflow: hidden; display: flex; - color: ${({ theme }) => theme.text1}; + color: var(${UI.COLOR_TEXT1}); &:hover { - color: ${({ theme }) => theme.text1}; - text-decoration-color: ${({ theme }) => theme.text1}; + color: var(${UI.COLOR_TEXT1}); + text-decoration-color: var(${UI.COLOR_TEXT1}); } } ` @@ -263,7 +264,7 @@ export const IndexNumber = styled.span` ` export const BalanceValue = styled.span<{ hasBalance: boolean }>` - color: ${({ hasBalance, theme }) => (hasBalance ? theme.text1 : transparentize(0.3, theme.text1))}; + color: ${({ hasBalance, theme }) => (hasBalance ? `var(${UI.COLOR_TEXT1})` : transparentize(0.3, theme.text1))}; font-weight: 500; font-size: 14px; white-space: nowrap; @@ -297,7 +298,7 @@ export const TableButton = styled(BaseButton)<{ color?: string; outlined?: boole max-height: 100%; > path { - fill: ${({ theme }) => theme.text1}; + fill: var(${UI.COLOR_TEXT1}); } } @@ -416,7 +417,7 @@ export const FiatValue = styled.div` ` export const InfoCircle = styled(HelpCircle)` - stroke: ${({ theme }) => theme.text1}; + stroke: var(${UI.COLOR_TEXT1}); width: 15px; height: 15px; margin-left: 5px; diff --git a/apps/cowswap-frontend/src/legacy/components/TransactionConfirmationModal/DisplayLink.tsx b/apps/cowswap-frontend/src/legacy/components/TransactionConfirmationModal/DisplayLink.tsx index 8e52480795..e8dbc87f05 100644 --- a/apps/cowswap-frontend/src/legacy/components/TransactionConfirmationModal/DisplayLink.tsx +++ b/apps/cowswap-frontend/src/legacy/components/TransactionConfirmationModal/DisplayLink.tsx @@ -1,11 +1,12 @@ import React, { useContext } from 'react' +import { getBlockExplorerUrl, getEtherscanLink, getExplorerLabel } from '@cowprotocol/common-utils' + import { Text } from 'rebass' import { ThemeContext } from 'styled-components/macro' import { OrderStatus } from 'legacy/state/orders/actions' import { useOrder } from 'legacy/state/orders/hooks' -import { getBlockExplorerUrl, getEtherscanLink, getExplorerLabel } from 'legacy/utils' import { ExternalLinkCustom } from './styled' diff --git a/apps/cowswap-frontend/src/legacy/components/TransactionConfirmationModal/LegacyConfirmationPendingContent.tsx b/apps/cowswap-frontend/src/legacy/components/TransactionConfirmationModal/LegacyConfirmationPendingContent.tsx index b85cbee668..f7f117013c 100644 --- a/apps/cowswap-frontend/src/legacy/components/TransactionConfirmationModal/LegacyConfirmationPendingContent.tsx +++ b/apps/cowswap-frontend/src/legacy/components/TransactionConfirmationModal/LegacyConfirmationPendingContent.tsx @@ -1,23 +1,27 @@ import React, { ReactNode, useMemo } from 'react' +import alertImage from '@cowprotocol/assets/cow-swap/alert-circle.svg' +import checkImage from '@cowprotocol/assets/cow-swap/check.svg' +import { getChainCurrencySymbols } from '@cowprotocol/common-const' +import { shortenAddress } from '@cowprotocol/common-utils' +import { ExternalLink } from '@cowprotocol/ui' +import { + getWeb3ReactConnection, + useGnosisSafeInfo, + useWalletDetails, + useWalletInfo, + getIsMetaMask, + injectedConnection, +} from '@cowprotocol/wallet' import { useWeb3React } from '@web3-react/core' import { t, Trans } from '@lingui/macro' import { CheckCircle, UserCheck } from 'react-feather' import SVG from 'react-inlinesvg' -import alertImage from 'legacy/assets/cow-swap/alert-circle.svg' -import checkImage from 'legacy/assets/cow-swap/check.svg' import { MediumAndUp, useMediaQuery } from 'legacy/hooks/useMediaQuery' -import { ExternalLink } from 'legacy/theme' -import { shortenAddress } from 'legacy/utils' -import { getChainCurrencySymbols } from 'legacy/utils/gnosis_chain/hack' import { getStatusIcon } from 'modules/account/containers/AccountDetails' -import { useGnosisSafeInfo, useWalletDetails, useWalletInfo } from 'modules/wallet' -import { getIsMetaMask } from 'modules/wallet/api/utils/connection' -import { getWeb3ReactConnection } from 'modules/wallet/web3-react/connection' -import { injectedConnection } from 'modules/wallet/web3-react/connection/injected' import { ApproveComparison, @@ -33,7 +37,8 @@ import { WalletIcon, Wrapper, } from './styled' -import { ConfirmOperationType } from './types' + +import { ConfirmOperationType } from '../../state/types' enum WalletType { SAFE, diff --git a/apps/cowswap-frontend/src/legacy/components/TransactionConfirmationModal/index.cosmos.tsx b/apps/cowswap-frontend/src/legacy/components/TransactionConfirmationModal/index.cosmos.tsx index 85175f9bf8..0a1630b537 100644 --- a/apps/cowswap-frontend/src/legacy/components/TransactionConfirmationModal/index.cosmos.tsx +++ b/apps/cowswap-frontend/src/legacy/components/TransactionConfirmationModal/index.cosmos.tsx @@ -1,14 +1,15 @@ +import { COW, GNO } from '@cowprotocol/common-const' import { OrderClass, OrderKind, SupportedChainId } from '@cowprotocol/cow-sdk' import styled from 'styled-components/macro' -import { ConfirmOperationType } from 'legacy/components/TransactionConfirmationModal' -import { COW, GNO } from 'legacy/constants/tokens' -import store from 'legacy/state' import { addPendingOrder, OrderStatus } from 'legacy/state/orders/actions' +import { ConfirmOperationType } from 'legacy/state/types' import { LegacyConfirmationPendingContent } from './LegacyConfirmationPendingContent' +import { cowSwapStore } from '../../state' + const txHash = '0xe87e1d02b052daa9605abe018e8172feffd1bc38ed2284e6hhhhhh' + Date.now() const defaultProps = { @@ -40,7 +41,7 @@ const Fixtures = { ), } -store.dispatch( +cowSwapStore.dispatch( addPendingOrder({ id: txHash, chainId: 5, diff --git a/apps/cowswap-frontend/src/legacy/components/TransactionConfirmationModal/index.tsx b/apps/cowswap-frontend/src/legacy/components/TransactionConfirmationModal/index.tsx index 321445cb45..76dbd956da 100644 --- a/apps/cowswap-frontend/src/legacy/components/TransactionConfirmationModal/index.tsx +++ b/apps/cowswap-frontend/src/legacy/components/TransactionConfirmationModal/index.tsx @@ -1,23 +1,24 @@ import { useSetAtom } from 'jotai' import React, { ReactNode, useCallback, useEffect } from 'react' +import { useWalletInfo } from '@cowprotocol/wallet' import { Currency } from '@uniswap/sdk-core' import { getActivityState, useActivityDerivedState } from 'legacy/hooks/useActivityDerivedState' import { useMultipleActivityDescriptors } from 'legacy/hooks/useRecentActivity' -import { handleFollowPendingTxPopupAtom } from 'legacy/state/application/atoms' +import { ConfirmOperationType } from 'legacy/state/types' import { useSetIsConfirmationModalOpen } from 'modules/swap/state/surplusModal' -import { useWalletInfo } from 'modules/wallet' +import { SwapConfirmState } from 'modules/swap/state/swapConfirmAtom' +import { handleFollowPendingTxPopupAtom } from 'modules/wallet/state/followPendingTxPopupAtom' +import { PermitModal } from 'common/containers/PermitModal' import { useGetSurplusData } from 'common/hooks/useGetSurplusFiatValue' import { CowModal } from 'common/pure/Modal' import { TransactionSubmittedContent } from 'common/pure/TransactionSubmittedContent' +import { TradeAmounts } from 'common/types' import { LegacyConfirmationPendingContent } from './LegacyConfirmationPendingContent' -import { ConfirmOperationType } from './types' - -export * from './types' export interface ConfirmationModalProps { isOpen: boolean @@ -28,6 +29,8 @@ export interface ConfirmationModalProps { pendingText?: ReactNode currencyToAdd?: Currency | undefined operationType: ConfirmOperationType + tradeAmounts?: TradeAmounts | undefined + swapConfirmState?: SwapConfirmState | undefined } export function TransactionConfirmationModal({ @@ -39,6 +42,8 @@ export function TransactionConfirmationModal({ content, currencyToAdd, operationType, + tradeAmounts, + swapConfirmState, }: ConfirmationModalProps) { const { chainId } = useWalletInfo() const setShowFollowPendingTxPopup = useSetAtom(handleFollowPendingTxPopupAtom) @@ -72,7 +77,15 @@ export function TransactionConfirmationModal({ return ( - {attemptingTxn ? ( + {showPermitModal(swapConfirmState) ? ( + + ) : attemptingTxn ? ( theme.bg1}; + background: var(${UI.COLOR_CONTAINER_BG_01}); position: sticky; top: 0; left: 0; @@ -115,7 +119,7 @@ export const GPModalHeader = styled(RowBetween)` left: 0; width: 100%; padding: 16px 0; - background: ${({ theme }) => theme.bg1}; + background: var(${UI.COLOR_CONTAINER_BG_01}); z-index: 20; ` @@ -154,7 +158,7 @@ export const ButtonCustom = styled.button` border-radius: 16px; min-height: 52px; border: 1px solid ${({ theme }) => theme.border2}; - color: ${({ theme }) => theme.text1}; + color: var(${UI.COLOR_TEXT1}); background: transparent; outline: 0; padding: 8px 16px; @@ -181,7 +185,7 @@ export const UpperSection = styled.div` display: flex; flex-flow: column wrap; padding: 16px 16px 32px; - background: ${({ theme }) => theme.grey1}; + background: var(${UI.COLOR_GREY}); border-radius: 16px 16px 0 0; ${({ theme }) => theme.mediaWidth.upToSmall` @@ -246,7 +250,7 @@ export const StepsIconWrapper = styled.div` height: 100%; width: 100%; padding: 18px; - stroke: ${({ theme }) => theme.text1}; + stroke: var(${UI.COLOR_TEXT1}); } @keyframes spin { @@ -304,7 +308,7 @@ export const StepsWrapper = styled.div` flex: 1 1 auto; height: 2px; border: 0; - background: ${({ theme }) => theme.text1}; + background: var(${UI.COLOR_TEXT1}); margin: auto; position: absolute; width: 100%; @@ -319,7 +323,7 @@ export const StepsWrapper = styled.div` content: ''; height: 4px; width: 100%; - background: ${({ theme }) => theme.grey1}; + background: var(${UI.COLOR_GREY}); display: block; margin: 0; animation: Shrink 1s forwards linear; diff --git a/apps/cowswap-frontend/src/legacy/components/TransactionExecutedContent/index.tsx b/apps/cowswap-frontend/src/legacy/components/TransactionExecutedContent/index.tsx index 5f351f8b59..bcb94824a0 100644 --- a/apps/cowswap-frontend/src/legacy/components/TransactionExecutedContent/index.tsx +++ b/apps/cowswap-frontend/src/legacy/components/TransactionExecutedContent/index.tsx @@ -1,6 +1,6 @@ +import cowMeditatingSmooth from '@cowprotocol/assets/images/cow-meditating-smoooth.svg' import { SupportedChainId } from '@cowprotocol/cow-sdk' -import cowMeditatingSmooth from 'legacy/assets/images/cow-meditating-smoooth.svg' import { DisplayLink } from 'legacy/components/TransactionConfirmationModal/DisplayLink' import { Order } from 'legacy/state/orders/actions' diff --git a/apps/cowswap-frontend/src/legacy/components/TransactionExecutedContent/styled.ts b/apps/cowswap-frontend/src/legacy/components/TransactionExecutedContent/styled.ts index 92b126fb5c..5dc912d358 100644 --- a/apps/cowswap-frontend/src/legacy/components/TransactionExecutedContent/styled.ts +++ b/apps/cowswap-frontend/src/legacy/components/TransactionExecutedContent/styled.ts @@ -1,7 +1,6 @@ -import styled from 'styled-components/macro' +import { FiatAmount, TokenAmount } from '@cowprotocol/ui' -import { FiatAmount } from 'common/pure/FiatAmount' -import { TokenAmount } from 'common/pure/TokenAmount' +import styled from 'styled-components/macro' export const ExecutedWrapper = styled.div` display: flex; diff --git a/apps/cowswap-frontend/src/legacy/components/TransactionSettings/TransactionSettingsMod.tsx b/apps/cowswap-frontend/src/legacy/components/TransactionSettings/TransactionSettingsMod.tsx index ae8541430c..7b286b19a8 100644 --- a/apps/cowswap-frontend/src/legacy/components/TransactionSettings/TransactionSettingsMod.tsx +++ b/apps/cowswap-frontend/src/legacy/components/TransactionSettings/TransactionSettingsMod.tsx @@ -1,14 +1,7 @@ import { useContext, useState } from 'react' -import { Percent } from '@uniswap/sdk-core' - -import { Trans } from '@lingui/macro' -import { darken } from 'polished' -import styled, { ThemeContext } from 'styled-components/macro' - -import { orderExpirationTimeAnalytics, slippageToleranceAnalytics } from 'legacy/components/analytics' -import { AutoColumn } from 'legacy/components/Column' -import { RowBetween, RowFixed } from 'legacy/components/Row' +import { orderExpirationTimeAnalytics, slippageToleranceAnalytics } from '@cowprotocol/analytics' +import { DEFAULT_DEADLINE_FROM_NOW } from '@cowprotocol/common-const' import { DEFAULT_SLIPPAGE_BPS, HIGH_ETH_FLOW_SLIPPAGE_BIPS, @@ -20,16 +13,24 @@ import { MINIMUM_ETH_FLOW_SLIPPAGE, MINIMUM_ETH_FLOW_SLIPPAGE_BIPS, MINIMUM_ORDER_VALID_TO_TIME_SECONDS, -} from 'legacy/constants' -import { DEFAULT_DEADLINE_FROM_NOW } from 'legacy/constants/misc' +} from '@cowprotocol/common-const' +import { RowBetween, RowFixed } from '@cowprotocol/ui' +import { useWalletInfo } from '@cowprotocol/wallet' +import { Percent } from '@uniswap/sdk-core' + +import { Trans } from '@lingui/macro' +import { darken } from 'polished' +import styled, { ThemeContext } from 'styled-components/macro' + +import { AutoColumn } from 'legacy/components/Column' import { useSetUserSlippageTolerance, useUserSlippageTolerance, useUserTransactionTTL } from 'legacy/state/user/hooks' import { ThemedText } from 'legacy/theme' import { useIsEoaEthFlow } from 'modules/swap/hooks/useIsEoaEthFlow' import { getNativeOrderDeadlineTooltip, getNonNativeOrderDeadlineTooltip } from 'modules/swap/pure/Row/RowDeadline' import { getNativeSlippageTooltip, getNonNativeSlippageTooltip } from 'modules/swap/pure/Row/RowSlippageContent' -import { useWalletInfo } from 'modules/wallet' +import { UI } from 'common/constants/theme' import useNativeCurrency from 'lib/hooks/useNativeCurrency' import QuestionHelper from '../QuestionHelper' @@ -47,7 +48,7 @@ enum DeadlineError { } export const FancyButton = styled.button` - color: ${({ theme }) => theme.text1}; + color: var(${UI.COLOR_TEXT1}); align-items: center; height: 2rem; border-radius: 36px; @@ -57,7 +58,7 @@ export const FancyButton = styled.button` /* border: 1px solid ${({ theme }) => theme.bg3}; */ border: 0; // mod outline: none; - /* background: ${({ theme }) => theme.bg1}; */ + /* background: var(${UI.COLOR_CONTAINER_BG_01}); */ background: ${({ theme }) => theme.bg2}; // mod :hover { /* border: 1px solid ${({ theme }) => theme.bg4}; */ @@ -84,7 +85,7 @@ const Option = styled(FancyButton)<{ active: boolean }>` ` export const Input = styled.input` - background: ${({ theme }) => theme.bg1}; + background: var(${UI.COLOR_CONTAINER_BG_01}); font-size: 16px; width: auto; outline: none; @@ -301,7 +302,7 @@ export default function TransactionSettings({ placeholderSlippage }: Transaction fontSize: '14px', paddingTop: '7px', // color: slippageError ? 'red' : '#F3841E', - color: slippageError ? theme.danger : theme.warning, // MOD + color: slippageError ? `var(${UI.COLOR_DANGER})` : theme.warning, // MOD }} > {slippageError ? ( diff --git a/apps/cowswap-frontend/src/legacy/components/TransactionSettings/index.tsx b/apps/cowswap-frontend/src/legacy/components/TransactionSettings/index.tsx index 34734c77d9..dfa63150f2 100644 --- a/apps/cowswap-frontend/src/legacy/components/TransactionSettings/index.tsx +++ b/apps/cowswap-frontend/src/legacy/components/TransactionSettings/index.tsx @@ -1,7 +1,9 @@ +import { RowBetween, RowFixed } from '@cowprotocol/ui' + import { darken } from 'polished' import styled from 'styled-components/macro' -import { RowBetween, RowFixed } from 'legacy/components/Row' +import { UI } from 'common/constants/theme' import SlippageTabsMod, { TransactionSettingsProps, OptionCustom } from './TransactionSettingsMod' @@ -15,7 +17,7 @@ const Wrapper = styled.div` } ${OptionCustom} { - background-color: ${({ theme }) => theme.grey1}; + background-color: var(${UI.COLOR_GREY}); border: 0; > div > input { @@ -27,18 +29,18 @@ const Wrapper = styled.div` > div > input::placeholder { opacity: 0.5; - color: ${({ theme }) => theme.text1}; + color: var(${UI.COLOR_TEXT1}); } } ${RowFixed} { > div { - color: ${({ theme }) => theme.text1}; + color: var(${UI.COLOR_TEXT1}); opacity: 0.85; } > button { - background-color: ${({ theme }) => theme.grey1}; + background-color: var(${UI.COLOR_GREY}); border: 0; } @@ -49,7 +51,7 @@ const Wrapper = styled.div` > button > input::placeholder { background: transparent; opacity: 0.5; - color: ${({ theme }) => theme.text1}; + color: var(${UI.COLOR_TEXT1}); } } ` diff --git a/apps/cowswap-frontend/src/legacy/components/Version/index.tsx b/apps/cowswap-frontend/src/legacy/components/Version/index.tsx index 42d2e7f177..ab78ef57e9 100644 --- a/apps/cowswap-frontend/src/legacy/components/Version/index.tsx +++ b/apps/cowswap-frontend/src/legacy/components/Version/index.tsx @@ -1,14 +1,18 @@ +import { + CODE_LINK, + DEFAULT_NETWORK_FOR_LISTS, + GP_SETTLEMENT_CONTRACT_ADDRESS, + GP_VAULT_RELAYER, +} from '@cowprotocol/common-const' +import { getEtherscanLink } from '@cowprotocol/common-utils' import contractsPkg from '@cowprotocol/contracts/package.json' import { SupportedChainId as ChainId } from '@cowprotocol/cow-sdk' +import { ExternalLink } from '@cowprotocol/ui' +import { useWalletInfo } from '@cowprotocol/wallet' import styled from 'styled-components/macro' -import { CODE_LINK, GP_VAULT_RELAYER, GP_SETTLEMENT_CONTRACT_ADDRESS } from 'legacy/constants' -import { DEFAULT_NETWORK_FOR_LISTS } from 'legacy/constants/lists' -import { ExternalLink } from 'legacy/theme' -import { getEtherscanLink } from 'legacy/utils' - -import { useWalletInfo } from 'modules/wallet' +import { UI } from 'common/constants/theme' // eslint-disable-next-line @nx/enforce-module-boundaries import pkg from '../../../../../../package.json' @@ -67,7 +71,7 @@ const StyledPolling = styled.div` flex-flow: column nowrap; align-items: flex-start; padding: 16px 0; - color: ${({ theme }) => theme.text1}; + color: var(${UI.COLOR_TEXT1}); gap: 10px; ` diff --git a/apps/cowswap-frontend/src/modules/wallet/web3-react/hooks/useEagerlyConnect.ts b/apps/cowswap-frontend/src/legacy/components/Web3Provider/hooks/useEagerlyConnect.ts similarity index 73% rename from apps/cowswap-frontend/src/modules/wallet/web3-react/hooks/useEagerlyConnect.ts rename to apps/cowswap-frontend/src/legacy/components/Web3Provider/hooks/useEagerlyConnect.ts index ddec61ccf5..cc5021f357 100644 --- a/apps/cowswap-frontend/src/modules/wallet/web3-react/hooks/useEagerlyConnect.ts +++ b/apps/cowswap-frontend/src/legacy/components/Web3Provider/hooks/useEagerlyConnect.ts @@ -1,18 +1,16 @@ import { useEffect } from 'react' +import { getCurrentChainIdFromUrl, isInjectedWidget } from '@cowprotocol/common-utils' +import { + BACKFILLABLE_WALLETS, + getWeb3ReactConnection, + injectedWidgetConnection, + networkConnection, + gnosisSafeConnection, +} from '@cowprotocol/wallet' import { Connector } from '@web3-react/types' -import { useAppSelector } from 'legacy/state/hooks' - -import { BACKFILLABLE_WALLETS } from 'modules/wallet/api/types' - -import { isInjectedWidget } from 'common/utils/isInjectedWidget' -import { getCurrentChainIdFromUrl } from 'utils/getCurrentChainIdFromUrl' - -import { getWeb3ReactConnection } from '../connection' -import { injectedWidgetConnection } from '../connection/injectedWidget' -import { networkConnection } from '../connection/network' -import { gnosisSafeConnection } from '../connection/safe' +import { useAppSelector } from '../../../state/hooks' async function connect(connector: Connector) { const chainId = getCurrentChainIdFromUrl() diff --git a/apps/cowswap-frontend/src/modules/wallet/web3-react/hooks/useOrderedConnections.ts b/apps/cowswap-frontend/src/legacy/components/Web3Provider/hooks/useOrderedConnections.ts similarity index 79% rename from apps/cowswap-frontend/src/modules/wallet/web3-react/hooks/useOrderedConnections.ts rename to apps/cowswap-frontend/src/legacy/components/Web3Provider/hooks/useOrderedConnections.ts index 622c8df2cc..8203dc8bde 100644 --- a/apps/cowswap-frontend/src/modules/wallet/web3-react/hooks/useOrderedConnections.ts +++ b/apps/cowswap-frontend/src/legacy/components/Web3Provider/hooks/useOrderedConnections.ts @@ -1,13 +1,11 @@ import { useMemo } from 'react' -import { useAppSelector } from 'legacy/state/hooks' - -import { BACKFILLABLE_WALLETS, ConnectionType } from 'modules/wallet' -import { getWeb3ReactConnection } from 'modules/wallet/web3-react/connection' +import { isInjectedWidget } from '@cowprotocol/common-utils' +import { BACKFILLABLE_WALLETS, ConnectionType, getWeb3ReactConnection } from '@cowprotocol/wallet' -import { isInjectedWidget } from 'common/utils/isInjectedWidget' +import { useAppSelector } from 'legacy/state/hooks' -const SELECTABLE_WALLETS = [...BACKFILLABLE_WALLETS, ConnectionType.FORTMATIC] +const SELECTABLE_WALLETS = [...BACKFILLABLE_WALLETS] // TODO: The logic looks very similar with useEagerlyConnect export function useOrderedConnections() { diff --git a/apps/cowswap-frontend/src/legacy/components/Web3Provider/index.tsx b/apps/cowswap-frontend/src/legacy/components/Web3Provider/index.tsx index fb57ba9b28..934d45baf0 100644 --- a/apps/cowswap-frontend/src/legacy/components/Web3Provider/index.tsx +++ b/apps/cowswap-frontend/src/legacy/components/Web3Provider/index.tsx @@ -1,14 +1,15 @@ import { ReactNode, useMemo } from 'react' +import { getConnectionName, Web3ReactConnection } from '@cowprotocol/wallet' import { Web3ReactHooks, Web3ReactProvider } from '@web3-react/core' import { Connector } from '@web3-react/types' -import { useOrderedConnections, useEagerlyConnect } from 'modules/wallet' -import { getConnectionName } from 'modules/wallet/api/utils/connection' -import { Web3ReactConnection } from 'modules/wallet/web3-react/types' +import { useEagerlyConnect } from './hooks/useEagerlyConnect' +import { useOrderedConnections } from './hooks/useOrderedConnections' export default function Web3Provider({ children }: { children: ReactNode }) { useEagerlyConnect() + const connections = useOrderedConnections() const connectors: [Connector, Web3ReactHooks][] = connections.map(({ hooks, connector }) => [connector, hooks]) diff --git a/apps/cowswap-frontend/src/legacy/components/analytics/pixel/constants.ts b/apps/cowswap-frontend/src/legacy/components/analytics/pixel/constants.ts deleted file mode 100644 index ab431341be..0000000000 --- a/apps/cowswap-frontend/src/legacy/components/analytics/pixel/constants.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { isEns, isProd } from 'legacy/utils/environments' - -export const PIXEL_ENABLED = isProd || isEns - -export enum PIXEL_EVENTS { - INIT = 'init', - CONNECT_WALLET = 'connect_wallet', - POST_TRADE = 'post_trade', -} diff --git a/apps/cowswap-frontend/src/legacy/components/analytics/pixel/facebook.ts b/apps/cowswap-frontend/src/legacy/components/analytics/pixel/facebook.ts deleted file mode 100644 index 024b01b9b4..0000000000 --- a/apps/cowswap-frontend/src/legacy/components/analytics/pixel/facebook.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { PIXEL_EVENTS } from './constants' -import { sendPixel } from './utils' - -const events = { - [PIXEL_EVENTS.INIT]: 'InitiateCheckout', - [PIXEL_EVENTS.CONNECT_WALLET]: 'Contact', - [PIXEL_EVENTS.POST_TRADE]: 'Lead', -} - -export const sendFacebookEvent = sendPixel((event) => { - window.fbq?.('track', events[event]) -}) diff --git a/apps/cowswap-frontend/src/legacy/components/analytics/pixel/linkedin.ts b/apps/cowswap-frontend/src/legacy/components/analytics/pixel/linkedin.ts deleted file mode 100644 index f041dcb559..0000000000 --- a/apps/cowswap-frontend/src/legacy/components/analytics/pixel/linkedin.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { PIXEL_EVENTS } from './constants' -import { sendPixel } from './utils' - -const events = { - [PIXEL_EVENTS.INIT]: 10759506, - [PIXEL_EVENTS.CONNECT_WALLET]: 10759514, - [PIXEL_EVENTS.POST_TRADE]: 10759522, -} - -export const sendLinkedinEvent = sendPixel((event) => { - window.lintrk?.('track', { conversion_id: events[event] }) -}) diff --git a/apps/cowswap-frontend/src/legacy/components/analytics/pixel/microsoft.ts b/apps/cowswap-frontend/src/legacy/components/analytics/pixel/microsoft.ts deleted file mode 100644 index db9ad254b0..0000000000 --- a/apps/cowswap-frontend/src/legacy/components/analytics/pixel/microsoft.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { PIXEL_EVENTS } from './constants' -import { sendPixel } from './utils' - -const events = { - [PIXEL_EVENTS.INIT]: 'page_view', - [PIXEL_EVENTS.CONNECT_WALLET]: 'begin_checkout', - [PIXEL_EVENTS.POST_TRADE]: 'purchase', -} - -export const sendMicrosoftEvent = sendPixel((event) => { - window.uetq = window.uetq || [] - window.uetq.push('event', events[event], {}) -}) diff --git a/apps/cowswap-frontend/src/legacy/components/analytics/pixel/paved.ts b/apps/cowswap-frontend/src/legacy/components/analytics/pixel/paved.ts deleted file mode 100644 index a26d0eb24c..0000000000 --- a/apps/cowswap-frontend/src/legacy/components/analytics/pixel/paved.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { PIXEL_EVENTS } from './constants' -import { sendPixel } from './utils' - -const events = { - [PIXEL_EVENTS.INIT]: 'search', - [PIXEL_EVENTS.CONNECT_WALLET]: 'sign_up', - [PIXEL_EVENTS.POST_TRADE]: 'purchase', -} - -export const sendPavedEvent = sendPixel((event: PIXEL_EVENTS) => { - window.pvd?.('event', events[event]) -}) diff --git a/apps/cowswap-frontend/src/legacy/components/analytics/pixel/reddit.ts b/apps/cowswap-frontend/src/legacy/components/analytics/pixel/reddit.ts deleted file mode 100644 index c979b6ee08..0000000000 --- a/apps/cowswap-frontend/src/legacy/components/analytics/pixel/reddit.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { PIXEL_EVENTS } from './constants' -import { sendPixel } from './utils' - -const events = { - [PIXEL_EVENTS.INIT]: 'Lead', - [PIXEL_EVENTS.CONNECT_WALLET]: 'SignUp', - [PIXEL_EVENTS.POST_TRADE]: 'Purchase', -} - -export const sendRedditEvent = sendPixel((event) => { - window.rdt?.('track', events[event]) -}) diff --git a/apps/cowswap-frontend/src/legacy/components/analytics/pixel/twitter.ts b/apps/cowswap-frontend/src/legacy/components/analytics/pixel/twitter.ts deleted file mode 100644 index 9f5969461d..0000000000 --- a/apps/cowswap-frontend/src/legacy/components/analytics/pixel/twitter.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { PIXEL_EVENTS } from './constants' -import { sendPixel } from './utils' - -const events = { - [PIXEL_EVENTS.INIT]: 'tw-oddz2-oddz8', - [PIXEL_EVENTS.CONNECT_WALLET]: 'tw-oddz2-oddza', - [PIXEL_EVENTS.POST_TRADE]: 'tw-oddz2-oddzb', -} - -export const sendTwitterEvent = sendPixel((event: PIXEL_EVENTS) => { - window.twq?.('event', events[event], {}) -}) diff --git a/apps/cowswap-frontend/src/legacy/components/earn/styled.ts b/apps/cowswap-frontend/src/legacy/components/earn/styled.ts index d918821091..f5a38f2b46 100644 --- a/apps/cowswap-frontend/src/legacy/components/earn/styled.ts +++ b/apps/cowswap-frontend/src/legacy/components/earn/styled.ts @@ -1,8 +1,8 @@ -import styled from 'styled-components/macro' +import uImage from '@cowprotocol/assets/images/big_unicorn.png' +import noise from '@cowprotocol/assets/images/noise.png' +import xlUnicorn from '@cowprotocol/assets/images/xl_uni.png' -import uImage from 'legacy/assets/images/big_unicorn.png' -import noise from 'legacy/assets/images/noise.png' -import xlUnicorn from 'legacy/assets/images/xl_uni.png' +import styled from 'styled-components/macro' import { AutoColumn } from '../Column' diff --git a/apps/cowswap-frontend/src/legacy/components/swap/ConfirmSwapModal/hooks.tsx b/apps/cowswap-frontend/src/legacy/components/swap/ConfirmSwapModal/hooks.tsx index a9d2eea105..951d0d7237 100644 --- a/apps/cowswap-frontend/src/legacy/components/swap/ConfirmSwapModal/hooks.tsx +++ b/apps/cowswap-frontend/src/legacy/components/swap/ConfirmSwapModal/hooks.tsx @@ -1,5 +1,6 @@ import { useMemo } from 'react' +import { TokenSymbol } from '@cowprotocol/ui' import { Currency, CurrencyAmount } from '@uniswap/sdk-core' import { Nullish } from 'types' @@ -7,8 +8,6 @@ import { Nullish } from 'types' import { useIsSafeApprovalBundle } from 'modules/limitOrders/hooks/useIsSafeApprovalBundle' import { useIsSafeEthFlow } from 'modules/swap/hooks/useIsSafeEthFlow' -import { TokenSymbol } from 'common/pure/TokenSymbol' - export function useButtonText(slippageAdjustedSellAmount: Nullish>) { const isSafeApprovalBundle = useIsSafeApprovalBundle(slippageAdjustedSellAmount) const isSafeEthFlowBundle = useIsSafeEthFlow() diff --git a/apps/cowswap-frontend/src/legacy/components/swap/ConfirmSwapModal/index.tsx b/apps/cowswap-frontend/src/legacy/components/swap/ConfirmSwapModal/index.tsx index bc2d8bb3f0..f02968dd43 100644 --- a/apps/cowswap-frontend/src/legacy/components/swap/ConfirmSwapModal/index.tsx +++ b/apps/cowswap-frontend/src/legacy/components/swap/ConfirmSwapModal/index.tsx @@ -1,24 +1,27 @@ import { useCallback, useMemo } from 'react' +import { TokenAmount } from '@cowprotocol/ui' +import { useWalletDetails } from '@cowprotocol/wallet' import { Percent } from '@uniswap/sdk-core' import { Trans } from '@lingui/macro' import { SwapModalFooter } from 'legacy/components/swap/SwapModalFooter' -import SwapModalHeader from 'legacy/components/swap/SwapModalHeader' -import { ConfirmOperationType, TransactionConfirmationModal } from 'legacy/components/TransactionConfirmationModal' -import { LegacyConfirmationModalContent } from 'legacy/components/TransactionConfirmationModal/LegacyConfirmationModalContent' import TradeGp from 'legacy/state/swap/TradeGp' import { SwapConfirmState } from 'modules/swap/state/swapConfirmAtom' -import { useWalletDetails } from 'modules/wallet' import { RateInfoParams } from 'common/pure/RateInfo' -import { TokenAmount } from 'common/pure/TokenAmount' import { TransactionErrorContent } from 'common/pure/TransactionErrorContent' +import { TradeAmounts } from 'common/types' import { useButtonText } from './hooks' +import { ConfirmOperationType } from '../../../state/types' +import { TransactionConfirmationModal } from '../../TransactionConfirmationModal' +import { LegacyConfirmationModalContent } from '../../TransactionConfirmationModal/LegacyConfirmationModalContent' +import { SwapModalHeader } from '../SwapModalHeader' + type ConfirmSwapModalProps = { swapConfirmState: SwapConfirmState trade: TradeGp | undefined @@ -100,7 +103,13 @@ export function ConfirmSwapModal({ bottomContent={modalBottom} /> ), - [onDismiss, modalBottom, modalHeader, swapErrorMessage] + [swapErrorMessage, onDismiss, modalHeader, modalBottom] + ) + + const tradeAmounts: TradeAmounts | undefined = useMemo( + () => + trade ? { inputAmount: trade.inputAmountWithoutFee, outputAmount: trade.outputAmountWithoutFee } : undefined, + [trade] ) return ( @@ -113,6 +122,8 @@ export function ConfirmSwapModal({ pendingText={} currencyToAdd={trade?.outputAmount.currency} operationType={ConfirmOperationType.ORDER_SIGN} + tradeAmounts={tradeAmounts} + swapConfirmState={swapConfirmState} /> ) } diff --git a/apps/cowswap-frontend/src/legacy/components/swap/FeeInformationTooltip.tsx b/apps/cowswap-frontend/src/legacy/components/swap/FeeInformationTooltip.tsx index 851afbc62b..74d25969f2 100644 --- a/apps/cowswap-frontend/src/legacy/components/swap/FeeInformationTooltip.tsx +++ b/apps/cowswap-frontend/src/legacy/components/swap/FeeInformationTooltip.tsx @@ -1,19 +1,18 @@ import React from 'react' +import { useTheme } from '@cowprotocol/common-hooks' +import { FiatAmount } from '@cowprotocol/ui' import { Currency, CurrencyAmount, Token } from '@uniswap/sdk-core' import styled from 'styled-components/macro' import QuestionHelper from 'legacy/components/QuestionHelper' import useCowBalanceAndSubsidy from 'legacy/hooks/useCowBalanceAndSubsidy' -import useTheme from 'legacy/hooks/useTheme' import TradeGp from 'legacy/state/swap/TradeGp' import { getInputReceiveAmountInfo, getOutputReceiveAmountInfo } from 'modules/swap/helpers/tradeReceiveAmount' import { ReceiveAmountInfoTooltip } from 'modules/swap/pure/ReceiveAmountInfo' -import { FiatAmount } from 'common/pure/FiatAmount' - interface FeeInformationTooltipProps { trade?: TradeGp label: React.ReactNode @@ -52,7 +51,7 @@ const FeeAmountAndFiat = styled.span` } ` -export default function FeeInformationTooltip(props: FeeInformationTooltipProps) { +export function FeeInformationTooltip(props: FeeInformationTooltipProps) { const { trade, label, amountAfterFees, type, showHelper, fiatValue, showFiat = false, allowsOffchainSigning } = props const theme = useTheme() diff --git a/apps/cowswap-frontend/src/legacy/components/swap/SwapHeader/SwapHeaderMod.tsx b/apps/cowswap-frontend/src/legacy/components/swap/SwapHeader/SwapHeaderMod.tsx index 47485e4672..0c85c1d9c6 100644 --- a/apps/cowswap-frontend/src/legacy/components/swap/SwapHeader/SwapHeaderMod.tsx +++ b/apps/cowswap-frontend/src/legacy/components/swap/SwapHeader/SwapHeaderMod.tsx @@ -1,15 +1,17 @@ +import { RowBetween, RowFixed } from '@cowprotocol/ui' import { Percent } from '@uniswap/sdk-core' import styled from 'styled-components/macro' -import { RowBetween, RowFixed } from 'legacy/components/Row' import SettingsTab from 'legacy/components/Settings' import { TradeWidgetLinks } from 'modules/application/containers/TradeWidgetLinks' +import { UI } from 'common/constants/theme' + const StyledSwapHeader = styled.div` width: 100%; - color: ${({ theme }) => theme.text2}; + color: var(${UI.COLOR_TEXT2}); ` export default function SwapHeader({ allowedSlippage, className }: { allowedSlippage: Percent; className?: string }) { diff --git a/apps/cowswap-frontend/src/legacy/components/swap/SwapModalFooter/index.tsx b/apps/cowswap-frontend/src/legacy/components/swap/SwapModalFooter/index.tsx index 054e7ddd5a..e65c8d691c 100644 --- a/apps/cowswap-frontend/src/legacy/components/swap/SwapModalFooter/index.tsx +++ b/apps/cowswap-frontend/src/legacy/components/swap/SwapModalFooter/index.tsx @@ -1,18 +1,19 @@ import { ReactNode } from 'react' +import { ButtonSize, ButtonError, AutoRow, RowBetween, RowFixed } from '@cowprotocol/ui' + import { Trans } from '@lingui/macro' import { Text } from 'rebass' import styled from 'styled-components/macro' -import { ButtonError } from 'legacy/components/Button' -import { AutoRow, RowBetween, RowFixed } from 'legacy/components/Row' import { SwapCallbackError } from 'legacy/components/swap/styleds' -import { ButtonSize } from 'legacy/theme/enum' + +import { UI } from 'common/constants/theme' const Wrapper = styled.div` ${RowBetween} > div, ${RowFixed} > div { - color: ${({ theme }) => theme.text1}; + color: var(${UI.COLOR_TEXT1}); } ` diff --git a/apps/cowswap-frontend/src/legacy/components/swap/SwapModalHeader/SwapModalHeaderMod.tsx b/apps/cowswap-frontend/src/legacy/components/swap/SwapModalHeader/SwapModalHeaderMod.tsx deleted file mode 100644 index a69b1e413e..0000000000 --- a/apps/cowswap-frontend/src/legacy/components/swap/SwapModalHeader/SwapModalHeaderMod.tsx +++ /dev/null @@ -1,255 +0,0 @@ -import React, { useContext, useMemo } from 'react' - -import { Percent, TradeType } from '@uniswap/sdk-core' - -import { Trans } from '@lingui/macro' -import { transparentize } from 'polished' -import { ArrowDown } from 'react-feather' -import { Text } from 'rebass' -import styled, { ThemeContext } from 'styled-components/macro' - -import { AutoColumn } from 'legacy/components/Column' -import { RowBetween, RowFixed } from 'legacy/components/Row' -import { AdvancedSwapDetails } from 'legacy/components/swap/AdvancedSwapDetails' -import { AuxInformationContainer, TruncatedText } from 'legacy/components/swap/styleds' -import { WarningProps } from 'legacy/components/SwapWarnings' -import { INPUT_OUTPUT_EXPLANATION } from 'legacy/constants' -import { Field } from 'legacy/state/swap/actions' -import TradeGp from 'legacy/state/swap/TradeGp' -import { ThemedText } from 'legacy/theme' -import { isAddress, shortenAddress } from 'legacy/utils' -import { computeSlippageAdjustedAmounts } from 'legacy/utils/prices' - -import { PriceUpdatedBanner } from 'modules/trade/pure/PriceUpdatedBanner' -import { useTradeUsdAmounts } from 'modules/usdAmount' - -import { CurrencyLogo } from 'common/pure/CurrencyLogo' -import { FiatValue } from 'common/pure/FiatValue' -import { RateInfo, RateInfoParams } from 'common/pure/RateInfo' -import { TokenAmount } from 'common/pure/TokenAmount' -import { TokenSymbol } from 'common/pure/TokenSymbol' - -import FeeInformationTooltip from '../FeeInformationTooltip' - -import { LightCardType } from './index' - -export const ArrowWrapper = styled.div` - --size: 26px; - padding: 0; - height: var(--size); - width: var(--size); - position: relative; - margin: -13px 0; - left: calc(50% - var(--size) / 2); - display: flex; - justify-content: center; - align-items: center; - z-index: 2; - border-radius: 8px; - border: ${({ theme }) => `2px solid ${theme.grey1}`}; - box-shadow: 0px 0px 0px 3px ${({ theme }) => theme.bg1}; - background: ${({ theme }) => (theme.darkMode ? theme.grey1 : theme.white)}; - - > svg { - stroke-width: 2px; - padding: 1px; - height: 100%; - width: 100%; - cursor: pointer; - } -` - -const StyledRateInfo = styled(RateInfo)` - font-size: 13px; - font-weight: 500; - margin: 0 auto; -` - -export interface SwapModalHeaderProps { - trade: TradeGp - allowedSlippage: Percent - recipient: string | null - showAcceptChanges: boolean - priceImpactWithoutFee?: Percent - priceImpact?: Percent - onAcceptChanges: () => void - LightCard: LightCardType - HighFeeWarning: React.FC - NoImpactWarning: React.ReactNode - allowsOffchainSigning: boolean - rateInfoParams: RateInfoParams -} - -export default function SwapModalHeader({ - trade, - allowedSlippage, - recipient, - showAcceptChanges, - onAcceptChanges, - priceImpact, - LightCard, - HighFeeWarning, - NoImpactWarning, - allowsOffchainSigning, - rateInfoParams, -}: SwapModalHeaderProps) { - const slippageAdjustedAmounts = useMemo( - () => computeSlippageAdjustedAmounts(trade, allowedSlippage), - [trade, allowedSlippage] - ) - - const theme = useContext(ThemeContext) - - const { - inputAmount: { value: fiatValueInput }, - outputAmount: { value: fiatValueOutput }, - } = useTradeUsdAmounts(trade.inputAmountWithoutFee, trade.outputAmountWithoutFee) - - const [slippageIn, slippageOut] = useMemo( - () => [slippageAdjustedAmounts[Field.INPUT], slippageAdjustedAmounts[Field.OUTPUT]], - [slippageAdjustedAmounts] - ) - - const [exactInLabel, exactOutLabel] = useMemo(() => { - return [ - trade?.tradeType === TradeType.EXACT_OUTPUT ? From (incl. fee) : null, - trade?.tradeType === TradeType.EXACT_INPUT ? Receive (incl. fee) : null, - ] - }, [trade]) - - return ( - - - - - - From - - - - - - - - - - - - - - - - - - - {!!exactInLabel && ( - - } - amountBeforeFees={} - feeAmount={trade.fee.feeAsCurrency} - allowsOffchainSigning={allowsOffchainSigning} - label={exactInLabel} - showHelper - trade={trade} - type="From" - fiatValue={fiatValueInput} - /> - - )} - - - - - - - - To - - - - - - - - - - - - - - - {} - - - - - - {!!exactOutLabel && ( - - } - amountBeforeFees={} - feeAmount={trade.outputAmountWithoutFee?.subtract(trade.outputAmount)} - label={exactOutLabel} - allowsOffchainSigning={allowsOffchainSigning} - showHelper - trade={trade} - type="To" - fiatValue={fiatValueOutput} - /> - - )} - - - {showAcceptChanges && } - - {trade.tradeType === TradeType.EXACT_INPUT ? ( - - - Output is estimated. You will receive at least{' '} - - {' '} - {' '} - or the swap will not execute. {INPUT_OUTPUT_EXPLANATION} - - - ) : ( - - - Input is estimated. You will sell at most{' '} - - {' '} - {' '} - or the swap will not execute. {INPUT_OUTPUT_EXPLANATION} - - - )} - - {recipient !== null ? ( - - - - Output will be sent to{' '} - {isAddress(recipient) ? shortenAddress(recipient) : recipient} - - - - ) : null} - {/* High Fee Warning */} - - {/* No Impact Warning */} - {!priceImpact && NoImpactWarning} - - ) -} diff --git a/apps/cowswap-frontend/src/legacy/components/swap/SwapModalHeader/index.tsx b/apps/cowswap-frontend/src/legacy/components/swap/SwapModalHeader/index.tsx index 802cc6b9e0..23524ae1f5 100644 --- a/apps/cowswap-frontend/src/legacy/components/swap/SwapModalHeader/index.tsx +++ b/apps/cowswap-frontend/src/legacy/components/swap/SwapModalHeader/index.tsx @@ -1,58 +1,46 @@ -import React from 'react' +import React, { useContext, useMemo } from 'react' +import { INPUT_OUTPUT_EXPLANATION } from '@cowprotocol/common-const' +import { isAddress, shortenAddress } from '@cowprotocol/common-utils' +import { RowBetween, RowFixed, TokenAmount, TokenSymbol } from '@cowprotocol/ui' +import { useWalletDetails } from '@cowprotocol/wallet' +import { Percent, TradeType } from '@uniswap/sdk-core' + +import { Trans } from '@lingui/macro' import { transparentize } from 'polished' -import styled from 'styled-components/macro' +import { ArrowDown } from 'react-feather' +import { Text } from 'rebass' +import { ThemeContext } from 'styled-components/macro' -import { LightCard as LightCardUni } from 'legacy/components/Card' -import { SwapShowAcceptChanges } from 'legacy/components/swap/styleds' -import { HighFeeWarning as HighFeeWarningBase } from 'legacy/components/SwapWarnings' +import { AutoColumn } from 'legacy/components/Column' +import { AdvancedSwapDetails } from 'legacy/components/swap/AdvancedSwapDetails' +import { AuxInformationContainer, TruncatedText } from 'legacy/components/swap/styleds' +import { WarningProps } from 'legacy/components/SwapWarnings' +import TradeGp from 'legacy/state/swap/TradeGp' +import { ThemedText } from 'legacy/theme' +import { computeSlippageAdjustedAmounts } from 'legacy/utils/prices' import { NoImpactWarning } from 'modules/trade/pure/NoImpactWarning' -import { useWalletDetails } from 'modules/wallet' - -import SwapModalHeaderMod, { SwapModalHeaderProps } from './SwapModalHeaderMod' - -const LightCard = styled(LightCardUni)<{ flatBorder?: boolean }>` - background-color: ${({ theme }) => theme.grey1}; - border: none; - ${({ flatBorder = false }) => flatBorder && `border-radius: 20px 20px 0 0;`}; -` - -export type LightCardType = typeof LightCard - -// targettable by styled injection -const HighFeeWarning = styled(HighFeeWarningBase)`` +import { PriceUpdatedBanner } from 'modules/trade/pure/PriceUpdatedBanner' +import { useTradeUsdAmounts } from 'modules/usdAmount' -const Wrapper = styled.div` - ${({ theme }) => theme.mediaWidth.upToSmall` - margin: 0 auto; - `}; +import { CurrencyLogo } from 'common/pure/CurrencyLogo' +import { FiatValue } from 'common/pure/FiatValue' +import { BannerOrientation, CustomRecipientWarningBanner } from 'common/pure/InlineBanner/banners' +import { RateInfoParams } from 'common/pure/RateInfo' - ${SwapShowAcceptChanges} { - background: ${({ theme }) => transparentize(0.85, theme.alert)}; - border: 1px solid ${({ theme }) => transparentize(0.75, theme.alert)}; - padding: 8px 8px 8px 16px; - margin: 8px 0 0; +import { ArrowWrapper, HighFeeWarning, LightCard, LightCardType, StyledRateInfo, Wrapper } from './styled' - svg { - stroke: ${({ theme }) => theme.alert}; - } - } +import { Field } from '../../../state/types' +import { FeeInformationTooltip } from '../FeeInformationTooltip' - svg { - stroke: ${({ theme }) => theme.text1}; - } -` - -export default function SwapModalHeader( - props: Omit -) { +export function SwapModalHeader(props: Omit) { const { allowsOffchainSigning } = useWalletDetails() const NoImpactWarningComponent = return ( - ) } + +interface SwapModalHeaderProps { + trade: TradeGp + allowedSlippage: Percent + recipient: string | null + showAcceptChanges: boolean + priceImpactWithoutFee?: Percent + priceImpact?: Percent + onAcceptChanges: () => void + LightCard: LightCardType + HighFeeWarning: React.FC + NoImpactWarning: React.ReactNode + allowsOffchainSigning: boolean + rateInfoParams: RateInfoParams +} + +function SwapModalHeaderComponent({ + trade, + allowedSlippage, + recipient, + showAcceptChanges, + onAcceptChanges, + priceImpact, + LightCard, + HighFeeWarning, + NoImpactWarning, + allowsOffchainSigning, + rateInfoParams, +}: SwapModalHeaderProps) { + const slippageAdjustedAmounts = useMemo( + () => computeSlippageAdjustedAmounts(trade, allowedSlippage), + [trade, allowedSlippage] + ) + + const theme = useContext(ThemeContext) + + const { + inputAmount: { value: fiatValueInput }, + outputAmount: { value: fiatValueOutput }, + } = useTradeUsdAmounts(trade.inputAmountWithoutFee, trade.outputAmountWithoutFee) + + const [slippageIn, slippageOut] = useMemo( + () => [slippageAdjustedAmounts[Field.INPUT], slippageAdjustedAmounts[Field.OUTPUT]], + [slippageAdjustedAmounts] + ) + + const [exactInLabel, exactOutLabel] = useMemo(() => { + return [ + trade?.tradeType === TradeType.EXACT_OUTPUT ? From (incl. fee) : null, + trade?.tradeType === TradeType.EXACT_INPUT ? Receive (incl. fee) : null, + ] + }, [trade]) + + const isCustomRecipient = recipient !== null + + return ( + + + + + + From + + + + + + + + + + + + + + + + + + + {!!exactInLabel && ( + + } + amountBeforeFees={} + feeAmount={trade.fee.feeAsCurrency} + allowsOffchainSigning={allowsOffchainSigning} + label={exactInLabel} + showHelper + trade={trade} + type="From" + fiatValue={fiatValueInput} + /> + + )} + + + + + + + + To + + + + + + + + + + + + + + + {} + + + + + + {!!exactOutLabel && ( + + } + amountBeforeFees={} + feeAmount={trade.outputAmountWithoutFee?.subtract(trade.outputAmount)} + label={exactOutLabel} + allowsOffchainSigning={allowsOffchainSigning} + showHelper + trade={trade} + type="To" + fiatValue={fiatValueOutput} + /> + + )} + + + {showAcceptChanges && } + + {trade.tradeType === TradeType.EXACT_INPUT ? ( + + + Output is estimated. You will receive at least{' '} + + {' '} + {' '} + or the swap will not execute. {INPUT_OUTPUT_EXPLANATION} + + + ) : ( + + + Input is estimated. You will sell at most{' '} + + {' '} + {' '} + or the swap will not execute. {INPUT_OUTPUT_EXPLANATION} + + + )} + + {/*TODO: adjust styles and maybe merge with the indication below? */} + {isCustomRecipient && ( + + + + )} + {isCustomRecipient ? ( + + + + Output will be sent to{' '} + {isAddress(recipient) ? shortenAddress(recipient) : recipient} + + + + ) : null} + {/* High Fee Warning */} + + {/* No Impact Warning */} + {!priceImpact && NoImpactWarning} + + ) +} diff --git a/apps/cowswap-frontend/src/legacy/components/swap/SwapModalHeader/styled.ts b/apps/cowswap-frontend/src/legacy/components/swap/SwapModalHeader/styled.ts new file mode 100644 index 0000000000..a75c03e991 --- /dev/null +++ b/apps/cowswap-frontend/src/legacy/components/swap/SwapModalHeader/styled.ts @@ -0,0 +1,73 @@ +import { transparentize } from 'polished' +import styled from 'styled-components/macro' + +import { LightCard as LightCardUni } from 'legacy/components/Card' +import { SwapShowAcceptChanges } from 'legacy/components/swap/styleds' +import { HighFeeWarning as HighFeeWarningBase } from 'legacy/components/SwapWarnings' + +import { UI } from 'common/constants/theme' +import { RateInfo } from 'common/pure/RateInfo' + +export const LightCard = styled(LightCardUni)<{ flatBorder?: boolean }>` + background-color: var(${UI.COLOR_GREY}); + border: none; + ${({ flatBorder = false }) => flatBorder && `border-radius: 20px 20px 0 0;`}; +` + +export type LightCardType = typeof LightCard + +// targettable by styled injection +export const HighFeeWarning = styled(HighFeeWarningBase)`` + +export const Wrapper = styled.div` + ${({ theme }) => theme.mediaWidth.upToSmall` + margin: 0 auto; + `}; + + ${SwapShowAcceptChanges} { + background: ${({ theme }) => transparentize(0.85, theme.alert)}; + border: 1px solid ${({ theme }) => transparentize(0.75, theme.alert)}; + padding: 8px 8px 8px 16px; + margin: 8px 0 0; + + svg { + stroke: ${({ theme }) => theme.alert}; + } + } + + svg { + stroke: var(${UI.COLOR_TEXT1}); + } +` + +export const ArrowWrapper = styled.div` + --size: 26px; + padding: 0; + height: var(--size); + width: var(--size); + position: relative; + margin: -13px 0; + left: calc(50% - var(--size) / 2); + display: flex; + justify-content: center; + align-items: center; + z-index: 2; + border-radius: 8px; + border: ${({ theme }) => `2px solid ${theme.grey1}`}; + box-shadow: 0px 0px 0px 3px ${({ theme }) => theme.bg1}; + background: ${({ theme }) => (theme.darkMode ? theme.grey1 : theme.white)}; + + > svg { + stroke-width: 2px; + padding: 1px; + height: 100%; + width: 100%; + cursor: pointer; + } +` + +export const StyledRateInfo = styled(RateInfo)` + font-size: 13px; + font-weight: 500; + margin: 0 auto; +` diff --git a/apps/cowswap-frontend/src/legacy/components/swap/UnsupportedCurrencyFooter/UnsupportedCurrencyFooterMod.tsx b/apps/cowswap-frontend/src/legacy/components/swap/UnsupportedCurrencyFooter/UnsupportedCurrencyFooterMod.tsx index f6c24ca0fc..420a3b9338 100644 --- a/apps/cowswap-frontend/src/legacy/components/swap/UnsupportedCurrencyFooter/UnsupportedCurrencyFooterMod.tsx +++ b/apps/cowswap-frontend/src/legacy/components/swap/UnsupportedCurrencyFooter/UnsupportedCurrencyFooterMod.tsx @@ -1,20 +1,21 @@ import { useState } from 'react' +import { getEtherscanLink } from '@cowprotocol/common-utils' +import { ButtonEmpty } from '@cowprotocol/ui' +import { AutoRow, RowBetween } from '@cowprotocol/ui' +import { ExternalLink } from '@cowprotocol/ui' +import { useWalletInfo } from '@cowprotocol/wallet' import { Currency } from '@uniswap/sdk-core' import { Trans } from '@lingui/macro' import styled from 'styled-components/macro' -import { ButtonEmpty } from 'legacy/components/Button' import Card, { OutlineCard } from 'legacy/components/Card' import { AutoColumn } from 'legacy/components/Column' -import { AutoRow, RowBetween } from 'legacy/components/Row' import { useIsUnsupportedTokenGp } from 'legacy/state/lists/hooks' -import { CloseIcon, ExternalLink, ThemedText, Z_INDEX } from 'legacy/theme' -import { getEtherscanLink } from 'legacy/utils' - -import { useWalletInfo } from 'modules/wallet' +import { CloseIcon, ThemedText, Z_INDEX } from 'legacy/theme' +import { UI } from 'common/constants/theme' import { CurrencyLogo } from 'common/pure/CurrencyLogo' import { Modal } from 'common/pure/Modal' @@ -28,7 +29,7 @@ export const DetailsFooter = styled.div<{ show: boolean }>` max-width: 400px; border-bottom-left-radius: 20px; border-bottom-right-radius: 20px; - color: ${({ theme }) => theme.text2}; + color: var(${UI.COLOR_TEXT2}); background-color: ${({ theme }) => theme.advancedBG}; z-index: ${Z_INDEX.deprecated_zero}; diff --git a/apps/cowswap-frontend/src/legacy/components/swap/UnsupportedCurrencyFooter/index.tsx b/apps/cowswap-frontend/src/legacy/components/swap/UnsupportedCurrencyFooter/index.tsx index 377a9e79fe..8782215615 100644 --- a/apps/cowswap-frontend/src/legacy/components/swap/UnsupportedCurrencyFooter/index.tsx +++ b/apps/cowswap-frontend/src/legacy/components/swap/UnsupportedCurrencyFooter/index.tsx @@ -1,9 +1,9 @@ +import { UNSUPPORTED_TOKENS_FAQ_URL } from '@cowprotocol/common-const' + import { transparentize } from 'polished' import { HashLink } from 'react-router-hash-link' import styled from 'styled-components/macro' -import { UNSUPPORTED_TOKENS_FAQ_URL } from 'legacy/constants' - import UnsupportedCurrencyFooterMod, { UnsupportedCurrencyFooterParams, DetailsFooter, diff --git a/apps/cowswap-frontend/src/legacy/components/swap/confirmPriceImpactWithoutFee.ts b/apps/cowswap-frontend/src/legacy/components/swap/confirmPriceImpactWithoutFee.ts index a3febf01c4..89c6afecc1 100644 --- a/apps/cowswap-frontend/src/legacy/components/swap/confirmPriceImpactWithoutFee.ts +++ b/apps/cowswap-frontend/src/legacy/components/swap/confirmPriceImpactWithoutFee.ts @@ -1,8 +1,7 @@ /** Should not be used. */ +import { ALLOWED_PRICE_IMPACT_HIGH, PRICE_IMPACT_WITHOUT_FEE_CONFIRM_MIN } from '@cowprotocol/common-const' import { Percent } from '@uniswap/sdk-core' -import { ALLOWED_PRICE_IMPACT_HIGH, PRICE_IMPACT_WITHOUT_FEE_CONFIRM_MIN } from '../../constants/misc' - /** * Given the price impact, get user confirmation. * diff --git a/apps/cowswap-frontend/src/legacy/components/swap/styleds.tsx b/apps/cowswap-frontend/src/legacy/components/swap/styleds.tsx index c95220e200..20444c6fe9 100644 --- a/apps/cowswap-frontend/src/legacy/components/swap/styleds.tsx +++ b/apps/cowswap-frontend/src/legacy/components/swap/styleds.tsx @@ -1,13 +1,16 @@ import { MouseEventHandler, ReactNode } from 'react' +import { TooltipContainer } from '@cowprotocol/ui' + import { transparentize } from 'polished' import { AlertTriangle } from 'react-feather' import { Text } from 'rebass' import styled, { css } from 'styled-components/macro' -import { TooltipContainer } from 'legacy/components/Tooltip' import { ThemedText } from 'legacy/theme' +import { UI } from 'common/constants/theme' + import { FeeInformationTooltipWrapper } from './FeeInformationTooltip' import { AutoColumn } from '../Column' @@ -30,7 +33,7 @@ export const ArrowWrapper = styled.div<{ clickable: boolean }>` margin-top: -14px; margin-bottom: -14px; left: 16px; - background-color: ${({ theme }) => theme.bg1}; + background-color: var(${UI.COLOR_CONTAINER_BG_01}); z-index: 2; ${({ clickable }) => clickable @@ -183,7 +186,7 @@ export const AuxInformationContainer = styled.div<{ showAux?: boolean }>` border: 1px solid ${({ theme, hideInput }) => (hideInput ? ' transparent' : theme.bg2)}; - background-color: ${({ theme }) => theme.bg1}; + background-color: var(${UI.COLOR_CONTAINER_BG_01}); width: ${({ hideInput }) => (hideInput ? '100%' : 'initial')}; :focus, diff --git a/apps/cowswap-frontend/src/legacy/constants/chains.ts b/apps/cowswap-frontend/src/legacy/constants/chains.ts deleted file mode 100644 index 7ae490cd42..0000000000 --- a/apps/cowswap-frontend/src/legacy/constants/chains.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { SupportedChainId } from '@cowprotocol/cow-sdk' - -/** - * Array of all the supported chain IDs - */ -export const ALL_SUPPORTED_CHAIN_IDS: SupportedChainId[] = Object.values(SupportedChainId).filter( - (id) => typeof id === 'number' -) as SupportedChainId[] diff --git a/apps/cowswap-frontend/src/legacy/constants/proposals/index.ts b/apps/cowswap-frontend/src/legacy/constants/proposals/index.ts deleted file mode 100644 index 337aa84f69..0000000000 --- a/apps/cowswap-frontend/src/legacy/constants/proposals/index.ts +++ /dev/null @@ -1,5 +0,0 @@ -export const UNISWAP_GRANTS_START_BLOCK = 11473815 -export const BRAVO_START_BLOCK = 13059344 -export const ONE_BIP_START_BLOCK = 13551293 -export const POLYGON_START_BLOCK = 13786993 -export const MOONBEAN_START_BLOCK = 14732457 diff --git a/apps/cowswap-frontend/src/legacy/constants/proposals/polygon_proposal_title.ts b/apps/cowswap-frontend/src/legacy/constants/proposals/polygon_proposal_title.ts deleted file mode 100644 index 9e3897c792..0000000000 --- a/apps/cowswap-frontend/src/legacy/constants/proposals/polygon_proposal_title.ts +++ /dev/null @@ -1 +0,0 @@ -export const POLYGON_PROPOSAL_TITLE = 'Should Uniswap v3 be deployed to Polygon?' diff --git a/apps/cowswap-frontend/src/legacy/constants/proposals/uniswap_grants_proposal_description.ts b/apps/cowswap-frontend/src/legacy/constants/proposals/uniswap_grants_proposal_description.ts deleted file mode 100644 index 51347d38fd..0000000000 --- a/apps/cowswap-frontend/src/legacy/constants/proposals/uniswap_grants_proposal_description.ts +++ /dev/null @@ -1,106 +0,0 @@ -export const UNISWAP_GRANTS_PROPOSAL_DESCRIPTION = `# Uniswap Grants Program v0.1 - -*co-authored with [Ken Ng](https://twitter.com/nkennethk?lang=en)* - -## Summary: - -**This post outlines a framework for funding Uniswap ecosystem development with grants from the[ UNI Community Treasury](https://uniswap.org/blog/uni/).** The program starts small—sponsoring hackathons, [for example](https://gov.uniswap.org/c/proposal-discussion/5)—but could grow in significance over time (with renewals approved by governance) to fund core protocol development. Grants administration is a subjective process that cannot be easily automated, and thus we propose a nimble committee of 6 members —1 lead and 5 reviewers—to deliver an efficient, predictable process to applicants, such that funding can be administered without having to put each application to a vote. We propose the program start with an initial cap of $750K per quarter and a limit of 2 quarters before renewal—a sum that we feel is appropriate for an MVP relative to the size of the treasury that UNI token holders are entrusted with allocating. - -**Purpose:** - -**The mission of the UGP is to provide valuable resources to help grow the Uniswap ecosystem.** Through public discourse and inbound applications, the community will get first-hand exposure to identify and respond to the most pressing needs of the ecosystem, as well as the ability to support innovative projects expanding the capabilities of Uniswap. By rewarding talent early with developer incentives, bounties, and infrastructure support, UGP acts as a catalyst for growth and helps to maintain Uniswap as a nexus for DeFi on Ethereum. - -**Quarterly Budget:** - -* Max quarterly budget of up to $750k -* Budget and caps to be assessed every six months - -**Grant Allocation Committee:** - -* Of 6 committee members: 1 lead and 5 reviewers -* Each committee has a term of 2 quarters (6 months) after which the program needs to be renewed by UNI governance -* Committee functions as a 4 of 5 multi-sig - -**Committee Members** - -While the goals and priorities of the grant program will be thoroughly discussed and reviewed by the community through public discourse, **the decision to start UGP by operating as a small committee is to ensure that the application and decision process will be efficient and predictable, so applicants have clear objectives and timely decisions.** - -Starting with just six members enables the committee to efficiently fund projects with tight feedback loops and rapid iterations. The purpose of this committee would be to test the hypothesis that the Grants Program can successfully provide value for the UNI ecosystem before scaling the program. - -**We suggest the grants program is administered by a single lead. Here we propose Kenneth Ng, a co-author of this post**. Ken has helped grow the Ethereum Foundation Grants Program over the last two years in establishing high level priorities and adapting for the ecosystems needs. - -**The other 5 committee members should be thought of as “reviewers” — UNI community members who will keep the grants program functional by ensuring Ken is leading effectively and, of course, not absconding with funds.** Part of the reviewers job is to hold the program accountable for success (defined below) and/or return any excess funds to the UNI treasury. Reviewers are not compensated as part of this proposal as we expect their time commitment to be minimal. Compensation for the lead role is discussed below, as we expect this to be a labor intensive role. - -**Program Lead:** [Ken Ng](https://twitter.com/nkennethk?lang=en) (HL Creative Corp) -*Ecosystem Support Program at the Ethereum Foundation* - -1. Reviewer: [Jesse Walden](https://twitter.com/jessewldn) (o/b/o Unofficial LLC dba [Variant Fund](http://twitter.com/variantfund)) -*Founder and Investor at Variant Fund (holds UNI)* - -2. Reviewer: [Monet Supply](https://twitter.com/MonetSupply) -*Risk Analyst at MakerDAO* - -3. Reviewer: [Robert Leshner](https://twitter.com/rleshner) -*Founder and CEO of Compound Finance* - -4. Reviewer: [Kain Warwick](https://twitter.com/kaiynne) -*Founder of Synthetix* - -5. Reviewer: [Ashleigh Schap](https://twitter.com/ashleighschap) -*Growth Lead, Uniswap (Company)* - -## Methodology - -**1.1 Budget** - -This proposal recommends a max cap of $750K per quarter, with the ability to reevaluate biannually at each epoch (two fiscal quarters). While the UGP Grants Committee will be the decision makers around individual grants, respective budgets, roadmaps, and milestones, any top-level changes to UGP including epochs and max cap, will require full community quorum (4% approval). - -The UGP will be funded by the UNI treasury according to the[ release schedule](https://uniswap.org/blog/uni/) set out by the Uniswap team, whereby 43% of the UNI treasury is released over a four-year timeline. In Year 1 this will total to 172,000,000 UNI (~$344M as of writing). - -Taking into consideration the current landscape of ecosystem funding across Ethereum, the community would be hard-pressed to allocate even 5% of Year 1’s treasury. For context Gitcoin CLR Round 7 distributed $725k ($450k in matched) across 857 projects and YTD, Moloch has granted just under $200k but in contrast, the EF has committed to somewhere in the 8 figure range. - -**1.2 Committee Compensation** - -Operating a successful grants program takes considerable time and effort. Take, for instance, the EF Ecosystem Support Program, which has awarded grants since 2018, consists of an internal team at the Foundation as well as an ever increasing roster of community advisors in order to keep expanding and adapting to best serve the needs of the Ethereum ecosystem. While the structure of the allocation committee has six members, we propose that only the lead will be remunerated for their work in establishing the initial processes, vetting applications, and managing the program overall as this role is expected to be time consuming if the program is to be succesful. We propose that the other committee members be unpaid UNI ecosystem stakeholders who have an interest in seeing the protocol ecosystem continue to operate and grow. - -**We propose the lead be compensated 25 UNI/hr (approximately $100 USD at time of this writing) capped at 30 hours/week. This compensation, along with the quarterly budget, will be allocated to the UGP multisig from the UNI treasury**. In keeping with the committee’s commitment to the community, hours and duties will be logged publicly and transparently . - -**2.1 Priorities** - -Initially, the program aims to start narrow in scope, funding peripheral ecosystem initiatives, such as targeted bounties, hackathon sponsorships, and other low-stakes means of building out the Uniswap developer ecosystem. Over time, if the program proves effective, the grant allocations can grow in scope to include, for example, improved frontends, trading interfaces, and eventually, core protocol development. - -![|624x199](upload://vNP0APCOjiwQMurCmYI47cTLklc.png) - -With the initial priorities in mind, some effective measures for quick successes might look like: - -* Total number of projects funded -* Quarterly increase in applications -* Project engagement post-event/funding -* Overall community engagement/sentiment - -**2.2 Timeline** - -In keeping with the fast pace of the UNI ecosystem, we organize time in epochs, or two calendar quarters. Each epoch will see two funding rounds, one per quarter, after which the community can review and create proposals to improve or revamp the program as they deem fit. - -**![|624x245](upload://n56TSh5X3mt4TSqVVMFhbnZM0eM.png)** - -**Rolling Wave 1 & 2 Applications** - -* Starting in Q1 2021, UGP will start accepting applications for events looking for support in the form of bounties or prizes that in parallel can be proactively sourced. During these first two waves of funding projects, the allocation committee lead can begin laying out guardrails for continued funding - -* Considering the immediate feedback loops for the first epoch, we expect these allocation decisions to be discussed and reviewed by the larger community. Should this not be of value, the community can submit a formal governance proposal to change any piece of UGP that was not effective - -**Wave 3 & Beyond** - -* Beginning with Wave 3, there should have been enough time with impactful projects funded to be considered for follow-on funding, should it make sense. In the same vein, projects within scope will be expanded to also include those working on integrations and and other key components. - -* Beyond the second epoch, as the community helps to review and help adapt UGP to be most effective, the scope will continue to grow in order to accommodate the state of the ecosystem including that of core protocol improvements - -## Conclusion: - -**If this proposal is successfully approved, UGP will start accepting applications on a rolling basis beginning at the start of 2021.** With the phases and priorities laid out above, UGP will aim to make a significant impact by catalyzing growth and innovation in the UNI ecosystem. - -**This program is meant to be the simplest possible MVP of a Uniswap Ecosystem Grants initiative.** While the multi-sig committee comes with trust assumptions about the members, our hope is the community will approve this limited engagement to get the ball rolling in an efficient structure. **After the first epoch (2 fiscal quarters) the burden of proof will be on UGP to show empirical evidence that the program is worth continuing in its existing form and will submit to governance to renew treasury funding.** - -If this program proves successful, we hope it will inspire others to follow suit and create their own funding committees for allocating treasury capital—ideally with different specializations. -` diff --git a/apps/cowswap-frontend/src/legacy/constants/routing.ts b/apps/cowswap-frontend/src/legacy/constants/routing.ts deleted file mode 100644 index 07369e0c80..0000000000 --- a/apps/cowswap-frontend/src/legacy/constants/routing.ts +++ /dev/null @@ -1,130 +0,0 @@ -// a list of tokens by chain - -import { SupportedChainId } from '@cowprotocol/cow-sdk' -import { Currency, Token } from '@uniswap/sdk-core' - -import { - AMPL, - COW, - DAI, - ETH2X_FLI, - EURE_GNOSIS_CHAIN, - FEI, - FRAX, - FXS, - renBTC, - rETH2, - sETH2, - SWISE, - TRIBE, - USDC_MAINNET, - USDT, - WBTC, - WRAPPED_NATIVE_CURRENCY, -} from 'legacy/constants/tokens' -import { USDC_GNOSIS_CHAIN, WBTC_GNOSIS_CHAIN, WETH_GNOSIS_CHAIN } from 'legacy/utils/gnosis_chain/constants' -import { DAI_GOERLI, USDC_GOERLI } from 'legacy/utils/goerli/constants' - -type ChainTokenList = { - readonly [chainId: number]: Token[] -} - -type ChainCurrencyList = { - readonly [chainId: number]: Currency[] -} - -const WRAPPED_NATIVE_CURRENCIES_ONLY: ChainTokenList = Object.fromEntries( - Object.entries(WRAPPED_NATIVE_CURRENCY) - .map(([key, value]) => [key, [value]]) - .filter(Boolean) -) - -// used to construct intermediary pairs for trading -export const BASES_TO_CHECK_TRADES_AGAINST: ChainTokenList = { - ...WRAPPED_NATIVE_CURRENCIES_ONLY, - [SupportedChainId.MAINNET]: [ - ...WRAPPED_NATIVE_CURRENCIES_ONLY[SupportedChainId.MAINNET], - DAI, - USDC_MAINNET, - USDT, - WBTC, - ], -} -export const ADDITIONAL_BASES: { [chainId: number]: { [tokenAddress: string]: Token[] } } = { - [SupportedChainId.MAINNET]: { - '0xF16E4d813f4DcfDe4c5b44f305c908742De84eF0': [ETH2X_FLI], - [rETH2.address]: [sETH2], - [SWISE.address]: [sETH2], - [FEI.address]: [TRIBE], - [TRIBE.address]: [FEI], - [FRAX.address]: [FXS], - [FXS.address]: [FRAX], - [WBTC.address]: [renBTC], - [renBTC.address]: [WBTC], - }, -} -/** - * Some tokens can only be swapped via certain pairs, so we override the list of bases that are considered for these - * tokens. - */ -export const CUSTOM_BASES: { [chainId: number]: { [tokenAddress: string]: Token[] } } = { - [SupportedChainId.MAINNET]: { - [AMPL.address]: [DAI, WRAPPED_NATIVE_CURRENCY[SupportedChainId.MAINNET] as Token], - }, -} - -/** - * Shows up in the currency select for swap and add liquidity - */ -export const COMMON_BASES: ChainCurrencyList = { - [SupportedChainId.MAINNET]: [ - DAI, - COW[SupportedChainId.MAINNET], - USDC_MAINNET, - USDT, - WBTC, - WRAPPED_NATIVE_CURRENCY[SupportedChainId.MAINNET], - ], - [SupportedChainId.GOERLI]: [ - WRAPPED_NATIVE_CURRENCY[SupportedChainId.GOERLI], - COW[SupportedChainId.GOERLI], - DAI_GOERLI, - USDC_GOERLI, - ], - [SupportedChainId.GNOSIS_CHAIN]: [ - USDC_GNOSIS_CHAIN, - COW[SupportedChainId.GNOSIS_CHAIN], - EURE_GNOSIS_CHAIN, - WRAPPED_NATIVE_CURRENCY[SupportedChainId.GNOSIS_CHAIN], - WETH_GNOSIS_CHAIN, - WBTC_GNOSIS_CHAIN, - ], -} - -// used to construct the list of all pairs we consider by default in the frontend -export const BASES_TO_TRACK_LIQUIDITY_FOR: ChainTokenList = { - ...WRAPPED_NATIVE_CURRENCIES_ONLY, - [SupportedChainId.MAINNET]: [ - ...WRAPPED_NATIVE_CURRENCIES_ONLY[SupportedChainId.MAINNET], - DAI, - USDC_MAINNET, - USDT, - WBTC, - ], -} -export const PINNED_PAIRS: { readonly [chainId: number]: [Token, Token][] } = { - [SupportedChainId.MAINNET]: [ - [ - new Token(SupportedChainId.MAINNET, '0x5d3a536E4D6DbD6114cc1Ead35777bAB948E3643', 8, 'cDAI', 'Compound Dai'), - new Token( - SupportedChainId.MAINNET, - '0x39AA39c021dfbaE8faC545936693aC917d5E7563', - 8, - 'cUSDC', - 'Compound USD Coin' - ), - ], - [USDC_MAINNET, USDT], - [DAI, USDT], - ], -} diff --git a/apps/cowswap-frontend/src/legacy/hooks/Tokens.ts b/apps/cowswap-frontend/src/legacy/hooks/Tokens.ts index f158677721..4026518ad4 100644 --- a/apps/cowswap-frontend/src/legacy/hooks/Tokens.ts +++ b/apps/cowswap-frontend/src/legacy/hooks/Tokens.ts @@ -1,120 +1,24 @@ import { useAtomValue } from 'jotai' import { useMemo } from 'react' -import { SupportedChainId } from '@cowprotocol/cow-sdk' +import { doesTokenMatchSymbolOrAddress } from '@cowprotocol/common-utils' +import { useWalletInfo } from '@cowprotocol/wallet' import { Currency, Token } from '@uniswap/sdk-core' -import { getChainInfo } from 'legacy/constants/chainInfo' import { useAllLists, useInactiveListUrls } from 'legacy/state/lists/hooks' -import { deserializeToken, useUserAddedTokens } from 'legacy/state/user/hooks' +import { deserializeToken, useFavouriteTokens, useUserAddedTokens } from 'legacy/state/user/hooks' import { TokensByAddress, tokensByAddressAtom } from 'modules/tokensList/state/tokensListAtom' -import { useWalletInfo } from 'modules/wallet' -import { useCurrencyFromMap, useTokenFromMapOrNetwork } from 'lib/hooks/useCurrency' import { getTokenFilter } from 'lib/hooks/useTokenList/filtering' -import { doesTokenMatchSymbolOrAddress } from 'utils/doesTokenMatchSymbolOrAddress' -import { TokenAddressMap, useUnsupportedTokenList } from './../state/lists/hooks' - -// reduce token map into standard address <-> Token mapping, optionally include user added tokens -export function useTokensFromMap(tokenMap: TokenAddressMap, includeUserAdded: boolean): { [address: string]: Token } { - const { chainId } = useWalletInfo() - const userAddedTokens = useUserAddedTokens() - - return useMemo(() => { - if (!chainId) return {} - - // reduce to just tokens - const mapWithoutUrls = Object.keys(tokenMap[chainId] ?? {}).reduce<{ [address: string]: Token }>( - (newMap, address) => { - newMap[address] = tokenMap[chainId][address].token - return newMap - }, - {} - ) - - if (includeUserAdded) { - return ( - userAddedTokens - // reduce into all ALL_TOKENS filtered by the current chain - .reduce<{ [address: string]: Token }>( - (tokenMap, token) => { - tokenMap[token.address] = token - return tokenMap - }, - // must make a copy because reduce modifies the map, and we do not - // want to make a copy in every iteration - { ...mapWithoutUrls } - ) - ) - } - - return mapWithoutUrls - }, [chainId, userAddedTokens, tokenMap, includeUserAdded]) -} +import { useCurrencyFromMap, useTokenFromMapOrNetwork } from '../../lib/hooks/useCurrency' +import { TokenAmounts, useOnchainBalances } from '../../modules/tokens' export function useAllTokens(): TokensByAddress { return useAtomValue(tokensByAddressAtom) } -type BridgeInfo = Record< - SupportedChainId, - { - tokenAddress: string - originBridgeAddress: string - destBridgeAddress: string - } -> - -export function useUnsupportedTokens(): { [address: string]: Token } { - const { chainId } = useWalletInfo() - const listsByUrl = useAllLists() - const unsupportedTokensMap = useUnsupportedTokenList() - const unsupportedTokens = useTokensFromMap(unsupportedTokensMap, false) - - // checks the default L2 lists to see if `bridgeInfo` has an L1 address value that is unsupported - const l2InferredBlockedTokens: typeof unsupportedTokens = useMemo(() => { - if (!chainId) { - return {} - } - - if (!listsByUrl) { - return {} - } - - const listUrl = getChainInfo(chainId)?.defaultListUrl - - if (!listUrl) { - return {} - } - - const { current: list } = listsByUrl[listUrl] - if (!list) { - return {} - } - - const unsupportedSet = new Set(Object.keys(unsupportedTokens)) - - return list.tokens.reduce((acc, tokenInfo) => { - const bridgeInfo = tokenInfo.extensions?.bridgeInfo as unknown as BridgeInfo - if ( - bridgeInfo && - bridgeInfo[SupportedChainId.MAINNET] && - bridgeInfo[SupportedChainId.MAINNET].tokenAddress && - unsupportedSet.has(bridgeInfo[SupportedChainId.MAINNET].tokenAddress) - ) { - const address = bridgeInfo[SupportedChainId.MAINNET].tokenAddress - // don't rely on decimals--it's possible that a token could be bridged w/ different decimals on the L2 - return { ...acc, [address]: new Token(SupportedChainId.MAINNET, address, tokenInfo.decimals) } - } - return acc - }, {}) - }, [chainId, listsByUrl, unsupportedTokens]) - - return { ...unsupportedTokens, ...l2InferredBlockedTokens } -} - export function useSearchInactiveTokenLists( search: string | undefined, minResults = 10, @@ -190,3 +94,31 @@ export function useCurrency(currencyId?: string | null): Currency | null | undef const tokens = useAllTokens() return useCurrencyFromMap(tokens, currencyId) } + +// mimics useAllBalances +export function useAllTokenBalances(): [TokenAmounts, boolean] { + const { account } = useWalletInfo() + const allTokens = useAllTokens() + // Mod, add favourite tokens to balances + const favTokens = useFavouriteTokens() + + const allTokensArray = useMemo(() => { + const favTokensObj = favTokens.reduce( + (acc, cur: Token) => { + acc[cur.address] = cur + return acc + }, + {} as { + [address: string]: Token + } + ) + + return Object.values({ ...favTokensObj, ...allTokens }) + }, [allTokens, favTokens]) + + const { isLoading, amounts } = useOnchainBalances({ + account: account ?? undefined, + tokens: allTokensArray, + }) + return [amounts ?? {}, isLoading] +} diff --git a/apps/cowswap-frontend/src/legacy/hooks/useAccountRiskCheck.ts b/apps/cowswap-frontend/src/legacy/hooks/useAccountRiskCheck.ts deleted file mode 100644 index 29de90842e..0000000000 --- a/apps/cowswap-frontend/src/legacy/hooks/useAccountRiskCheck.ts +++ /dev/null @@ -1,45 +0,0 @@ -import { useEffect } from 'react' - -import ms from 'ms.macro' - -import { ApplicationModal, setOpenModal } from 'legacy/state/application/reducer' -import { useAppDispatch } from 'legacy/state/hooks' - -import { sendEvent } from '../components/analytics/googleAnalytics' - -export default function useAccountRiskCheck(account: string | null | undefined) { - const dispatch = useAppDispatch() - - useEffect(() => { - if (account) { - const riskCheckLocalStorageKey = `risk-check-${account}` - const now = Date.now() - try { - const storedTime = localStorage.getItem(riskCheckLocalStorageKey) - const checkExpirationTime = storedTime ? parseInt(storedTime) : now - 1 - if (checkExpirationTime < Date.now()) { - const headers = new Headers({ 'Content-Type': 'application/json' }) - fetch('https://screening-worker.uniswap.workers.dev', { - method: 'POST', - headers, - body: JSON.stringify({ address: account }), - }) - .then((res) => res.json()) - .then((data) => { - if (data.block) { - dispatch(setOpenModal(ApplicationModal.BLOCKED_ACCOUNT)) - sendEvent({ - category: 'Address Screening', - action: 'blocked', - label: account, - }) - } - }) - .catch(() => dispatch(setOpenModal(null))) - } - } finally { - localStorage.setItem(riskCheckLocalStorageKey, (now + ms`7 days`).toString()) - } - } - }, [account, dispatch]) -} diff --git a/apps/cowswap-frontend/src/legacy/hooks/useActiveLocale.ts b/apps/cowswap-frontend/src/legacy/hooks/useActiveLocale.ts index 92a9aa942b..65ecf2614f 100644 --- a/apps/cowswap-frontend/src/legacy/hooks/useActiveLocale.ts +++ b/apps/cowswap-frontend/src/legacy/hooks/useActiveLocale.ts @@ -1,11 +1,10 @@ import { useMemo } from 'react' -import { DEFAULT_LOCALE, SUPPORTED_LOCALES, SupportedLocale } from 'legacy/constants/locales' -import store from 'legacy/state' -import { useUserLocale } from 'legacy/state/user/hooks' +import { DEFAULT_LOCALE, SUPPORTED_LOCALES, SupportedLocale } from '@cowprotocol/common-const' +import { useParsedQueryString, parsedQueryString } from '@cowprotocol/common-hooks' -import useParsedQueryString from './useParsedQueryString' -import { parsedQueryString } from './useParsedQueryString' +import { cowSwapStore } from 'legacy/state' +import { useUserLocale } from 'legacy/state/user/hooks' /** * Given a locale string (e.g. from user agent), return the best match for corresponding SupportedLocale @@ -35,7 +34,7 @@ export function navigatorLocale(): SupportedLocale | undefined { } function storeLocale(): SupportedLocale | undefined { - return store.getState().user.userLocale ?? undefined + return cowSwapStore.getState().user.userLocale ?? undefined } export const initialLocale = diff --git a/apps/cowswap-frontend/src/legacy/hooks/useActivityDerivedState.ts b/apps/cowswap-frontend/src/legacy/hooks/useActivityDerivedState.ts index 02876405e1..1572f033de 100644 --- a/apps/cowswap-frontend/src/legacy/hooks/useActivityDerivedState.ts +++ b/apps/cowswap-frontend/src/legacy/hooks/useActivityDerivedState.ts @@ -1,17 +1,16 @@ import { useMemo } from 'react' +import { getEtherscanLink, getExplorerOrderLink } from '@cowprotocol/common-utils' +import { getSafeWebUrl } from '@cowprotocol/core' +import { useGnosisSafeInfo } from '@cowprotocol/wallet' import { SafeInfoResponse } from '@safe-global/api-kit' -import { ActivityDescriptors, ActivityStatus, ActivityType } from 'legacy/hooks/useRecentActivity' import { EnhancedTransactionDetails } from 'legacy/state/enhancedTransactions/reducer' import { Order, OrderStatus } from 'legacy/state/orders/actions' -import { getEtherscanLink } from 'legacy/utils' -import { getExplorerOrderLink } from 'legacy/utils/explorer' import { ActivityDerivedState } from 'modules/account/containers/Transaction' -import { useGnosisSafeInfo } from 'modules/wallet' -import { getSafeWebUrl } from 'api/gnosisSafe' +import { ActivityDescriptors, ActivityStatus, ActivityType } from './useRecentActivity' export function useActivityDerivedState({ chainId, diff --git a/apps/cowswap-frontend/src/legacy/hooks/useAllCurrencyCombinations.ts b/apps/cowswap-frontend/src/legacy/hooks/useAllCurrencyCombinations.ts deleted file mode 100644 index 412a82200f..0000000000 --- a/apps/cowswap-frontend/src/legacy/hooks/useAllCurrencyCombinations.ts +++ /dev/null @@ -1,73 +0,0 @@ -import { useMemo } from 'react' - -import { Currency, Token } from '@uniswap/sdk-core' - -import { ADDITIONAL_BASES, BASES_TO_CHECK_TRADES_AGAINST, CUSTOM_BASES } from '../constants/routing' - -export function useAllCurrencyCombinations(currencyA?: Currency, currencyB?: Currency): [Token, Token][] { - const chainId = currencyA?.chainId - - const [tokenA, tokenB] = chainId ? [currencyA?.wrapped, currencyB?.wrapped] : [undefined, undefined] - - const bases: Token[] = useMemo(() => { - if (!chainId || chainId !== tokenB?.chainId) return [] - - const common = BASES_TO_CHECK_TRADES_AGAINST[chainId] ?? [] - const additionalA = tokenA ? ADDITIONAL_BASES[chainId]?.[tokenA.address] ?? [] : [] - const additionalB = tokenB ? ADDITIONAL_BASES[chainId]?.[tokenB.address] ?? [] : [] - - return [...common, ...additionalA, ...additionalB] - }, [chainId, tokenA, tokenB]) - - const basePairs: [Token, Token][] = useMemo( - () => - bases - .flatMap((base): [Token, Token][] => bases.map((otherBase) => [base, otherBase])) - // though redundant with the first filter below, that expression runs more often, so this is probably worthwhile - .filter(([t0, t1]) => !t0.equals(t1)), - [bases] - ) - - return useMemo( - () => - tokenA && tokenB - ? [ - // the direct pair - [tokenA, tokenB] as [Token, Token], - // token A against all bases - ...bases.map((base): [Token, Token] => [tokenA, base]), - // token B against all bases - ...bases.map((base): [Token, Token] => [tokenB, base]), - // each base against all bases - ...basePairs, - ] - // filter out invalid pairs comprised of the same asset (e.g. WETH<>WETH) - .filter(([t0, t1]) => !t0.equals(t1)) - // filter out duplicate pairs - .filter(([t0, t1], i, otherPairs) => { - // find the first index in the array at which there are the same 2 tokens as the current - const firstIndexInOtherPairs = otherPairs.findIndex(([t0Other, t1Other]) => { - return (t0.equals(t0Other) && t1.equals(t1Other)) || (t0.equals(t1Other) && t1.equals(t0Other)) - }) - // only accept the first occurrence of the same 2 tokens - return firstIndexInOtherPairs === i - }) - // optionally filter out some pairs for tokens with custom bases defined - .filter(([tokenA, tokenB]) => { - if (!chainId) return true - const customBases = CUSTOM_BASES[chainId] - - const customBasesA: Token[] | undefined = customBases?.[tokenA.address] - const customBasesB: Token[] | undefined = customBases?.[tokenB.address] - - if (!customBasesA && !customBasesB) return true - - if (customBasesA && !customBasesA.find((base) => tokenB.equals(base))) return false - if (customBasesB && !customBasesB.find((base) => tokenA.equals(base))) return false - - return true - }) - : [], - [tokenA, tokenB, bases, basePairs, chainId] - ) -} diff --git a/apps/cowswap-frontend/src/legacy/hooks/useApeModeQueryParamReader.ts b/apps/cowswap-frontend/src/legacy/hooks/useApeModeQueryParamReader.ts deleted file mode 100644 index 8cd1cc6071..0000000000 --- a/apps/cowswap-frontend/src/legacy/hooks/useApeModeQueryParamReader.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { useEffect } from 'react' - -import { useAppDispatch } from 'legacy/state/hooks' - -import useParsedQueryString from './useParsedQueryString' - -import { updateUserExpertMode } from '../state/user/reducer' - -export default function ApeModeQueryParamReader(): null { - useApeModeQueryParamReader() - return null -} - -function useApeModeQueryParamReader() { - const dispatch = useAppDispatch() - const { ape } = useParsedQueryString() - - useEffect(() => { - if (typeof ape !== 'string') return - if (ape === '' || ape.toLowerCase() === 'true') { - dispatch(updateUserExpertMode({ userExpertMode: true })) - } - }) -} diff --git a/apps/cowswap-frontend/src/legacy/hooks/useApproveCallback/index.ts b/apps/cowswap-frontend/src/legacy/hooks/useApproveCallback/index.ts index 406809c49f..0016fa3732 100644 --- a/apps/cowswap-frontend/src/legacy/hooks/useApproveCallback/index.ts +++ b/apps/cowswap-frontend/src/legacy/hooks/useApproveCallback/index.ts @@ -1,17 +1,15 @@ import { useMemo } from 'react' +import { V_COW_CONTRACT_ADDRESS } from '@cowprotocol/common-const' +import { useWalletInfo } from '@cowprotocol/wallet' import { TransactionResponse } from '@ethersproject/providers' import { Currency, CurrencyAmount, MaxUint256 } from '@uniswap/sdk-core' -import { V_COW_CONTRACT_ADDRESS } from 'legacy/constants' -import { ClaimType } from 'legacy/state/claim/hooks' - -import { useWalletInfo } from 'modules/wallet' - -import { EnhancedUserClaimData } from 'pages/Claim/types' - import { ApprovalState, ApproveCallbackParams, useApproveCallback } from './useApproveCallbackMod' +import { ClaimType } from '../../state/claim/hooks/types' +import { EnhancedUserClaimData } from '../../state/claim/types' + export type OptionalApproveCallbackParams = { transactionSummary?: string modalMessage?: string diff --git a/apps/cowswap-frontend/src/legacy/hooks/useApproveCallback/useApproveCallbackMod.ts b/apps/cowswap-frontend/src/legacy/hooks/useApproveCallback/useApproveCallbackMod.ts index 525a5b4f12..24d3238d5e 100644 --- a/apps/cowswap-frontend/src/legacy/hooks/useApproveCallback/useApproveCallbackMod.ts +++ b/apps/cowswap-frontend/src/legacy/hooks/useApproveCallback/useApproveCallbackMod.ts @@ -1,19 +1,18 @@ import { useCallback, useMemo } from 'react' +import { useTokenContract, usePrevious } from '@cowprotocol/common-hooks' +import { calculateGasMargin } from '@cowprotocol/common-utils' +import { useWalletInfo } from '@cowprotocol/wallet' import { BigNumber } from '@ethersproject/bignumber' import { MaxUint256 } from '@ethersproject/constants' import { TransactionResponse } from '@ethersproject/providers' import { Currency, CurrencyAmount } from '@uniswap/sdk-core' -import { ConfirmOperationType } from 'legacy/components/TransactionConfirmationModal' -import { useCurrency } from 'legacy/hooks/Tokens' -import { useTokenContract } from 'legacy/hooks/useContract' -import usePrevious from 'legacy/hooks/usePrevious' import { useTokenAllowance } from 'legacy/hooks/useTokenAllowance' import { useHasPendingApproval, useTransactionAdder } from 'legacy/state/enhancedTransactions/hooks' -import { calculateGasMargin } from 'legacy/utils/calculateGasMargin' -import { useWalletInfo } from 'modules/wallet' +import { ConfirmOperationType } from '../../state/types' +import { useCurrency } from '../Tokens' import { ApproveCallbackState, OptionalApproveCallbackParams } from './index' diff --git a/apps/cowswap-frontend/src/legacy/hooks/useArgentWalletContract.ts b/apps/cowswap-frontend/src/legacy/hooks/useArgentWalletContract.ts deleted file mode 100644 index 880bed8133..0000000000 --- a/apps/cowswap-frontend/src/legacy/hooks/useArgentWalletContract.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { ArgentWalletContract, ArgentWalletContractAbi } from '@cowswap/abis' - -import { useWalletInfo } from 'modules/wallet' - -import { useContract } from './useContract' -import useIsArgentWallet from './useIsArgentWallet' - -export function useArgentWalletContract(): ArgentWalletContract | null { - const { account } = useWalletInfo() - const isArgentWallet = useIsArgentWallet() - return useContract( - isArgentWallet ? account ?? undefined : undefined, - ArgentWalletContractAbi, - true - ) as ArgentWalletContract -} diff --git a/apps/cowswap-frontend/src/legacy/hooks/useColor/index.ts b/apps/cowswap-frontend/src/legacy/hooks/useColor/index.ts deleted file mode 100644 index 5f84aa9829..0000000000 --- a/apps/cowswap-frontend/src/legacy/hooks/useColor/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './useColorMod' diff --git a/apps/cowswap-frontend/src/legacy/hooks/useCombinedBalance.ts b/apps/cowswap-frontend/src/legacy/hooks/useCombinedBalance.ts new file mode 100644 index 0000000000..24ada8485b --- /dev/null +++ b/apps/cowswap-frontend/src/legacy/hooks/useCombinedBalance.ts @@ -0,0 +1,57 @@ +import { useMemo } from 'react' + +import { COW } from '@cowprotocol/common-const' +import { useWalletInfo } from '@cowprotocol/wallet' +import { CurrencyAmount } from '@uniswap/sdk-core' + +import JSBI from 'jsbi' + +import { useVCowData } from 'legacy/state/cowToken/hooks' + +import { useTokenBalance } from 'modules/tokens/hooks/useCurrencyBalance' + +/** + * Hook that returns COW balance + */ +function useCowBalance() { + const { chainId, account } = useWalletInfo() + const cowToken = chainId ? COW[chainId] : undefined + return useTokenBalance(account || undefined, cowToken) +} + +/** + * Hook that returns combined vCOW + COW balance + vCow from locked GNO + */ +export function useCombinedBalance() { + const { chainId, account } = useWalletInfo() + const { total: vCowBalance } = useVCowData() + // const { allocated, claimed } = useCowFromLockedGnoBalances() + const cowBalance = useCowBalance() + + // const lockedGnoBalance = useMemo(() => { + // if (!allocated || !claimed) { + // return + // } + + // return JSBI.subtract(allocated.quotient, claimed.quotient) + // }, [allocated, claimed]) + + return useMemo(() => { + let tmpBalance = JSBI.BigInt(0) + + const isLoading = !!(account && (!vCowBalance /* || !lockedGnoBalance */ || !cowBalance)) + + const cow = COW[chainId] + + if (account) { + if (vCowBalance) tmpBalance = JSBI.add(tmpBalance, vCowBalance.quotient) + // if (lockedGnoBalance) tmpBalance = JSBI.add(tmpBalance, lockedGnoBalance) + if (cowBalance) tmpBalance = JSBI.add(tmpBalance, cowBalance.quotient) + } + + // TODO: check COW vs vCOW + const balance = CurrencyAmount.fromRawAmount(cow, tmpBalance) + + return { balance, isLoading } + }, [vCowBalance, /* lockedGnoBalance, */ cowBalance, chainId, account]) +} diff --git a/apps/cowswap-frontend/src/legacy/hooks/useCowBalanceAndSubsidy.ts b/apps/cowswap-frontend/src/legacy/hooks/useCowBalanceAndSubsidy.ts index 566e0a6d1f..c6055b0d90 100644 --- a/apps/cowswap-frontend/src/legacy/hooks/useCowBalanceAndSubsidy.ts +++ b/apps/cowswap-frontend/src/legacy/hooks/useCowBalanceAndSubsidy.ts @@ -1,14 +1,14 @@ import { useMemo } from 'react' +import { useWalletInfo } from '@cowprotocol/wallet' import { CurrencyAmount, Token } from '@uniswap/sdk-core' import { BigNumber } from 'bignumber.js' import { COW_SUBSIDY_DATA } from 'legacy/components/CowSubsidyModal/constants' import { getDiscountFromBalance } from 'legacy/components/CowSubsidyModal/utils' -import { useCombinedBalance } from 'legacy/state/cowToken/hooks' -import { useWalletInfo } from 'modules/wallet' +import { useCombinedBalance } from './useCombinedBalance' const ZERO_BALANCE_SUBSIDY = { subsidy: { tier: 0, discount: COW_SUBSIDY_DATA[0][1] }, balance: undefined } diff --git a/apps/cowswap-frontend/src/legacy/hooks/useCurrentBlockTimestamp.ts b/apps/cowswap-frontend/src/legacy/hooks/useCurrentBlockTimestamp.ts index 0198ea62c8..701b902783 100644 --- a/apps/cowswap-frontend/src/legacy/hooks/useCurrentBlockTimestamp.ts +++ b/apps/cowswap-frontend/src/legacy/hooks/useCurrentBlockTimestamp.ts @@ -1,11 +1,10 @@ import { useMemo } from 'react' +import { useInterfaceMulticall } from '@cowprotocol/common-hooks' import { BigNumber } from '@ethersproject/bignumber' import { useSingleCallResult } from 'lib/hooks/multicall' -import { useInterfaceMulticall } from './useContract' - // gets the current timestamp from the blockchain export default function useCurrentBlockTimestamp(): BigNumber | undefined { const multicall = useInterfaceMulticall() diff --git a/apps/cowswap-frontend/src/legacy/hooks/useENSAddress.ts b/apps/cowswap-frontend/src/legacy/hooks/useENSAddress.ts deleted file mode 100644 index dacd96b5b5..0000000000 --- a/apps/cowswap-frontend/src/legacy/hooks/useENSAddress.ts +++ /dev/null @@ -1,38 +0,0 @@ -import { useMemo } from 'react' - -import { safeNamehash } from 'legacy/utils/safeNamehash' - -import { useSingleCallResult } from 'lib/hooks/multicall' - -import { useENSRegistrarContract, useENSResolverContract } from './useContract' -import useDebounce from './useDebounce' - -import isZero from '../utils/isZero' - -/** - * Does a lookup for an ENS name to find its address. - */ -export default function useENSAddress(ensName?: string | null): { loading: boolean; address: string | null } { - const debouncedName = useDebounce(ensName, 200) - const ensNodeArgument = useMemo( - () => [debouncedName === null ? undefined : safeNamehash(debouncedName)], - [debouncedName] - ) - const registrarContract = useENSRegistrarContract(false) - const resolverAddress = useSingleCallResult(registrarContract, 'resolver', ensNodeArgument) - const resolverAddressResult = resolverAddress.result?.[0] - const resolverContract = useENSResolverContract( - resolverAddressResult && !isZero(resolverAddressResult) ? resolverAddressResult : undefined, - false - ) - const addr = useSingleCallResult(resolverContract, 'addr', ensNodeArgument) - - const changed = debouncedName !== ensName - return useMemo( - () => ({ - address: changed ? null : addr.result?.[0] ?? null, - loading: changed || resolverAddress.loading || addr.loading, - }), - [addr.loading, addr.result, changed, resolverAddress.loading] - ) -} diff --git a/apps/cowswap-frontend/src/legacy/hooks/useENSAvatar.ts b/apps/cowswap-frontend/src/legacy/hooks/useENSAvatar.ts deleted file mode 100644 index f53e194dd1..0000000000 --- a/apps/cowswap-frontend/src/legacy/hooks/useENSAvatar.ts +++ /dev/null @@ -1,165 +0,0 @@ -import { useEffect, useMemo, useState } from 'react' - -import { BigNumber } from '@ethersproject/bignumber' -import { hexZeroPad } from '@ethersproject/bytes' -import { namehash } from '@ethersproject/hash' - -import { safeNamehash } from 'legacy/utils/safeNamehash' - -import { useWalletInfo } from 'modules/wallet' - -import { fetchWithBackoff } from 'common/utils/fetch' -import { useSingleCallResult } from 'lib/hooks/multicall' -import uriToHttp from 'lib/utils/uriToHttp' - -import { useENSRegistrarContract, useENSResolverContract, useERC1155Contract, useERC721Contract } from './useContract' -import useDebounce from './useDebounce' -import useENSName from './useENSName' - -import { isAddress } from '../utils' -import isZero from '../utils/isZero' - -/** - * Returns the ENS avatar URI, if available. - * Spec: https://gist.github.com/Arachnid/9db60bd75277969ee1689c8742b75182. - */ -export default function useENSAvatar( - address?: string, - enforceOwnership = true -): { avatar: string | null; loading: boolean } { - const debouncedAddress = useDebounce(address, 200) - const node = useMemo(() => { - if (!debouncedAddress || !isAddress(debouncedAddress)) return undefined - return namehash(`${debouncedAddress.toLowerCase().substr(2)}.addr.reverse`) - }, [debouncedAddress]) - - const addressAvatar = useAvatarFromNode(node) - const ENSName = useENSName(address).ENSName - const nameAvatar = useAvatarFromNode(ENSName === null ? undefined : safeNamehash(ENSName)) - let avatar = addressAvatar.avatar || nameAvatar.avatar - - const nftAvatar = useAvatarFromNFT(avatar, enforceOwnership) - avatar = nftAvatar.avatar || avatar - - const http = avatar && uriToHttp(avatar)[0] - - const changed = debouncedAddress !== address - return useMemo( - () => ({ - avatar: changed ? null : http ?? null, - loading: changed || addressAvatar.loading || nameAvatar.loading || nftAvatar.loading, - }), - [addressAvatar.loading, changed, http, nameAvatar.loading, nftAvatar.loading] - ) -} - -function useAvatarFromNode(node?: string): { avatar?: string; loading: boolean } { - const nodeArgument = useMemo(() => [node], [node]) - const textArgument = useMemo(() => [node, 'avatar'], [node]) - const registrarContract = useENSRegistrarContract(false) - const resolverAddress = useSingleCallResult(registrarContract, 'resolver', nodeArgument) - const resolverAddressResult = resolverAddress.result?.[0] - const resolverContract = useENSResolverContract( - resolverAddressResult && !isZero(resolverAddressResult) ? resolverAddressResult : undefined, - false - ) - const avatar = useSingleCallResult(resolverContract, 'text', textArgument) - - return useMemo( - () => ({ - avatar: avatar.result?.[0], - loading: resolverAddress.loading || avatar.loading, - }), - [avatar.loading, avatar.result, resolverAddress.loading] - ) -} - -function useAvatarFromNFT(nftUri = '', enforceOwnership: boolean): { avatar?: string; loading: boolean } { - const parts = nftUri.toLowerCase().split(':') - const protocol = parts[0] - // ignore the chain from eip155 - // TODO: when we are able, pull only from the specified chain - const [, erc] = parts[1]?.split('/') ?? [] - const [contractAddress, id] = parts[2]?.split('/') ?? [] - const isERC721 = protocol === 'eip155' && erc === 'erc721' - const isERC1155 = protocol === 'eip155' && erc === 'erc1155' - const erc721 = useERC721Uri(isERC721 ? contractAddress : undefined, id, enforceOwnership) - const erc1155 = useERC1155Uri(isERC1155 ? contractAddress : undefined, id, enforceOwnership) - const uri = erc721.uri || erc1155.uri - const http = uri && uriToHttp(uri)[0] - - const [loading, setLoading] = useState(false) - const [avatar, setAvatar] = useState(undefined) - useEffect(() => { - setAvatar(undefined) - if (http) { - setLoading(true) - fetchWithBackoff(http) - .then((res) => res.json()) - .then(({ image }) => { - setAvatar(image) - }) - .catch((e) => console.warn(e)) - .finally(() => { - setLoading(false) - }) - } - }, [http]) - - return useMemo( - () => ({ avatar, loading: erc721.loading || erc1155.loading || loading }), - [avatar, erc1155.loading, erc721.loading, loading] - ) -} - -function useERC721Uri( - contractAddress: string | undefined, - id: string | undefined, - enforceOwnership: boolean -): { uri?: string; loading: boolean } { - const idArgument = useMemo(() => [id], [id]) - const { account } = useWalletInfo() - const contract = useERC721Contract(contractAddress) - const owner = useSingleCallResult(contract, 'ownerOf', idArgument) - const uri = useSingleCallResult(contract, 'tokenURI', idArgument) - return useMemo( - () => ({ - uri: !enforceOwnership || account === owner.result?.[0] ? uri.result?.[0] : undefined, - loading: owner.loading || uri.loading, - }), - [account, enforceOwnership, owner.loading, owner.result, uri.loading, uri.result] - ) -} - -function useERC1155Uri( - contractAddress: string | undefined, - id: string | undefined, - enforceOwnership: boolean -): { uri?: string; loading: boolean } { - const { account } = useWalletInfo() - const idArgument = useMemo(() => [id], [id]) - const accountArgument = useMemo(() => [account || '', id], [account, id]) - const contract = useERC1155Contract(contractAddress) - const balance = useSingleCallResult(contract, 'balanceOf', accountArgument) - const uri = useSingleCallResult(contract, 'uri', idArgument) - // ERC-1155 allows a generic {id} in the URL, so prepare to replace if relevant, - // in lowercase hexadecimal (with no 0x prefix) and leading zero padded to 64 hex characters. - const idHex = getIdHex(id) - return useMemo( - () => ({ - uri: !enforceOwnership || balance.result?.[0] > 0 ? uri.result?.[0]?.replaceAll('{id}', idHex) : undefined, - loading: balance.loading || uri.loading, - }), - [balance.loading, balance.result, enforceOwnership, uri.loading, uri.result, idHex] - ) -} - -function getIdHex(id: string | undefined): string | undefined { - try { - return id ? hexZeroPad(BigNumber.from(id).toHexString(), 32).substring(2) : id - } catch (e) { - console.log(`Couldn't get id hex from id: ${id}`, e) - - return undefined - } -} diff --git a/apps/cowswap-frontend/src/legacy/hooks/useENSContentHash.ts b/apps/cowswap-frontend/src/legacy/hooks/useENSContentHash.ts deleted file mode 100644 index 9c07f471df..0000000000 --- a/apps/cowswap-frontend/src/legacy/hooks/useENSContentHash.ts +++ /dev/null @@ -1,32 +0,0 @@ -import { useMemo } from 'react' - -import { safeNamehash } from 'legacy/utils/safeNamehash' - -import { useSingleCallResult } from 'lib/hooks/multicall' - -import { useENSRegistrarContract, useENSResolverContract } from './useContract' - -import isZero from '../utils/isZero' - -/** - * Does a lookup for an ENS name to find its contenthash. - */ -export default function useENSContentHash(ensName?: string | null): { loading: boolean; contenthash: string | null } { - const ensNodeArgument = useMemo(() => [ensName === null ? undefined : safeNamehash(ensName)], [ensName]) - const registrarContract = useENSRegistrarContract(false) - const resolverAddressResult = useSingleCallResult(registrarContract, 'resolver', ensNodeArgument) - const resolverAddress = resolverAddressResult.result?.[0] - const resolverContract = useENSResolverContract( - resolverAddress && isZero(resolverAddress) ? undefined : resolverAddress, - false - ) - const contenthash = useSingleCallResult(resolverContract, 'contenthash', ensNodeArgument) - - return useMemo( - () => ({ - contenthash: contenthash.result?.[0] ?? null, - loading: resolverAddressResult.loading || contenthash.loading, - }), - [contenthash.loading, contenthash.result, resolverAddressResult.loading] - ) -} diff --git a/apps/cowswap-frontend/src/legacy/hooks/useENSName.ts b/apps/cowswap-frontend/src/legacy/hooks/useENSName.ts deleted file mode 100644 index a745544073..0000000000 --- a/apps/cowswap-frontend/src/legacy/hooks/useENSName.ts +++ /dev/null @@ -1,49 +0,0 @@ -import { useMemo } from 'react' - -import { namehash } from '@ethersproject/hash' - -import { useSingleCallResult } from 'lib/hooks/multicall' - -import { useENSRegistrarContract, useENSResolverContract } from './useContract' -import useDebounce from './useDebounce' -import useENSAddress from './useENSAddress' - -import { isAddress } from '../utils' -import isZero from '../utils/isZero' - -/** - * Does a reverse lookup for an address to find its ENS name. - * Note this is not the same as looking up an ENS name to find an address. - */ -export default function useENSName(address?: string): { ENSName: string | null; loading: boolean } { - const debouncedAddress = useDebounce(address, 200) - const ensNodeArgument = useMemo(() => { - if (!debouncedAddress || !isAddress(debouncedAddress)) return [undefined] - return [namehash(`${debouncedAddress.toLowerCase().substr(2)}.addr.reverse`)] - }, [debouncedAddress]) - const registrarContract = useENSRegistrarContract(false) - const resolverAddress = useSingleCallResult(registrarContract, 'resolver', ensNodeArgument) - const resolverAddressResult = resolverAddress.result?.[0] - const resolverContract = useENSResolverContract( - resolverAddressResult && !isZero(resolverAddressResult) ? resolverAddressResult : undefined, - false - ) - const nameCallRes = useSingleCallResult(resolverContract, 'name', ensNodeArgument) - const name = nameCallRes.result?.[0] - - /* ENS does not enforce that an address owns a .eth domain before setting it as a reverse proxy - and recommends that you perform a match on the forward resolution - see: https://docs.ens.domains/dapp-developer-guide/resolving-names#reverse-resolution - */ - const fwdAddr = useENSAddress(name) - const checkedName = address === fwdAddr?.address ? name : null - - const changed = debouncedAddress !== address - return useMemo( - () => ({ - ENSName: changed ? null : checkedName, - loading: changed || resolverAddress.loading || nameCallRes.loading, - }), - [changed, nameCallRes.loading, checkedName, resolverAddress.loading] - ) -} diff --git a/apps/cowswap-frontend/src/legacy/hooks/useErrorMessageAndModal.tsx b/apps/cowswap-frontend/src/legacy/hooks/useErrorMessageAndModal.tsx index 70633e00d8..b7a659aa9c 100644 --- a/apps/cowswap-frontend/src/legacy/hooks/useErrorMessageAndModal.tsx +++ b/apps/cowswap-frontend/src/legacy/hooks/useErrorMessageAndModal.tsx @@ -1,36 +1,7 @@ import { useMemo, useState } from 'react' -import { ErrorMessageProps, SwapCallbackError } from 'legacy/components/swap/styleds' - import useTransactionErrorModal from './useTransactionErrorModal' -/** - * @description hook for getting CoW Swap error and handling them visually - * @description ErrorMessage component accepts an error message to override exported error state, and a close option - * @returns returns object: { error, setError, ErrorMessage } => error message, error message setter, and our ErrorMessage component - */ -export function useErrorMessage() { - const [internalError, setError] = useState() - - return useMemo(() => { - const handleCloseError = () => setError(undefined) - - return { - error: internalError, - handleSetError: setError, - ErrorMessage: function ErrorMessage({ - error = internalError, - showClose = false, - ...rest - }: Pick) { - return error ? ( - - ) : null - }, - } - }, [internalError]) -} - export function useErrorModal() { const [internalError, setInternalError] = useState() const { openModal, closeModal, TransactionErrorModal } = useTransactionErrorModal() diff --git a/apps/cowswap-frontend/src/legacy/hooks/useFavouriteOrCommonTokens.tsx b/apps/cowswap-frontend/src/legacy/hooks/useFavouriteOrCommonTokens.tsx index 8b0aa5d85b..ed8f8f8f4d 100644 --- a/apps/cowswap-frontend/src/legacy/hooks/useFavouriteOrCommonTokens.tsx +++ b/apps/cowswap-frontend/src/legacy/hooks/useFavouriteOrCommonTokens.tsx @@ -1,9 +1,9 @@ import { useMemo } from 'react' -import { COMMON_BASES } from 'legacy/constants/routing' -import { useFavouriteTokens } from 'legacy/state/user/hooks' +import { COMMON_BASES } from '@cowprotocol/common-const' +import { useWalletInfo } from '@cowprotocol/wallet' -import { useWalletInfo } from 'modules/wallet' +import { useFavouriteTokens } from 'legacy/state/user/hooks' export function useFavouriteOrCommonTokens() { const { chainId } = useWalletInfo() diff --git a/apps/cowswap-frontend/src/legacy/hooks/useFetchListCallback.ts b/apps/cowswap-frontend/src/legacy/hooks/useFetchListCallback.ts index 78880c8ba8..4246458c47 100644 --- a/apps/cowswap-frontend/src/legacy/hooks/useFetchListCallback.ts +++ b/apps/cowswap-frontend/src/legacy/hooks/useFetchListCallback.ts @@ -2,20 +2,18 @@ import { useAtomValue, useSetAtom } from 'jotai' import { atomWithStorage } from 'jotai/utils' import { useCallback } from 'react' +import { MAINNET_PROVIDER } from '@cowprotocol/common-const' +import { atomWithPartialUpdate, resolveENSContentHash } from '@cowprotocol/common-utils' +import { useWalletInfo } from '@cowprotocol/wallet' import { TokenList } from '@uniswap/token-lists' import { nanoid } from '@reduxjs/toolkit' import ms from 'ms.macro' -import { MAINNET_PROVIDER } from 'legacy/constants/networks' import { useAppDispatch } from 'legacy/state/hooks' import { fetchTokenList } from 'legacy/state/lists/actions' -import { useWalletInfo } from 'modules/wallet' - import getTokenList from 'lib/hooks/useTokenList/fetchTokenList' -import resolveENSContentHash from 'lib/utils/resolveENSContentHash' -import { atomWithPartialUpdate } from 'utils/jotai/atomWithPartialUpdate' const TOKENS_LIST_ENS_CACHE_TIMEOUT = ms`6h` diff --git a/apps/cowswap-frontend/src/legacy/hooks/useGasPrice.ts b/apps/cowswap-frontend/src/legacy/hooks/useGasPrice.ts index ebfcfbdf56..327f0fa5b2 100644 --- a/apps/cowswap-frontend/src/legacy/hooks/useGasPrice.ts +++ b/apps/cowswap-frontend/src/legacy/hooks/useGasPrice.ts @@ -1,12 +1,12 @@ import { useMemo } from 'react' +import { useContract } from '@cowprotocol/common-hooks' +import { useENSAddress } from '@cowprotocol/ens' + import JSBI from 'jsbi' import { useSingleCallResult } from 'lib/hooks/multicall' -import { useContract } from './useContract' -import useENSAddress from './useENSAddress' - const CHAIN_DATA_ABI = [ { inputs: [], diff --git a/apps/cowswap-frontend/src/legacy/hooks/useGetSafeInfo.ts b/apps/cowswap-frontend/src/legacy/hooks/useGetSafeInfo.ts index 9ab23ace1b..3f8fdedf1b 100644 --- a/apps/cowswap-frontend/src/legacy/hooks/useGetSafeInfo.ts +++ b/apps/cowswap-frontend/src/legacy/hooks/useGetSafeInfo.ts @@ -1,16 +1,13 @@ import { useCallback } from 'react' +import { retry, RetryOptions } from '@cowprotocol/common-utils' +import { getSafeTransaction } from '@cowprotocol/core' +import { useWalletInfo } from '@cowprotocol/wallet' import { SafeMultisigTransactionResponse } from '@safe-global/safe-core-sdk-types' import { useWeb3React } from '@web3-react/core' import { RetryResult } from 'types' -import { retry, RetryOptions } from 'legacy/utils/retry' - -import { useWalletInfo } from 'modules/wallet' - -import { getSafeTransaction } from 'api/gnosisSafe' - const DEFAULT_RETRY_OPTIONS: RetryOptions = { n: 3, minWait: 1000, maxWait: 3000 } export type GetSafeInfo = (hash: string) => RetryResult diff --git a/apps/cowswap-frontend/src/legacy/hooks/useHttpLocations.ts b/apps/cowswap-frontend/src/legacy/hooks/useHttpLocations.ts index 688e25aba1..20f04ebe38 100644 --- a/apps/cowswap-frontend/src/legacy/hooks/useHttpLocations.ts +++ b/apps/cowswap-frontend/src/legacy/hooks/useHttpLocations.ts @@ -1,10 +1,7 @@ import { useMemo } from 'react' -import contenthashToUri from 'lib/utils/contenthashToUri' -import parseENSAddress from 'lib/utils/parseENSAddress' -import uriToHttp from 'lib/utils/uriToHttp' - -import useENSContentHash from './useENSContentHash' +import { contenthashToUri, parseENSAddress, uriToHttp } from '@cowprotocol/common-utils' +import { useENSContentHash } from '@cowprotocol/ens' export default function useHttpLocations(uri: string | undefined): string[] { const ens = useMemo(() => (uri ? parseENSAddress(uri) : undefined), [uri]) diff --git a/apps/cowswap-frontend/src/legacy/hooks/useIsActiveWallet.ts b/apps/cowswap-frontend/src/legacy/hooks/useIsActiveWallet.ts index b4cad5ac9d..5034ca64f9 100644 --- a/apps/cowswap-frontend/src/legacy/hooks/useIsActiveWallet.ts +++ b/apps/cowswap-frontend/src/legacy/hooks/useIsActiveWallet.ts @@ -1,9 +1,8 @@ +import { Web3ReactConnection } from '@cowprotocol/wallet' import { useWeb3React } from '@web3-react/core' import { useSelectedWallet } from 'legacy/state/user/hooks' -import { Web3ReactConnection } from 'modules/wallet/web3-react/types' - export const useIsActiveWallet = (connection: Web3ReactConnection) => { const { account } = useWeb3React() diff --git a/apps/cowswap-frontend/src/legacy/hooks/useIsAmbireWallet.ts b/apps/cowswap-frontend/src/legacy/hooks/useIsAmbireWallet.ts deleted file mode 100644 index c817985c2f..0000000000 --- a/apps/cowswap-frontend/src/legacy/hooks/useIsAmbireWallet.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { useWalletMetaData } from 'modules/wallet' -import { getIsAmbireWallet } from 'modules/wallet/api/utils/connection' - -export default function useIsAmbireWallet(): boolean { - const { walletName } = useWalletMetaData() - - return getIsAmbireWallet(walletName) -} diff --git a/apps/cowswap-frontend/src/legacy/hooks/useIsArgentWallet.ts b/apps/cowswap-frontend/src/legacy/hooks/useIsArgentWallet.ts deleted file mode 100644 index 8e10102a9a..0000000000 --- a/apps/cowswap-frontend/src/legacy/hooks/useIsArgentWallet.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { useMemo } from 'react' - -import { useWalletInfo } from 'modules/wallet' - -import { NEVER_RELOAD, useSingleCallResult } from 'lib/hooks/multicall' - -import { useArgentWalletDetectorContract } from './useContract' - -export default function useIsArgentWallet(): boolean { - const { account } = useWalletInfo() - const argentWalletDetector = useArgentWalletDetectorContract() - const inputs = useMemo(() => [account ?? undefined], [account]) - const call = useSingleCallResult(argentWalletDetector, 'isArgentWallet', inputs, NEVER_RELOAD) - return Boolean(call?.result?.[0]) -} diff --git a/apps/cowswap-frontend/src/legacy/hooks/useIsSwapUnsupported.ts b/apps/cowswap-frontend/src/legacy/hooks/useIsSwapUnsupported.ts deleted file mode 100644 index fac7bceb86..0000000000 --- a/apps/cowswap-frontend/src/legacy/hooks/useIsSwapUnsupported.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { useMemo } from 'react' - -import { Currency } from '@uniswap/sdk-core' - -import { useUnsupportedTokens } from 'legacy/hooks/Tokens' - -/** - * Returns true if the input currency or output currency cannot be traded in the interface - * @param currencyIn the input currency to check - * @param currencyOut the output currency to check - */ -export function useIsSwapUnsupported(currencyIn?: Currency | null, currencyOut?: Currency | null): boolean { - const unsupportedTokens = useUnsupportedTokens() - return useMemo(() => { - if (!unsupportedTokens) { - return false - } - const currencyInUnsupported = Boolean(currencyIn?.isToken && unsupportedTokens[currencyIn.address]) - const currencyOutUnsupported = Boolean(currencyOut?.isToken && unsupportedTokens[currencyOut.address]) - return currencyInUnsupported || currencyOutUnsupported - }, [currencyIn, currencyOut, unsupportedTokens]) -} diff --git a/apps/cowswap-frontend/src/legacy/hooks/useLocationLinkProps.ts b/apps/cowswap-frontend/src/legacy/hooks/useLocationLinkProps.ts deleted file mode 100644 index d812001598..0000000000 --- a/apps/cowswap-frontend/src/legacy/hooks/useLocationLinkProps.ts +++ /dev/null @@ -1,41 +0,0 @@ -import { useMemo } from 'react' - -import { LocationDescriptor } from 'history' -import { stringify } from 'qs' -import { useLocation } from 'react-router-dom' - -import { SupportedLocale } from 'legacy/constants/locales' -import useParsedQueryString from 'legacy/hooks/useParsedQueryString' - -import { useActiveLocale } from './useActiveLocale' - -import { sendEvent } from '../components/analytics/googleAnalytics' - -export function useLocationLinkProps(locale: SupportedLocale | null): { - to?: LocationDescriptor - onClick?: () => void -} { - const location = useLocation() - const qs = useParsedQueryString() - const activeLocale = useActiveLocale() - - return useMemo( - () => - !locale - ? {} - : { - to: { - ...location, - search: stringify({ ...qs, lng: locale }), - }, - onClick: () => { - sendEvent({ - category: 'Localization', - action: 'Switch Locale', - label: `${activeLocale} -> ${locale}`, - }) - }, - }, - [location, qs, activeLocale, locale] - ) -} diff --git a/apps/cowswap-frontend/src/legacy/hooks/useNetworkName.ts b/apps/cowswap-frontend/src/legacy/hooks/useNetworkName.ts deleted file mode 100644 index a25b5b1adf..0000000000 --- a/apps/cowswap-frontend/src/legacy/hooks/useNetworkName.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { useMemo } from 'react' - -import { CHAIN_INFO } from 'legacy/constants/chainInfo' - -import { useWalletInfo } from 'modules/wallet' - -export default function useNetworkName(): string | undefined { - const { chainId } = useWalletInfo() - - return useMemo(() => { - return CHAIN_INFO[chainId].label || '' - }, [chainId]) -} diff --git a/apps/cowswap-frontend/src/legacy/hooks/usePriceImpact/useFiatValuePriceImpact.ts b/apps/cowswap-frontend/src/legacy/hooks/usePriceImpact/useFiatValuePriceImpact.ts index e0561dcd3a..519cc9db61 100644 --- a/apps/cowswap-frontend/src/legacy/hooks/usePriceImpact/useFiatValuePriceImpact.ts +++ b/apps/cowswap-frontend/src/legacy/hooks/usePriceImpact/useFiatValuePriceImpact.ts @@ -1,11 +1,10 @@ +import { ONE_HUNDRED_PERCENT } from '@cowprotocol/common-const' +import { useDebounce } from '@cowprotocol/common-hooks' import { Currency, CurrencyAmount, Percent } from '@uniswap/sdk-core' import JSBI from 'jsbi' import ms from 'ms.macro' -import { ONE_HUNDRED_PERCENT } from 'legacy/constants/misc' -import useDebounce from 'legacy/hooks/useDebounce' - import { useDerivedTradeState } from 'modules/trade/hooks/useDerivedTradeState' import { useTradeUsdAmounts } from 'modules/usdAmount' diff --git a/apps/cowswap-frontend/src/legacy/hooks/useRecentActivity.ts b/apps/cowswap-frontend/src/legacy/hooks/useRecentActivity.ts index 435fcfb60f..1f653b49e0 100644 --- a/apps/cowswap-frontend/src/legacy/hooks/useRecentActivity.ts +++ b/apps/cowswap-frontend/src/legacy/hooks/useRecentActivity.ts @@ -1,17 +1,15 @@ import { useMemo } from 'react' +import { MAXIMUM_ORDERS_TO_DISPLAY } from '@cowprotocol/common-const' +import { getDateTimestamp } from '@cowprotocol/common-utils' import { OrderClass, SupportedChainId as ChainId } from '@cowprotocol/cow-sdk' +import { useWalletInfo } from '@cowprotocol/wallet' -import { MAXIMUM_ORDERS_TO_DISPLAY } from 'legacy/constants' import { isTransactionRecent, useAllTransactions, useTransactionsByHash } from 'legacy/state/enhancedTransactions/hooks' import { EnhancedTransactionDetails } from 'legacy/state/enhancedTransactions/reducer' import { Order, OrderStatus } from 'legacy/state/orders/actions' import { useCombinedPendingOrders, useOrder, useOrders, useOrdersById } from 'legacy/state/orders/hooks' -import { useWalletInfo } from 'modules/wallet' - -import { getDateTimestamp } from 'utils/time' - export interface AddedOrder extends Order { addedTime: number } diff --git a/apps/cowswap-frontend/src/legacy/hooks/useRefetchPriceCallback.tsx b/apps/cowswap-frontend/src/legacy/hooks/useRefetchPriceCallback.tsx index d858a2fe29..95ff6ea1f0 100644 --- a/apps/cowswap-frontend/src/legacy/hooks/useRefetchPriceCallback.tsx +++ b/apps/cowswap-frontend/src/legacy/hooks/useRefetchPriceCallback.tsx @@ -1,9 +1,18 @@ import { useCallback } from 'react' +import { isOnline } from '@cowprotocol/common-hooks' +import { + CancelableResult, + onlyResolvesLast, + getPromiseFulfilledValue, + isPromiseFulfilled, + registerOnWindow, + calculateValidTo, + getQuoteUnsupportedToken, +} from '@cowprotocol/common-utils' import { PriceQuality } from '@cowprotocol/cow-sdk' import { useGetGpPriceStrategy } from 'legacy/hooks/useGetGpPriceStrategy' -import { isOnline } from 'legacy/hooks/useIsOnline' import { AddGpUnsupportedTokenParams } from 'legacy/state/lists/actions' import { useAddGpUnsupportedToken, @@ -13,9 +22,8 @@ import { import { QuoteError } from 'legacy/state/price/actions' import { useQuoteDispatchers } from 'legacy/state/price/hooks' import { QuoteInformationObject } from 'legacy/state/price/reducer' +import { LegacyFeeQuoteParams, LegacyQuoteParams } from 'legacy/state/price/types' import { useUserTransactionTTL } from 'legacy/state/user/hooks' -import { CancelableResult, onlyResolvesLast } from 'legacy/utils/async' -import { getPromiseFulfilledValue, isPromiseFulfilled, registerOnWindow } from 'legacy/utils/misc' import { getBestQuote, getFastQuote, QuoteResult } from 'legacy/utils/price' import { useIsEoaEthFlow } from 'modules/swap/hooks/useIsEoaEthFlow' @@ -26,9 +34,6 @@ import GpQuoteError, { GpQuoteErrorDetails, isValidQuoteError, } from 'api/gnosisProtocol/errors/QuoteError' -import { LegacyFeeQuoteParams, LegacyQuoteParams } from 'api/gnosisProtocol/legacy/types' -import { getQuoteUnsupportedToken } from 'utils/getQuoteUnsupportedToken' -import { calculateValidTo } from 'utils/time' interface HandleQuoteErrorParams { quoteData: QuoteInformationObject | LegacyFeeQuoteParams @@ -241,12 +246,6 @@ export function useRefetchQuoteCallback() { }, } - // Register get best and fast quote methods on window - registerOnWindow({ - getBestQuote: async () => getBestQuoteResolveOnlyLastCall(bestQuoteParams), - getFastQuote: async () => getFastQuoteResolveOnlyLastCall(fastQuoteParams), - }) - // Get the fast quote if (!isPriceRefresh) { getFastQuoteResolveOnlyLastCall(fastQuoteParams) diff --git a/apps/cowswap-frontend/src/legacy/hooks/useTheme.ts b/apps/cowswap-frontend/src/legacy/hooks/useTheme.ts deleted file mode 100644 index eca5cc2471..0000000000 --- a/apps/cowswap-frontend/src/legacy/hooks/useTheme.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { useContext } from 'react' - -import { ThemeContext } from 'styled-components/macro' - -export default function useTheme() { - return useContext(ThemeContext) -} diff --git a/apps/cowswap-frontend/src/legacy/hooks/useTokenAllowance.ts b/apps/cowswap-frontend/src/legacy/hooks/useTokenAllowance.ts index 673d35f939..0de703a8f2 100644 --- a/apps/cowswap-frontend/src/legacy/hooks/useTokenAllowance.ts +++ b/apps/cowswap-frontend/src/legacy/hooks/useTokenAllowance.ts @@ -1,13 +1,12 @@ import { useMemo } from 'react' +import { useTokenContract } from '@cowprotocol/common-hooks' import { CurrencyAmount, Token } from '@uniswap/sdk-core' import { Nullish } from 'types' import { useSingleCallResult } from 'lib/hooks/multicall' -import { useTokenContract } from './useContract' - export function useTokenAllowance( token: Nullish, owner?: string, diff --git a/apps/cowswap-frontend/src/legacy/hooks/useTokenInfoFromActiveList.ts b/apps/cowswap-frontend/src/legacy/hooks/useTokenInfoFromActiveList.ts deleted file mode 100644 index 788cd14f2c..0000000000 --- a/apps/cowswap-frontend/src/legacy/hooks/useTokenInfoFromActiveList.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { useMemo } from 'react' - -import { Currency } from '@uniswap/sdk-core' - -import { useCombinedActiveList } from 'legacy/state/lists/hooks' - -import { useWalletInfo } from 'modules/wallet' - -/** - * Returns a WrappedTokenInfo from the active token lists when possible, - * or the passed token otherwise. */ -export function useTokenInfoFromActiveList(currency: Currency) { - const { chainId } = useWalletInfo() - const activeList = useCombinedActiveList() - - return useMemo(() => { - if (!chainId) return - if (currency.isNative) return currency - - try { - return activeList[chainId][currency.wrapped.address].token - } catch (e: any) { - return currency - } - }, [activeList, chainId, currency]) -} diff --git a/apps/cowswap-frontend/src/legacy/hooks/useTokenLazy.ts b/apps/cowswap-frontend/src/legacy/hooks/useTokenLazy.ts index 4a1acbf487..a1978de686 100644 --- a/apps/cowswap-frontend/src/legacy/hooks/useTokenLazy.ts +++ b/apps/cowswap-frontend/src/legacy/hooks/useTokenLazy.ts @@ -1,16 +1,15 @@ import { useCallback } from 'react' -import { Erc20 } from '@cowswap/abis' +import { Erc20 } from '@cowprotocol/abis' +import { getBytes32TokenContract, getTokenContract } from '@cowprotocol/common-hooks' +import { retry } from '@cowprotocol/common-utils' +import { useWalletInfo } from '@cowprotocol/wallet' import { Contract } from '@ethersproject/contracts' import { JsonRpcProvider } from '@ethersproject/providers' import { Token } from '@uniswap/sdk-core' import { useWeb3React } from '@web3-react/core' -import { getBytes32TokenContract, getTokenContract } from 'legacy/hooks/useContract' import { useAddUserToken } from 'legacy/state/user/hooks' -import { retry } from 'legacy/utils/retry' - -import { useWalletInfo } from 'modules/wallet' import { parseStringOrBytes32 } from 'lib/hooks/useCurrency' diff --git a/apps/cowswap-frontend/src/legacy/hooks/useTotalSupply.ts b/apps/cowswap-frontend/src/legacy/hooks/useTotalSupply.ts index 070dfc2571..87b1b9db60 100644 --- a/apps/cowswap-frontend/src/legacy/hooks/useTotalSupply.ts +++ b/apps/cowswap-frontend/src/legacy/hooks/useTotalSupply.ts @@ -1,11 +1,10 @@ import { useMemo } from 'react' +import { useTokenContract } from '@cowprotocol/common-hooks' import { Currency, CurrencyAmount, Token } from '@uniswap/sdk-core' import { useSingleCallResult } from 'lib/hooks/multicall' -import { useTokenContract } from './useContract' - // returns undefined if input token is undefined, or fails to get token contract, // or contract total supply cannot be fetched export function useTotalSupply(token?: Currency): CurrencyAmount | undefined { diff --git a/apps/cowswap-frontend/src/legacy/hooks/useTransactionConfirmationModal.tsx b/apps/cowswap-frontend/src/legacy/hooks/useTransactionConfirmationModal.tsx index 574eac9894..157b2f0c1a 100644 --- a/apps/cowswap-frontend/src/legacy/hooks/useTransactionConfirmationModal.tsx +++ b/apps/cowswap-frontend/src/legacy/hooks/useTransactionConfirmationModal.tsx @@ -1,9 +1,11 @@ import { useState, useCallback } from 'react' -import { TransactionConfirmationModal, ConfirmOperationType } from 'legacy/components/TransactionConfirmationModal' +import { TransactionConfirmationModal } from 'legacy/components/TransactionConfirmationModal' import { useOpenModal, useCloseModals, useModalIsOpen } from 'legacy/state/application/hooks' import { ApplicationModal } from 'legacy/state/application/reducer' +import { ConfirmOperationType } from '../state/types' + export default function useTransactionConfirmationModal( defaultOperationType: ConfirmOperationType = ConfirmOperationType.WRAP_ETHER ) { diff --git a/apps/cowswap-frontend/src/legacy/hooks/useWrapCallback.ts b/apps/cowswap-frontend/src/legacy/hooks/useWrapCallback.ts index 363b5ce6af..7dc8c777ae 100644 --- a/apps/cowswap-frontend/src/legacy/hooks/useWrapCallback.ts +++ b/apps/cowswap-frontend/src/legacy/hooks/useWrapCallback.ts @@ -1,22 +1,19 @@ +import { wrapAnalytics } from '@cowprotocol/analytics' +import { RADIX_HEX } from '@cowprotocol/common-const' +import { getChainCurrencySymbols } from '@cowprotocol/common-const' +import { calculateGasMargin, formatTokenAmount, isRejectRequestProviderError } from '@cowprotocol/common-utils' import { SupportedChainId } from '@cowprotocol/cow-sdk' import { BigNumber } from '@ethersproject/bignumber' import { Contract } from '@ethersproject/contracts' import { TransactionResponse } from '@ethersproject/providers' import { Currency, CurrencyAmount } from '@uniswap/sdk-core' -import { wrapAnalytics } from 'legacy/components/analytics' -import { ConfirmOperationType } from 'legacy/components/TransactionConfirmationModal' -import { getOperationMessage } from 'legacy/components/TransactionConfirmationModal/LegacyConfirmationPendingContent' -import { RADIX_HEX } from 'legacy/constants' import { useTransactionAdder } from 'legacy/state/enhancedTransactions/hooks' -import { calculateGasMargin } from 'legacy/utils/calculateGasMargin' -import { getChainCurrencySymbols } from 'legacy/utils/gnosis_chain/hack' import { ExtendedTradeRawState, TradeRawState } from 'modules/trade/types/TradeRawState' -import { formatTokenAmount } from 'utils/amountFormat' - -import { isRejectRequestProviderError } from '../utils/misc' +import { getOperationMessage } from '../components/TransactionConfirmationModal/LegacyConfirmationPendingContent' +import { ConfirmOperationType } from '../state/types' // Use a 180K gas as a fallback if there's issue calculating the gas estimation (fixes some issues with some nodes failing to calculate gas costs for SC wallets) const WRAP_UNWRAP_GAS_LIMIT_DEFAULT = BigNumber.from('180000') diff --git a/apps/cowswap-frontend/src/legacy/state/application/hooks.ts b/apps/cowswap-frontend/src/legacy/state/application/hooks.ts index cb8eb4da2b..73990bfb27 100644 --- a/apps/cowswap-frontend/src/legacy/state/application/hooks.ts +++ b/apps/cowswap-frontend/src/legacy/state/application/hooks.ts @@ -1,11 +1,13 @@ import { useCallback, useMemo } from 'react' +import { DEFAULT_TXN_DISMISS_MS } from '@cowprotocol/common-const' + import { createAction } from '@reduxjs/toolkit' -import { DEFAULT_TXN_DISMISS_MS } from 'legacy/constants/misc' -import { AppState } from 'legacy/state' -import { addPopup, ApplicationModal, PopupContent, removePopup } from 'legacy/state/application/reducer' -import { useAppDispatch, useAppSelector } from 'legacy/state/hooks' +import { addPopup, ApplicationModal, PopupContent, removePopup } from './reducer' + +import { useAppDispatch, useAppSelector } from '../hooks' +import { AppState } from '../index' export const setOpenModal = createAction('application/setOpenModal') @@ -66,7 +68,7 @@ export function useTogglePrivacyPolicy(): () => void { } /** - * @deprecated use @cowswap/snackbars instead + * @deprecated use @cowprotocol/snackbars instead */ export function useRemovePopup(): (key: string) => void { const dispatch = useAppDispatch() @@ -79,7 +81,7 @@ export function useRemovePopup(): (key: string) => void { } /** - * @deprecated use @cowswap/snackbars instead + * @deprecated use @cowprotocol/snackbars instead */ export function useActivePopups(): AppState['application']['popupList'] { const list = useAppSelector((state: AppState) => state.application.popupList) @@ -102,7 +104,7 @@ export function useCloseModals(): () => void { } /** - * @deprecated use @cowswap/snackbars instead + * @deprecated use @cowprotocol/snackbars instead */ export function useAddPopup(): (content: PopupContent, key?: string, removeAfterMs?: number | null) => void { const dispatch = useAppDispatch() diff --git a/apps/cowswap-frontend/src/legacy/state/application/initialState.ts b/apps/cowswap-frontend/src/legacy/state/application/initialState.ts index 506ed1ca9d..e3f262d3a6 100644 --- a/apps/cowswap-frontend/src/legacy/state/application/initialState.ts +++ b/apps/cowswap-frontend/src/legacy/state/application/initialState.ts @@ -1,5 +1,5 @@ -import { localWarning } from 'legacy/state/application/localWarning' -import { ApplicationState } from 'legacy/state/application/reducer' +import { localWarning } from './localWarning' +import { ApplicationState } from './reducer' const popupList: ApplicationState['popupList'] = [] diff --git a/apps/cowswap-frontend/src/legacy/state/application/localWarning.ts b/apps/cowswap-frontend/src/legacy/state/application/localWarning.ts index 6f8039615f..f89b5293c9 100644 --- a/apps/cowswap-frontend/src/legacy/state/application/localWarning.ts +++ b/apps/cowswap-frontend/src/legacy/state/application/localWarning.ts @@ -1,5 +1,5 @@ -import { PINATA_API_KEY, PINATA_SECRET_API_KEY } from 'legacy/constants/ipfs' -import { isLocal } from 'legacy/utils/environments' +import { PINATA_API_KEY, PINATA_SECRET_API_KEY } from '@cowprotocol/common-const' +import { isLocal } from '@cowprotocol/common-utils' let warningMsg diff --git a/apps/cowswap-frontend/src/legacy/state/application/reducer.ts b/apps/cowswap-frontend/src/legacy/state/application/reducer.ts index 4add005de0..3b1d4f3c94 100644 --- a/apps/cowswap-frontend/src/legacy/state/application/reducer.ts +++ b/apps/cowswap-frontend/src/legacy/state/application/reducer.ts @@ -1,12 +1,12 @@ +import { DEFAULT_TXN_DISMISS_MS } from '@cowprotocol/common-const' +import { BlockExplorerLinkType } from '@cowprotocol/common-utils' import { SupportedChainId } from '@cowprotocol/cow-sdk' import { createSlice, nanoid } from '@reduxjs/toolkit' import { FlattenInterpolation, ThemeProps, DefaultTheme } from 'styled-components/macro' import { Nullish } from 'types' -import { DEFAULT_TXN_DISMISS_MS } from 'legacy/constants/misc' -import { initialState } from 'legacy/state/application/initialState' -import { BlockExplorerLinkType } from 'legacy/utils' +import { initialState } from './initialState' type BasePopupContent = { failedSwitchNetwork: SupportedChainId diff --git a/apps/cowswap-frontend/src/legacy/state/claim/actions.ts b/apps/cowswap-frontend/src/legacy/state/claim/actions.ts index 36a2668ddc..358368d100 100644 --- a/apps/cowswap-frontend/src/legacy/state/claim/actions.ts +++ b/apps/cowswap-frontend/src/legacy/state/claim/actions.ts @@ -2,7 +2,7 @@ import { SupportedChainId } from '@cowprotocol/cow-sdk' import { createAction } from '@reduxjs/toolkit' -import { ClaimInfo } from 'legacy/state/claim/reducer' +import { ClaimInfo } from './reducer' export enum ClaimStatus { DEFAULT = 'DEFAULT', @@ -12,33 +12,6 @@ export enum ClaimStatus { FAILED = 'FAILED', } -export type ClaimActions = { - // account - setInputAddress: (payload: string) => void - setActiveClaimAccount: (payload: string) => void - setActiveClaimAccountENS: (payload: string) => void - - // search - setIsSearchUsed: (payload: boolean) => void - - // claiming - setClaimStatus: (payload: ClaimStatus) => void - setClaimedAmount: (payload: string) => void - setEstimatedGas: (payload: string) => void - - // investing - setIsInvestFlowActive: (payload: boolean) => void - setInvestFlowStep: (payload: number) => void - initInvestFlowData: () => void - updateInvestAmount: (payload: { index: number; amount: string }) => void - updateInvestError: (payload: { index: number; error: string | undefined }) => void - setIsTouched: (payload: { index: number; isTouched: boolean }) => void - - // claim row selection - setSelected: (payload: number[]) => void - setSelectedAll: (payload: boolean) => void -} - // accounts export const setInputAddress = createAction('claim/setInputAddress') export const setActiveClaimAccount = createAction('claim/setActiveClaimAccount') diff --git a/apps/cowswap-frontend/src/legacy/state/claim/hooks/const.ts b/apps/cowswap-frontend/src/legacy/state/claim/hooks/const.ts new file mode 100644 index 0000000000..c684a50073 --- /dev/null +++ b/apps/cowswap-frontend/src/legacy/state/claim/hooks/const.ts @@ -0,0 +1,7 @@ +import { ClaimType } from './types' + +const CLAIMS_REPO_BRANCH = 'main' + +export const CLAIMS_REPO = `https://raw.githubusercontent.com/cowprotocol/cow-merkle-drop/${CLAIMS_REPO_BRANCH}/` +export const FREE_CLAIM_TYPES: ClaimType[] = [ClaimType.Airdrop, ClaimType.Team, ClaimType.Advisor] +export const PAID_CLAIM_TYPES: ClaimType[] = [ClaimType.GnoOption, ClaimType.UserOption, ClaimType.Investor] diff --git a/apps/cowswap-frontend/src/legacy/state/claim/hooks/index.ts b/apps/cowswap-frontend/src/legacy/state/claim/hooks/index.ts index a5aaba7fe6..ccedc9e2b8 100644 --- a/apps/cowswap-frontend/src/legacy/state/claim/hooks/index.ts +++ b/apps/cowswap-frontend/src/legacy/state/claim/hooks/index.ts @@ -1,8 +1,11 @@ import { useCallback, useEffect, useMemo, useRef, useState } from 'react' -import { SupportedChainId as ChainId } from '@cowprotocol/cow-sdk' -import { SupportedChainId } from '@cowprotocol/cow-sdk' -import { VCow } from '@cowswap/abis' +import { VCow } from '@cowprotocol/abis' +import { GpEther, V_COW } from '@cowprotocol/common-const' +import { useIsMounted, useVCowContract } from '@cowprotocol/common-hooks' +import { calculateGasMargin, formatTokenAmount, isAddress } from '@cowprotocol/common-utils' +import { SupportedChainId as ChainId, SupportedChainId } from '@cowprotocol/cow-sdk' +import { useWalletInfo } from '@cowprotocol/wallet' import { BigNumber } from '@ethersproject/bignumber' import { TransactionResponse } from '@ethersproject/providers' import { parseUnits } from '@ethersproject/units' @@ -11,55 +14,44 @@ import { CurrencyAmount, Price, Token } from '@uniswap/sdk-core' import JSBI from 'jsbi' import ms from 'ms.macro' -import { useSelector, useDispatch } from 'react-redux' +import { useDispatch, useSelector } from 'react-redux' -import { GpEther, V_COW } from 'legacy/constants/tokens' -import { useVCowContract } from 'legacy/hooks/useContract' -import useIsMounted from 'legacy/hooks/useIsMounted' -import { AppDispatch } from 'legacy/state' -import { AppState } from 'legacy/state' +import { useSingleContractMultipleData } from 'lib/hooks/multicall' + +import { PAID_CLAIM_TYPES } from './const' +import { ClaimInput, ClaimType, RepoClaims, UserClaims, VCowPrices } from './types' import { + claimTypeToTokenAmount, getClaimKey, getClaimsRepoPath, isFreeClaim, - claimTypeToTokenAmount, transformRepoClaimsToUserClaims, -} from 'legacy/state/claim/hooks/utils' -import { ClaimInfo } from 'legacy/state/claim/reducer' -import { useTransactionAdder } from 'legacy/state/enhancedTransactions/hooks' -import { useAllClaimingTransactionIndices } from 'legacy/state/enhancedTransactions/hooks' -import { isAddress } from 'legacy/utils' -import { calculateGasMargin } from 'legacy/utils/calculateGasMargin' - -import { useWalletInfo } from 'modules/wallet' - -import { useSingleContractMultipleData } from 'lib/hooks/multicall' -import { EnhancedUserClaimData } from 'pages/Claim/types' -import { formatTokenAmount } from 'utils/amountFormat' +} from './utils' +import { useAllClaimingTransactionIndices, useTransactionAdder } from '../../enhancedTransactions/hooks' +import { AppDispatch, AppState } from '../../index' import { - setInputAddress, + ClaimStatus, + initInvestFlowData, + resetClaimUi, setActiveClaimAccount, setActiveClaimAccountENS, - setIsSearchUsed, - setClaimStatus, setClaimedAmount, - setIsInvestFlowActive, + setClaimsCount, + setClaimStatus, + setEstimatedGas, + setInputAddress, setInvestFlowStep, - initInvestFlowData, - updateInvestAmount, + setIsInvestFlowActive, + setIsSearchUsed, + setIsTouched, setSelected, setSelectedAll, - ClaimStatus, - resetClaimUi, + updateInvestAmount, updateInvestError, - setEstimatedGas, - setIsTouched, - setClaimsCount, } from '../actions' - -const CLAIMS_REPO_BRANCH = 'main' -export const CLAIMS_REPO = `https://raw.githubusercontent.com/cowprotocol/cow-merkle-drop/${CLAIMS_REPO_BRANCH}/` +import { ClaimInfo } from '../reducer' +import { EnhancedUserClaimData } from '../types' // Base amount = 1 VCOW const ONE_VCOW = CurrencyAmount.fromRawAmount( @@ -74,20 +66,8 @@ const AIRDROP_TIME = ms`6 weeks` // For native token price calculation const DENOMINATOR = JSBI.exponentiate(JSBI.BigInt(10), JSBI.BigInt(18)) -export enum ClaimType { - Airdrop, // free, no vesting, can be available on both mainnet and gchain - GnoOption, // paid, with vesting, must use GNO, can be available on both mainnet and gchain - UserOption, // paid, with vesting, must use Native currency, can be available on both mainnet and gchain - Investor, // paid, with vesting, must use USDC, only on mainnet - Team, // free, with vesting, only on mainnet - Advisor, // free, with vesting, only on mainnet -} - type RepoClaimType = keyof typeof ClaimType -export const FREE_CLAIM_TYPES: ClaimType[] = [ClaimType.Airdrop, ClaimType.Team, ClaimType.Advisor] -export const PAID_CLAIM_TYPES: ClaimType[] = [ClaimType.GnoOption, ClaimType.UserOption, ClaimType.Investor] - export interface UserClaimData { index: number amount: string @@ -99,23 +79,8 @@ export type RepoClaimData = Omit & { type: RepoClaimType } -export interface ClaimInput { - /** - * The index of the claim - */ - index: number - /** - * The amount of the claim. Optional - * If not present, will claim the full amount - */ - amount?: string -} - type Account = string | null | undefined -export type UserClaims = UserClaimData[] -export type RepoClaims = RepoClaimData[] - export type ClassifiedUserClaims = { available: UserClaims expired: UserClaims @@ -402,12 +367,6 @@ function _useVCowPriceForToken(priceFnName: VCowPriceFnNames): string | null { return price } -export type VCowPrices = { - native: string | null - gno: string | null - usdc: string | null -} - export function useVCowPrices(): VCowPrices { const native = useNativeTokenPrice() const gno = useGnoPrice() diff --git a/apps/cowswap-frontend/src/legacy/state/claim/hooks/types.ts b/apps/cowswap-frontend/src/legacy/state/claim/hooks/types.ts new file mode 100644 index 0000000000..dd593fd8b3 --- /dev/null +++ b/apps/cowswap-frontend/src/legacy/state/claim/hooks/types.ts @@ -0,0 +1,30 @@ +import { RepoClaimData, UserClaimData } from './index' + +export enum ClaimType { + Airdrop, // free, no vesting, can be available on both mainnet and gchain + GnoOption, // paid, with vesting, must use GNO, can be available on both mainnet and gchain + UserOption, // paid, with vesting, must use Native currency, can be available on both mainnet and gchain + Investor, // paid, with vesting, must use USDC, only on mainnet + Team, // free, with vesting, only on mainnet + Advisor, // free, with vesting, only on mainnet +} + +export interface ClaimInput { + /** + * The index of the claim + */ + index: number + /** + * The amount of the claim. Optional + * If not present, will claim the full amount + */ + amount?: string +} + +export type UserClaims = UserClaimData[] +export type RepoClaims = RepoClaimData[] +export type VCowPrices = { + native: string | null + gno: string | null + usdc: string | null +} diff --git a/apps/cowswap-frontend/src/legacy/state/claim/hooks/utils.ts b/apps/cowswap-frontend/src/legacy/state/claim/hooks/utils.ts index e936f0e6f5..d6cca292b8 100644 --- a/apps/cowswap-frontend/src/legacy/state/claim/hooks/utils.ts +++ b/apps/cowswap-frontend/src/legacy/state/claim/hooks/utils.ts @@ -1,21 +1,12 @@ +import { GpEther, USDC, GNO, ZERO_PERCENT, ONE_HUNDRED_PERCENT } from '@cowprotocol/common-const' import { SupportedChainId } from '@cowprotocol/cow-sdk' import { Currency, CurrencyAmount, Percent, Token } from '@uniswap/sdk-core' -import { ONE_HUNDRED_PERCENT, ZERO_PERCENT } from 'legacy/constants/misc' -import { GNO, GpEther, USDC } from 'legacy/constants/tokens' -import { - CLAIMS_REPO, - ClaimType, - FREE_CLAIM_TYPES, - PAID_CLAIM_TYPES, - RepoClaims, - UserClaims, - VCowPrices, -} from 'legacy/state/claim/hooks/index' -import { ClaimInput } from 'legacy/state/claim/hooks/index' -import { InvestClaim } from 'legacy/state/claim/reducer' - -import { EnhancedUserClaimData, InvestmentAmounts } from 'pages/Claim/types' +import { CLAIMS_REPO, FREE_CLAIM_TYPES, PAID_CLAIM_TYPES } from './const' +import { ClaimInput, ClaimType, RepoClaims, UserClaims, VCowPrices } from './types' + +import { InvestClaim } from '../reducer' +import { EnhancedUserClaimData, InvestmentAmounts } from '../types' /** * Helper function to check whether any claim is an investment option diff --git a/apps/cowswap-frontend/src/pages/Claim/types.ts b/apps/cowswap-frontend/src/legacy/state/claim/types.ts similarity index 89% rename from apps/cowswap-frontend/src/pages/Claim/types.ts rename to apps/cowswap-frontend/src/legacy/state/claim/types.ts index 436889852d..bba01d01c3 100644 --- a/apps/cowswap-frontend/src/pages/Claim/types.ts +++ b/apps/cowswap-frontend/src/legacy/state/claim/types.ts @@ -1,9 +1,9 @@ import { SyntheticEvent } from 'react' +import { GpEther } from '@cowprotocol/common-const' import { Currency, CurrencyAmount, Price, Token } from '@uniswap/sdk-core' -import { GpEther } from 'legacy/constants/tokens' -import { UserClaimData } from 'legacy/state/claim/hooks' +import { UserClaimData } from './hooks' export type ClaimCommonTypes = { account: string | null | undefined diff --git a/apps/cowswap-frontend/src/legacy/state/claim/updater.tsx b/apps/cowswap-frontend/src/legacy/state/claim/updater.tsx index 23e17bc005..3388fd2753 100644 --- a/apps/cowswap-frontend/src/legacy/state/claim/updater.tsx +++ b/apps/cowswap-frontend/src/legacy/state/claim/updater.tsx @@ -1,16 +1,10 @@ import { useEffect, useMemo } from 'react' import { SupportedChainId } from '@cowprotocol/cow-sdk' +import { useWalletInfo } from '@cowprotocol/wallet' -import { - ClassifiedUserClaims, - useClaimDispatchers, - useClaimState, - useClassifiedUserClaims, -} from 'legacy/state/claim/hooks' -import { ClaimInfo } from 'legacy/state/claim/reducer' - -import { useWalletInfo } from 'modules/wallet' +import { ClassifiedUserClaims, useClaimDispatchers, useClaimState, useClassifiedUserClaims } from './hooks' +import { ClaimInfo } from './reducer' export default function Updater() { const { chainId } = useWalletInfo() diff --git a/apps/cowswap-frontend/src/legacy/state/connection/hooks.ts b/apps/cowswap-frontend/src/legacy/state/connection/hooks.ts deleted file mode 100644 index d75ecd87e5..0000000000 --- a/apps/cowswap-frontend/src/legacy/state/connection/hooks.ts +++ /dev/null @@ -1,38 +0,0 @@ -import { useMemo } from 'react' - -import { Token } from '@uniswap/sdk-core' - -import { useAllTokens } from 'legacy/hooks/Tokens' -import { useFavouriteTokens } from 'legacy/state/user/hooks' - -import { useOnchainBalances } from 'modules/tokens' -import { TokenAmounts } from 'modules/tokens' -import { useWalletInfo } from 'modules/wallet' - -// mimics useAllBalances -export function useAllTokenBalances(): [TokenAmounts, boolean] { - const { account } = useWalletInfo() - const allTokens = useAllTokens() - // Mod, add favourite tokens to balances - const favTokens = useFavouriteTokens() - - const allTokensArray = useMemo(() => { - const favTokensObj = favTokens.reduce( - (acc, cur: Token) => { - acc[cur.address] = cur - return acc - }, - {} as { - [address: string]: Token - } - ) - - return Object.values({ ...favTokensObj, ...allTokens }) - }, [allTokens, favTokens]) - - const { isLoading, amounts } = useOnchainBalances({ - account: account ?? undefined, - tokens: allTokensArray, - }) - return [amounts ?? {}, isLoading] -} diff --git a/apps/cowswap-frontend/src/legacy/state/connection/reducer.ts b/apps/cowswap-frontend/src/legacy/state/connection/reducer.ts index 14ae1b7651..c5c8f5ce32 100644 --- a/apps/cowswap-frontend/src/legacy/state/connection/reducer.ts +++ b/apps/cowswap-frontend/src/legacy/state/connection/reducer.ts @@ -1,6 +1,6 @@ -import { createSlice } from '@reduxjs/toolkit' +import { ConnectionType } from '@cowprotocol/wallet' -import { ConnectionType } from 'modules/wallet' +import { createSlice } from '@reduxjs/toolkit' export interface ConnectionState { errorByConnectionType: Record @@ -14,7 +14,7 @@ export const initialState: ConnectionState = { } const connectionSlice = createSlice({ - name: 'modules/wallet/web3-react/utils/connection', + name: 'wallet-connection', initialState, reducers: { updateConnectionError( diff --git a/apps/cowswap-frontend/src/legacy/state/cowToken/hooks.ts b/apps/cowswap-frontend/src/legacy/state/cowToken/hooks.ts index 5770448a2a..6558986cbc 100644 --- a/apps/cowswap-frontend/src/legacy/state/cowToken/hooks.ts +++ b/apps/cowswap-frontend/src/legacy/state/cowToken/hooks.ts @@ -1,25 +1,21 @@ import { useCallback, useMemo } from 'react' +import { V_COW } from '@cowprotocol/common-const' +import { useVCowContract } from '@cowprotocol/common-hooks' +import { useWalletInfo } from '@cowprotocol/wallet' import { TransactionResponse } from '@ethersproject/providers' import { Currency, CurrencyAmount } from '@uniswap/sdk-core' -import JSBI from 'jsbi' - -import { ConfirmOperationType } from 'legacy/components/TransactionConfirmationModal' -import { V_COW, COW } from 'legacy/constants/tokens' -import { APPROVE_GAS_LIMIT_DEFAULT } from 'legacy/hooks/useApproveCallback/useApproveCallbackMod' -import { useVCowContract } from 'legacy/hooks/useContract' -import { AppState } from 'legacy/state' -import { useTransactionAdder } from 'legacy/state/enhancedTransactions/hooks' -import { useAppDispatch, useAppSelector } from 'legacy/state/hooks' - -import { useTokenBalance } from 'modules/tokens/hooks/useCurrencyBalance' -import { useWalletInfo } from 'modules/wallet' - -import { useSingleCallResult, CallStateResult as Result } from 'lib/hooks/multicall' +import { CallStateResult as Result, useSingleCallResult } from 'lib/hooks/multicall' import { setSwapVCowStatus, SwapVCowStatus } from './actions' +import { APPROVE_GAS_LIMIT_DEFAULT } from '../../hooks/useApproveCallback/useApproveCallbackMod' +import { useTransactionAdder } from '../enhancedTransactions/hooks' +import { useAppDispatch, useAppSelector } from '../hooks' +import { AppState } from '../index' +import { ConfirmOperationType } from '../types' + export type SetSwapVCowStatusCallback = (payload: SwapVCowStatus) => void type VCowData = { @@ -156,49 +152,3 @@ export function useSetSwapVCowStatus(): SetSwapVCowStatusCallback { export function useSwapVCowStatus() { return useAppSelector((state: AppState) => state.cowToken.swapVCowStatus) } - -/** - * Hook that returns COW balance - */ -export function useCowBalance() { - const { chainId, account } = useWalletInfo() - const cowToken = chainId ? COW[chainId] : undefined - return useTokenBalance(account || undefined, cowToken) -} - -/** - * Hook that returns combined vCOW + COW balance + vCow from locked GNO - */ -export function useCombinedBalance() { - const { chainId, account } = useWalletInfo() - const { total: vCowBalance } = useVCowData() - // const { allocated, claimed } = useCowFromLockedGnoBalances() - const cowBalance = useCowBalance() - - // const lockedGnoBalance = useMemo(() => { - // if (!allocated || !claimed) { - // return - // } - - // return JSBI.subtract(allocated.quotient, claimed.quotient) - // }, [allocated, claimed]) - - return useMemo(() => { - let tmpBalance = JSBI.BigInt(0) - - const isLoading = !!(account && (!vCowBalance /* || !lockedGnoBalance */ || !cowBalance)) - - const cow = COW[chainId] - - if (account) { - if (vCowBalance) tmpBalance = JSBI.add(tmpBalance, vCowBalance.quotient) - // if (lockedGnoBalance) tmpBalance = JSBI.add(tmpBalance, lockedGnoBalance) - if (cowBalance) tmpBalance = JSBI.add(tmpBalance, cowBalance.quotient) - } - - // TODO: check COW vs vCOW - const balance = CurrencyAmount.fromRawAmount(cow, tmpBalance) - - return { balance, isLoading } - }, [vCowBalance, /* lockedGnoBalance, */ cowBalance, chainId, account]) -} diff --git a/apps/cowswap-frontend/src/legacy/state/cowToken/middleware.ts b/apps/cowswap-frontend/src/legacy/state/cowToken/middleware.ts index 46670f65de..89852f3350 100644 --- a/apps/cowswap-frontend/src/legacy/state/cowToken/middleware.ts +++ b/apps/cowswap-frontend/src/legacy/state/cowToken/middleware.ts @@ -1,11 +1,11 @@ -import { isAnyOf, Middleware } from '@reduxjs/toolkit' +import { getCowSoundError, getCowSoundSuccess } from '@cowprotocol/common-utils' -import { AppState } from 'legacy/state' -import { getCowSoundSuccess, getCowSoundError } from 'legacy/utils/sound' +import { isAnyOf, Middleware } from '@reduxjs/toolkit' import { setSwapVCowStatus, SwapVCowStatus } from './actions' import { finalizeTransaction } from '../enhancedTransactions/actions' +import { AppState } from '../index' const isFinalizeTransaction = isAnyOf(finalizeTransaction) diff --git a/apps/cowswap-frontend/src/legacy/state/enhancedTransactions/hooks/TransactionHooksMod.tsx b/apps/cowswap-frontend/src/legacy/state/enhancedTransactions/hooks/TransactionHooksMod.tsx index 08efffa04b..16bbf7479f 100644 --- a/apps/cowswap-frontend/src/legacy/state/enhancedTransactions/hooks/TransactionHooksMod.tsx +++ b/apps/cowswap-frontend/src/legacy/state/enhancedTransactions/hooks/TransactionHooksMod.tsx @@ -1,9 +1,8 @@ import { useMemo } from 'react' -import { useAppSelector } from 'legacy/state/hooks' - -import { useWalletInfo } from 'modules/wallet' +import { useWalletInfo } from '@cowprotocol/wallet' +import { useAppSelector } from '../../hooks' import { EnhancedTransactionDetails } from '../reducer' // returns all the transactions for the current chain diff --git a/apps/cowswap-frontend/src/legacy/state/enhancedTransactions/hooks/index.ts b/apps/cowswap-frontend/src/legacy/state/enhancedTransactions/hooks/index.ts index d90451ad02..cb9a814b0f 100644 --- a/apps/cowswap-frontend/src/legacy/state/enhancedTransactions/hooks/index.ts +++ b/apps/cowswap-frontend/src/legacy/state/enhancedTransactions/hooks/index.ts @@ -1,10 +1,10 @@ import { useCallback, useMemo } from 'react' -import { useAllTransactions } from 'legacy/state/enhancedTransactions/hooks/index' -import { useAppDispatch } from 'legacy/state/hooks' +import { useWalletInfo, useIsSafeWallet } from '@cowprotocol/wallet' -import { useWalletInfo, useIsSafeWallet } from 'modules/wallet' +import { useAllTransactions } from './TransactionHooksMod' +import { useAppDispatch } from '../../hooks' import { addTransaction, AddTransactionParams } from '../actions' import { EnhancedTransactionDetails, HashType } from '../reducer' diff --git a/apps/cowswap-frontend/src/legacy/state/enhancedTransactions/reducer.ts b/apps/cowswap-frontend/src/legacy/state/enhancedTransactions/reducer.ts index 797e31daf7..5b491a5ad0 100644 --- a/apps/cowswap-frontend/src/legacy/state/enhancedTransactions/reducer.ts +++ b/apps/cowswap-frontend/src/legacy/state/enhancedTransactions/reducer.ts @@ -12,7 +12,7 @@ import { updateSafeTransaction, ReplacementType, SerializableTransactionReceipt, -} from 'legacy/state/enhancedTransactions/actions' +} from './actions' export enum HashType { ETHEREUM_TX = 'ETHEREUM_TX', diff --git a/apps/cowswap-frontend/src/legacy/state/enhancedTransactions/updater/index.tsx b/apps/cowswap-frontend/src/legacy/state/enhancedTransactions/updater/index.tsx deleted file mode 100644 index 44786f61ae..0000000000 --- a/apps/cowswap-frontend/src/legacy/state/enhancedTransactions/updater/index.tsx +++ /dev/null @@ -1,13 +0,0 @@ -import React from 'react' - -import CancelReplaceTxUpdater from './CancelReplaceTxUpdater' -import FinalizeTxUpdater from './FinalizeTxUpdater' - -export default function Updater() { - return ( - <> - - - - ) -} diff --git a/apps/cowswap-frontend/src/legacy/state/gas/actions.ts b/apps/cowswap-frontend/src/legacy/state/gas/actions.ts index 4af7a31ade..e89e042717 100644 --- a/apps/cowswap-frontend/src/legacy/state/gas/actions.ts +++ b/apps/cowswap-frontend/src/legacy/state/gas/actions.ts @@ -1,9 +1,9 @@ import { createAction } from '@reduxjs/toolkit' -import { WithChainId } from 'legacy/state/lists/actions' - import { GasFeeEndpointResponse } from 'api/gasPrices' +import { WithChainId } from '../lists/actions' + export type UpdateGasPrices = GasFeeEndpointResponse & WithChainId export const updateGasPrices = createAction('gas/updateGasPrices') diff --git a/apps/cowswap-frontend/src/legacy/state/gas/atoms.ts b/apps/cowswap-frontend/src/legacy/state/gas/atoms.ts index 6c4b231ac5..53cb47e594 100644 --- a/apps/cowswap-frontend/src/legacy/state/gas/atoms.ts +++ b/apps/cowswap-frontend/src/legacy/state/gas/atoms.ts @@ -1,6 +1,6 @@ import { atom } from 'jotai' -import { DEFAULT_GP_PRICE_STRATEGY } from 'legacy/constants' +import { DEFAULT_GP_PRICE_STRATEGY } from '@cowprotocol/common-const' export type GpPriceStrategy = 'COWSWAP' | 'LEGACY' diff --git a/apps/cowswap-frontend/src/legacy/state/gas/gas-price-strategy-updater.tsx b/apps/cowswap-frontend/src/legacy/state/gas/gas-price-strategy-updater.tsx index fa2e021437..d1bb63d8c8 100644 --- a/apps/cowswap-frontend/src/legacy/state/gas/gas-price-strategy-updater.tsx +++ b/apps/cowswap-frontend/src/legacy/state/gas/gas-price-strategy-updater.tsx @@ -1,15 +1,15 @@ import { useSetAtom } from 'jotai' import { useEffect } from 'react' -import ms from 'ms.macro' - -import { DEFAULT_GP_PRICE_STRATEGY } from 'legacy/constants' -import { gasPriceStrategyAtom } from 'legacy/state/gas/atoms' +import { DEFAULT_GP_PRICE_STRATEGY } from '@cowprotocol/common-const' +import { useWalletInfo } from '@cowprotocol/wallet' -import { useWalletInfo } from 'modules/wallet' +import ms from 'ms.macro' import { getPriceStrategy } from 'api/gnosisProtocol/priceApi' +import { gasPriceStrategyAtom } from './atoms' + const GP_PRICE_STRATEGY_INTERVAL_TIME = ms`30 minutes` export function GasPriceStrategyUpdater(): null { diff --git a/apps/cowswap-frontend/src/legacy/state/gas/hooks.ts b/apps/cowswap-frontend/src/legacy/state/gas/hooks.ts index 753bedece7..df58a68901 100644 --- a/apps/cowswap-frontend/src/legacy/state/gas/hooks.ts +++ b/apps/cowswap-frontend/src/legacy/state/gas/hooks.ts @@ -1,33 +1,13 @@ -import { useSetAtom } from 'jotai' -import { useCallback } from 'react' - import { SupportedChainId as ChainId } from '@cowprotocol/cow-sdk' -import { useSelector, useDispatch } from 'react-redux' - -import { AppDispatch } from 'legacy/state' -import { AppState } from 'legacy/state' +import { useSelector } from 'react-redux' -import { gasPriceAtom } from 'modules/gasPirce' - -import { updateGasPrices, UpdateGasPrices } from './actions' import { GasState } from './reducer' +import { AppState } from '../index' + export function useGasPrices(chainId?: ChainId) { return useSelector((state) => { return chainId ? state.gas[chainId] : null }) } - -export function useUpdateGasPrices() { - const dispatch = useDispatch() - const setGasPrice = useSetAtom(gasPriceAtom) - - return useCallback( - (gasParams: UpdateGasPrices) => { - dispatch(updateGasPrices(gasParams)) - setGasPrice(gasParams) - }, - [dispatch, setGasPrice] - ) -} diff --git a/apps/cowswap-frontend/src/legacy/state/global/actions.ts b/apps/cowswap-frontend/src/legacy/state/global/actions.ts index d4cfa1d5e4..4094748f77 100644 --- a/apps/cowswap-frontend/src/legacy/state/global/actions.ts +++ b/apps/cowswap-frontend/src/legacy/state/global/actions.ts @@ -1,6 +1,6 @@ import { createAction } from '@reduxjs/toolkit' -import { WithChainId } from 'legacy/state/lists/actions' +import { WithChainId } from '../lists/actions' // fired once when the app reloads but before the app renders // allows any updates to be applied to store data loaded from localStorage diff --git a/apps/cowswap-frontend/src/legacy/state/hooks/index.ts b/apps/cowswap-frontend/src/legacy/state/hooks/index.ts index 0b2089a33e..1412b2aef9 100644 --- a/apps/cowswap-frontend/src/legacy/state/hooks/index.ts +++ b/apps/cowswap-frontend/src/legacy/state/hooks/index.ts @@ -1,6 +1,6 @@ import { TypedUseSelectorHook, useDispatch, useSelector } from 'react-redux' -import { AppDispatch, AppState } from 'legacy/state' +import { AppDispatch, AppState } from '../index' export const useAppDispatch = () => useDispatch() export const useAppSelector: TypedUseSelectorHook = useSelector diff --git a/apps/cowswap-frontend/src/legacy/state/index.ts b/apps/cowswap-frontend/src/legacy/state/index.ts index 86b5acadd5..d76c9a9fab 100644 --- a/apps/cowswap-frontend/src/legacy/state/index.ts +++ b/apps/cowswap-frontend/src/legacy/state/index.ts @@ -1,39 +1,36 @@ +import { DEFAULT_NETWORK_FOR_LISTS } from '@cowprotocol/common-const' + import { configureStore, StateFromReducersMapObject } from '@reduxjs/toolkit' import { load, save } from 'redux-localstorage-simple' -import { DEFAULT_NETWORK_FOR_LISTS } from 'legacy/constants/lists' -import application from 'legacy/state/application/reducer' -import claim from 'legacy/state/claim/reducer' -import connection from 'legacy/state/connection/reducer' -import { cowTokenMiddleware } from 'legacy/state/cowToken/middleware' -import cowToken from 'legacy/state/cowToken/reducer' -import enhancedTransactions from 'legacy/state/enhancedTransactions/reducer' -import gas from 'legacy/state/gas/reducer' -import { updateVersion } from 'legacy/state/global/actions' -import lists from 'legacy/state/lists/reducer' -import logs from 'legacy/state/logs/slice' -import orders from 'legacy/state/orders/reducer' -import { priceMiddleware } from 'legacy/state/price/middleware' -import price from 'legacy/state/price/reducer' -import profile from 'legacy/state/profile/reducer' -import swap from 'legacy/state/swap/reducer' -import user from 'legacy/state/user/reducer' - -import multicall from 'lib/state/multicall' +// import { composableOrdersPopupMiddleware } from 'modules/twap/state/composableOrdersPopupMiddleware' -import { appziMiddleware, popupMiddleware, soundMiddleware, composableOrdersPopupMiddleware } from './orders/middleware' +import application from './application/reducer' +import claim from './claim/reducer' +import connection from './connection/reducer' +import { cowTokenMiddleware } from './cowToken/middleware' +import cowToken from './cowToken/reducer' +import enhancedTransactions from './enhancedTransactions/reducer' +import gas from './gas/reducer' +import { updateVersion } from './global/actions' +import lists from './lists/reducer' +import logs from './logs/slice' +import { multicall } from './multicall' +import { appziMiddleware, popupMiddleware, soundMiddleware } from './orders/middleware' +import orders from './orders/reducer' +import { priceMiddleware } from './price/middleware' +import price from './price/reducer' +import profile from './profile/reducer' +import swap from './swap/reducer' +import user from './user/reducer' -const UNISWAP_REDUCERS = { +const reducers = { application, user, connection, swap, multicall: multicall.reducer, logs, -} - -const reducers = { - ...UNISWAP_REDUCERS, transactions: enhancedTransactions, // replace transactions state by "enhancedTransactions" lists, orders, @@ -46,13 +43,14 @@ const reducers = { const PERSISTED_KEYS: string[] = ['user', 'transactions', 'orders', 'lists', 'gas', 'affiliate', 'profile', 'swap'] -const store = configureStore({ +export const cowSwapStore = configureStore({ reducer: reducers, middleware: (getDefaultMiddleware) => getDefaultMiddleware({ thunk: true, serializableCheck: false }) .concat(save({ states: PERSISTED_KEYS, debounce: 1000 })) .concat(popupMiddleware) - .concat(composableOrdersPopupMiddleware) + // TODO: fix it + // .concat(composableOrdersPopupMiddleware) .concat(cowTokenMiddleware) .concat(soundMiddleware) .concat(appziMiddleware) @@ -61,12 +59,10 @@ const store = configureStore({ }) // this instantiates the app / reducers in several places using the default chainId -store.dispatch(updateVersion({ chainId: DEFAULT_NETWORK_FOR_LISTS })) +cowSwapStore.dispatch(updateVersion({ chainId: DEFAULT_NETWORK_FOR_LISTS })) // TODO: this is new, should we enable it? // setupListeners(store.dispatch) -export default store - export type AppState = StateFromReducersMapObject -export type AppDispatch = typeof store.dispatch +export type AppDispatch = typeof cowSwapStore.dispatch diff --git a/apps/cowswap-frontend/src/legacy/state/lists/hooks.ts b/apps/cowswap-frontend/src/legacy/state/lists/hooks.ts index 428ddc176b..c9f96e4f02 100644 --- a/apps/cowswap-frontend/src/legacy/state/lists/hooks.ts +++ b/apps/cowswap-frontend/src/legacy/state/lists/hooks.ts @@ -1,6 +1,8 @@ import { useCallback, useMemo } from 'react' +import { UNSUPPORTED_LIST_URLS } from '@cowprotocol/common-const' import { SupportedChainId as ChainId } from '@cowprotocol/cow-sdk' +import { useWalletInfo } from '@cowprotocol/wallet' import DEFAULT_TOKEN_LIST from '@uniswap/default-token-list' import { Currency } from '@uniswap/sdk-core' import { TokenInfo } from '@uniswap/token-lists' @@ -8,23 +10,18 @@ import { TokenInfo } from '@uniswap/token-lists' import { shallowEqual } from 'react-redux' import { Nullish } from 'types' -import { UNSUPPORTED_LIST_URLS } from 'legacy/constants/lists' -import BROKEN_LIST from 'legacy/constants/tokenLists/broken.tokenlist.json' -import UNSUPPORTED_TOKEN_LIST from 'legacy/constants/tokenLists/unsupported.tokenlist.json' -import { AppState } from 'legacy/state' -import { useAppDispatch, useAppSelector } from 'legacy/state/hooks' +import { UnsupportedToken } from 'api/gnosisProtocol' +import { ChainTokenMap, tokensToChainTokenMap } from 'lib/hooks/useTokenList/utils' + import { addGpUnsupportedToken, AddGpUnsupportedTokenParams, removeGpUnsupportedToken, RemoveGpUnsupportedTokenParams, -} from 'legacy/state/lists/actions' -import sortByListPriority from 'legacy/utils/listSort' +} from './actions' -import { useWalletInfo } from 'modules/wallet' - -import { UnsupportedToken } from 'api/gnosisProtocol' -import { ChainTokenMap, tokensToChainTokenMap } from 'lib/hooks/useTokenList/utils' +import { useAppDispatch, useAppSelector } from '../hooks' +import { AppState } from '../index' export type TokenAddressMap = ChainTokenMap @@ -34,11 +31,8 @@ type Mutable = { export function useActiveListUrls(): string[] | undefined { const { chainId } = useWalletInfo() - const activeListUrls = useAppSelector((state) => state.lists[chainId]?.activeListUrls, shallowEqual) - return useMemo(() => { - return activeListUrls?.filter((url) => !UNSUPPORTED_LIST_URLS[chainId]?.includes(url)) - }, [chainId, activeListUrls]) + return useAppSelector((state) => state.lists[chainId]?.activeListUrls, shallowEqual) } export function useAllLists(): AppState['lists'][ChainId]['byUrl'] { @@ -77,48 +71,22 @@ export function useCombinedTokenMapFromUrls(urls: string[] | undefined): TokenAd const lists = useAllLists() return useMemo(() => { if (!urls) return {} - return ( - urls - .slice() - // sort by priority so top priority goes last - .sort(sortByListPriority) - .reduce((allTokens, currentUrl) => { - const current = lists[currentUrl]?.current - if (!current) return allTokens - try { - return combineMaps(allTokens, tokensToChainTokenMap(current)) - } catch (error: any) { - console.error('Could not show token list due to error', error) - return allTokens - } - }, {}) - ) + return urls.slice().reduce((allTokens, currentUrl) => { + const current = lists[currentUrl]?.current + if (!current) return allTokens + try { + return combineMaps(allTokens, tokensToChainTokenMap(current)) + } catch (error: any) { + console.error('Could not show token list due to error', error) + return allTokens + } + }, {}) }, [lists, urls]) } -// get all the tokens from active lists, combine with local default tokens -export function useCombinedActiveList(): TokenAddressMap { - const activeListUrls = useActiveListUrls() - const activeTokens = useCombinedTokenMapFromUrls(activeListUrls) - return activeTokens -} - // list of tokens not supported on interface for various reasons, used to show warnings and prevent swaps and adds export function useUnsupportedTokenList(): TokenAddressMap { - // get hard-coded broken tokens - const brokenListMap = useMemo(() => tokensToChainTokenMap(BROKEN_LIST), []) - - // get hard-coded list of unsupported tokens - const localUnsupportedListMap = useMemo(() => tokensToChainTokenMap(UNSUPPORTED_TOKEN_LIST), []) - - // get dynamic list of unsupported tokens - const loadedUnsupportedListMap = useCombinedTokenMapFromUrls(UNSUPPORTED_LIST_URLS[1]) - - // format into one token address map - return useMemo( - () => combineMaps(brokenListMap, combineMaps(localUnsupportedListMap, loadedUnsupportedListMap)), - [brokenListMap, localUnsupportedListMap, loadedUnsupportedListMap] - ) + return useCombinedTokenMapFromUrls(UNSUPPORTED_LIST_URLS[1]) } export function useTokensListFromUrls(urls: string[] | undefined): TokenInfo[] { @@ -127,16 +95,12 @@ export function useTokensListFromUrls(urls: string[] | undefined): TokenInfo[] { return useMemo(() => { if (!urls) return [] - return ( - urls - .slice() - // sort by priority so top priority goes last - .sort(sortByListPriority) - .map((url) => { - return lists?.[url]?.current?.tokens || [] - }) - .flat() - ) + return urls + .slice() + .map((url) => { + return lists?.[url]?.current?.tokens || [] + }) + .flat() }, [lists, urls]) } diff --git a/apps/cowswap-frontend/src/legacy/state/lists/reducer.test.ts b/apps/cowswap-frontend/src/legacy/state/lists/reducer.test.ts index 8fe6778621..ce5824454c 100644 --- a/apps/cowswap-frontend/src/legacy/state/lists/reducer.test.ts +++ b/apps/cowswap-frontend/src/legacy/state/lists/reducer.test.ts @@ -1,11 +1,12 @@ +import { DEFAULT_ACTIVE_LIST_URLS_BY_NETWORK, DEFAULT_LIST_OF_LISTS_BY_NETWORK } from '@cowprotocol/common-const' import { SupportedChainId as ChainId } from '@cowprotocol/cow-sdk' import { createStore, Store } from 'redux' -import { DEFAULT_ACTIVE_LIST_URLS_BY_NETWORK, DEFAULT_LIST_OF_LISTS_BY_NETWORK } from 'legacy/constants/lists' -import { updateVersion } from 'legacy/state/global/actions' -import { fetchTokenList, acceptListUpdate, addList, removeList, enableList } from 'legacy/state/lists/actions' -import reducer, { ListsStateByNetwork } from 'legacy/state/lists/reducer' +import { fetchTokenList, acceptListUpdate, addList, removeList, enableList } from './actions' +import reducer, { ListsStateByNetwork } from './reducer' + +import { updateVersion } from '../global/actions' const DEFAULT_LIST_OF_LISTS = DEFAULT_LIST_OF_LISTS_BY_NETWORK[ChainId.MAINNET] diff --git a/apps/cowswap-frontend/src/legacy/state/lists/reducer.ts b/apps/cowswap-frontend/src/legacy/state/lists/reducer.ts index 26194307d5..e1a59f405c 100644 --- a/apps/cowswap-frontend/src/legacy/state/lists/reducer.ts +++ b/apps/cowswap-frontend/src/legacy/state/lists/reducer.ts @@ -1,16 +1,14 @@ -import { SupportedChainId as ChainId } from '@cowprotocol/cow-sdk' -import { getVersionUpgrade, TokenList, VersionUpgrade } from '@uniswap/token-lists' - -import { createReducer } from '@reduxjs/toolkit' - import { DEFAULT_ACTIVE_LIST_URLS_BY_NETWORK, DEFAULT_LIST_OF_LISTS_BY_NETWORK, DEFAULT_NETWORK_FOR_LISTS, UNSUPPORTED_LIST_URLS, -} from 'legacy/constants/lists' -import { updateVersion } from 'legacy/state/global/actions' -import { getChainIdValues } from 'legacy/utils/misc' +} from '@cowprotocol/common-const' +import { getChainIdValues } from '@cowprotocol/common-utils' +import { SupportedChainId as ChainId } from '@cowprotocol/cow-sdk' +import { getVersionUpgrade, TokenList, VersionUpgrade } from '@uniswap/token-lists' + +import { createReducer } from '@reduxjs/toolkit' import { UnsupportedToken } from 'api/gnosisProtocol' @@ -25,6 +23,8 @@ import { removeList, } from './actions' +import { updateVersion } from '../global/actions' + export interface ListsState { readonly byUrl: { readonly [url: string]: { diff --git a/apps/cowswap-frontend/src/legacy/state/lists/wrappedTokenInfo.ts b/apps/cowswap-frontend/src/legacy/state/lists/wrappedTokenInfo.ts index 6ca86f5fd9..3e446c5866 100644 --- a/apps/cowswap-frontend/src/legacy/state/lists/wrappedTokenInfo.ts +++ b/apps/cowswap-frontend/src/legacy/state/lists/wrappedTokenInfo.ts @@ -1,11 +1,11 @@ +import { isAddress } from '@cowprotocol/common-utils' import { Currency, Token } from '@uniswap/sdk-core' import { Tags, TokenInfo, TokenList } from '@uniswap/token-lists' -import { isAddress } from '../../utils' - type TagDetails = Tags[keyof Tags] export interface TagInfo extends TagDetails { id: string + icon?: string } /** * Token instances created from token info on a token list. diff --git a/apps/cowswap-frontend/src/legacy/state/logs/hooks.ts b/apps/cowswap-frontend/src/legacy/state/logs/hooks.ts index f73ebd1b6b..1719211d3b 100644 --- a/apps/cowswap-frontend/src/legacy/state/logs/hooks.ts +++ b/apps/cowswap-frontend/src/legacy/state/logs/hooks.ts @@ -1,11 +1,9 @@ import { useEffect, useMemo } from 'react' +import { useBlockNumber } from '@cowprotocol/common-hooks' +import { useWalletInfo } from '@cowprotocol/wallet' import { Filter } from '@ethersproject/providers' -import { useWalletInfo } from 'modules/wallet' - -import useBlockNumber from 'lib/hooks/useBlockNumber' - import { addListener, removeListener } from './slice' import { filterToKey, isHistoricalLog, Log } from './utils' diff --git a/apps/cowswap-frontend/src/legacy/state/multicall.tsx b/apps/cowswap-frontend/src/legacy/state/multicall.tsx new file mode 100644 index 0000000000..b4cb8342c2 --- /dev/null +++ b/apps/cowswap-frontend/src/legacy/state/multicall.tsx @@ -0,0 +1,13 @@ +import { useInterfaceMulticall, useBlockNumber } from '@cowprotocol/common-hooks' +import { createMulticall } from '@uniswap/redux-multicall' +import { useWeb3React } from '@web3-react/core' + +export const multicall = createMulticall() + +export function MulticallUpdater() { + const { chainId } = useWeb3React() + const latestBlockNumber = useBlockNumber() + const contract = useInterfaceMulticall() + + return +} diff --git a/apps/cowswap-frontend/src/legacy/state/orders/actions.ts b/apps/cowswap-frontend/src/legacy/state/orders/actions.ts index c9696db9b8..162055f7c8 100644 --- a/apps/cowswap-frontend/src/legacy/state/orders/actions.ts +++ b/apps/cowswap-frontend/src/legacy/state/orders/actions.ts @@ -5,10 +5,10 @@ import { Token } from '@uniswap/sdk-core' import { createAction } from '@reduxjs/toolkit' -import { SerializedToken } from 'legacy/state/user/types' - import { ComposableCowInfo } from 'common/types' +import { SerializedToken } from '../user/types' + export enum OrderStatus { PENDING = 'pending', PRESIGNATURE_PENDING = 'presignaturePending', @@ -59,6 +59,10 @@ export interface BaseOrder extends Omit { // Additional information from the order available in the API apiAdditionalInfo?: OrderInfoApi + // De-normalizing it as this is known at order placement time as `appData`, + // but when returned from the api is replaced with the `appDataHash` + // See this order response for example https://barn.api.cow.fi/goerli/api/v1/orders/0xc170856a42f38ba07a7af3ea8f299ea724ec0aa22445eb741cbad7f9dd4fcda05b0abe214ab7875562adee331deff0fe1912fe4265269bb1 + fullAppData?: EnrichedOrder['fullAppData'] // Wallet specific presignGnosisSafeTxHash?: string // Gnosis Safe tx diff --git a/apps/cowswap-frontend/src/legacy/state/orders/buildCancellationPopupSummary.tsx b/apps/cowswap-frontend/src/legacy/state/orders/buildCancellationPopupSummary.tsx index da99578d51..98ac575f44 100644 --- a/apps/cowswap-frontend/src/legacy/state/orders/buildCancellationPopupSummary.tsx +++ b/apps/cowswap-frontend/src/legacy/state/orders/buildCancellationPopupSummary.tsx @@ -1,9 +1,13 @@ -import styled from 'styled-components/macro' - -import { CancellationSummary } from 'modules/account/containers/Transaction/styled' +import { shortenOrderId } from '@cowprotocol/common-utils' -import { shortenOrderId } from '../../utils' +import styled from 'styled-components/macro' +const CancellationSummary = styled.span` + padding: 12px; + margin: 0; + border-radius: 6px; + background: ${({ theme }) => theme.bg1}; +` // Moved this function to separate file to avoid curcular deps const Wrapper = styled.div` diff --git a/apps/cowswap-frontend/src/modules/orders/utils/flatOrdersStateNetwork.ts b/apps/cowswap-frontend/src/legacy/state/orders/flatOrdersStateNetwork.ts similarity index 78% rename from apps/cowswap-frontend/src/modules/orders/utils/flatOrdersStateNetwork.ts rename to apps/cowswap-frontend/src/legacy/state/orders/flatOrdersStateNetwork.ts index 32de96257a..04cb870963 100644 --- a/apps/cowswap-frontend/src/modules/orders/utils/flatOrdersStateNetwork.ts +++ b/apps/cowswap-frontend/src/legacy/state/orders/flatOrdersStateNetwork.ts @@ -1,4 +1,4 @@ -import { OrdersStateNetwork, PartialOrdersMap } from 'legacy/state/orders/reducer' +import { OrdersStateNetwork, PartialOrdersMap } from './reducer' export function flatOrdersStateNetwork(state: OrdersStateNetwork): PartialOrdersMap { return { diff --git a/apps/cowswap-frontend/src/legacy/state/orders/helpers.tsx b/apps/cowswap-frontend/src/legacy/state/orders/helpers.tsx index 56e2a876f5..589541102e 100644 --- a/apps/cowswap-frontend/src/legacy/state/orders/helpers.tsx +++ b/apps/cowswap-frontend/src/legacy/state/orders/helpers.tsx @@ -1,4 +1,4 @@ -import { BlockExplorerLinkType, formatOrderId } from 'legacy/utils' +import { BlockExplorerLinkType, formatOrderId } from '@cowprotocol/common-utils' import { OrderStatus } from './actions' import { OrderObject, OrdersStateNetwork } from './reducer' diff --git a/apps/cowswap-frontend/src/legacy/state/orders/hooks.ts b/apps/cowswap-frontend/src/legacy/state/orders/hooks.ts index 93fa1f58fc..e31c65b69d 100644 --- a/apps/cowswap-frontend/src/legacy/state/orders/hooks.ts +++ b/apps/cowswap-frontend/src/legacy/state/orders/hooks.ts @@ -1,16 +1,10 @@ import { useCallback, useMemo } from 'react' +import { isTruthy } from '@cowprotocol/common-utils' import { OrderClass, SupportedChainId } from '@cowprotocol/cow-sdk' import { useDispatch, useSelector } from 'react-redux' -import { AppDispatch, AppState } from 'legacy/state' -import { isOrderExpired, partialOrderUpdate } from 'legacy/state/orders/utils' -import { deserializeToken, serializeToken } from 'legacy/state/user/hooks' -import { isTruthy } from 'legacy/utils/misc' - -import { flatOrdersStateNetwork } from 'modules/orders/utils/flatOrdersStateNetwork' - import { OrderID } from 'api/gnosisProtocol' import { @@ -35,6 +29,7 @@ import { UpdatePresignGnosisSafeTxParams, clearOrdersStorage, } from './actions' +import { flatOrdersStateNetwork } from './flatOrdersStateNetwork' import { getDefaultNetworkState, ORDER_LIST_KEYS, @@ -46,6 +41,10 @@ import { PartialOrdersMap, V2OrderObject, } from './reducer' +import { isOrderExpired, partialOrderUpdate } from './utils' + +import { AppDispatch, AppState } from '../index' +import { deserializeToken, serializeToken } from '../user/hooks' export interface AddOrUpdateUnserialisedOrdersParams extends Omit { orders: Order[] diff --git a/apps/cowswap-frontend/src/legacy/state/orders/middleware/appziMiddleware.test.ts b/apps/cowswap-frontend/src/legacy/state/orders/middleware/appziMiddleware.test.ts index 8e9c366034..d47f88132f 100644 --- a/apps/cowswap-frontend/src/legacy/state/orders/middleware/appziMiddleware.test.ts +++ b/apps/cowswap-frontend/src/legacy/state/orders/middleware/appziMiddleware.test.ts @@ -1,16 +1,15 @@ +import { isOrderInPendingTooLong, openNpsAppziSometimes } from '@cowprotocol/common-utils' import { OrderClass } from '@cowprotocol/cow-sdk' import { AnyAction, Dispatch, MiddlewareAPI } from 'redux' import { instance, mock, resetCalls, when } from 'ts-mockito' -import { isOrderInPendingTooLong, openNpsAppziSometimes } from 'legacy/utils/appzi' - import { appziMiddleware } from './appziMiddleware' import { AppState } from '../../index' import { getOrderByIdFromState } from '../helpers' -jest.mock('legacy/utils/appzi') +jest.mock('@cowprotocol/common-utils') jest.mock('../helpers', () => { return { ...jest.requireActual('../helpers'), diff --git a/apps/cowswap-frontend/src/legacy/state/orders/middleware/appziMiddleware.ts b/apps/cowswap-frontend/src/legacy/state/orders/middleware/appziMiddleware.ts index a073cd9e64..69a95df740 100644 --- a/apps/cowswap-frontend/src/legacy/state/orders/middleware/appziMiddleware.ts +++ b/apps/cowswap-frontend/src/legacy/state/orders/middleware/appziMiddleware.ts @@ -1,11 +1,14 @@ +import { + getExplorerOrderLink, + isOrderInPendingTooLong, + openNpsAppziSometimes, + timeSinceInSeconds, +} from '@cowprotocol/common-utils' import { OrderClass, SupportedChainId as ChainId } from '@cowprotocol/cow-sdk' import { isAnyOf } from '@reduxjs/toolkit' import { AnyAction, Dispatch, Middleware, MiddlewareAPI } from 'redux' -import { timeSinceInSeconds } from '../../../../utils/time' -import { isOrderInPendingTooLong, openNpsAppziSometimes } from '../../../utils/appzi' -import { getExplorerOrderLink } from '../../../utils/explorer' import { AppState } from '../../index' import * as OrderActions from '../actions' import { getOrderByIdFromState } from '../helpers' diff --git a/apps/cowswap-frontend/src/legacy/state/orders/middleware/batchCancelOrdersPopup.ts b/apps/cowswap-frontend/src/legacy/state/orders/middleware/batchCancelOrdersPopup.ts index 9686978e14..44f701cbec 100644 --- a/apps/cowswap-frontend/src/legacy/state/orders/middleware/batchCancelOrdersPopup.ts +++ b/apps/cowswap-frontend/src/legacy/state/orders/middleware/batchCancelOrdersPopup.ts @@ -1,6 +1,7 @@ +import { orderAnalytics } from '@cowprotocol/analytics' + import { Dispatch, MiddlewareAPI } from 'redux' -import { orderAnalytics } from '../../../components/analytics' import { addPopup, AddPopupPayload } from '../../application/reducer' import { AppState } from '../../index' import { BaseOrder } from '../actions' diff --git a/apps/cowswap-frontend/src/legacy/state/orders/middleware/batchExpireOrdersPopup.ts b/apps/cowswap-frontend/src/legacy/state/orders/middleware/batchExpireOrdersPopup.ts index 55ed23ab6c..ca49e806de 100644 --- a/apps/cowswap-frontend/src/legacy/state/orders/middleware/batchExpireOrdersPopup.ts +++ b/apps/cowswap-frontend/src/legacy/state/orders/middleware/batchExpireOrdersPopup.ts @@ -1,6 +1,7 @@ +import { orderAnalytics } from '@cowprotocol/analytics' + import { Dispatch, MiddlewareAPI } from 'redux' -import { orderAnalytics } from '../../../components/analytics' import { addPopup } from '../../application/reducer' import { AppState } from '../../index' import { ExpireOrdersBatchParams } from '../actions' diff --git a/apps/cowswap-frontend/src/legacy/state/orders/middleware/batchFulfillOrderPopup.tsx b/apps/cowswap-frontend/src/legacy/state/orders/middleware/batchFulfillOrderPopup.tsx index c9192cb58c..d57af681b8 100644 --- a/apps/cowswap-frontend/src/legacy/state/orders/middleware/batchFulfillOrderPopup.tsx +++ b/apps/cowswap-frontend/src/legacy/state/orders/middleware/batchFulfillOrderPopup.tsx @@ -1,8 +1,8 @@ +import { orderAnalytics } from '@cowprotocol/analytics' + import { MiddlewareAPI } from '@reduxjs/toolkit' import { Dispatch } from 'redux' -import { orderAnalytics } from 'legacy/components/analytics' - import { ExecutedSummary } from 'common/pure/ExecutedSummary' import { parseOrder } from 'utils/orderUtils/parseOrder' diff --git a/apps/cowswap-frontend/src/legacy/state/orders/middleware/batchPresignOrdersPopup.ts b/apps/cowswap-frontend/src/legacy/state/orders/middleware/batchPresignOrdersPopup.ts index b8c3bcb04c..5e9ccdc52c 100644 --- a/apps/cowswap-frontend/src/legacy/state/orders/middleware/batchPresignOrdersPopup.ts +++ b/apps/cowswap-frontend/src/legacy/state/orders/middleware/batchPresignOrdersPopup.ts @@ -1,6 +1,7 @@ +import { orderAnalytics } from '@cowprotocol/analytics' + import { Dispatch, MiddlewareAPI } from 'redux' -import { orderAnalytics } from '../../../components/analytics' import { addPopup } from '../../application/reducer' import { AppState } from '../../index' import { PresignedOrdersParams } from '../actions' diff --git a/apps/cowswap-frontend/src/legacy/state/orders/middleware/index.ts b/apps/cowswap-frontend/src/legacy/state/orders/middleware/index.ts index 6c4190f6f5..e4e8161399 100644 --- a/apps/cowswap-frontend/src/legacy/state/orders/middleware/index.ts +++ b/apps/cowswap-frontend/src/legacy/state/orders/middleware/index.ts @@ -1,4 +1,3 @@ export { popupMiddleware } from './popupMiddleware' export { soundMiddleware } from './soundMiddleware' export { appziMiddleware } from './appziMiddleware' -export { composableOrdersPopupMiddleware } from './composableOrdersPopupMiddleware' diff --git a/apps/cowswap-frontend/src/legacy/state/orders/middleware/pendingOrderPopup.ts b/apps/cowswap-frontend/src/legacy/state/orders/middleware/pendingOrderPopup.ts index 208c437c45..10e801ef6d 100644 --- a/apps/cowswap-frontend/src/legacy/state/orders/middleware/pendingOrderPopup.ts +++ b/apps/cowswap-frontend/src/legacy/state/orders/middleware/pendingOrderPopup.ts @@ -1,7 +1,8 @@ +import { orderAnalytics } from '@cowprotocol/analytics' + import { MiddlewareAPI } from '@reduxjs/toolkit' import { Dispatch } from 'redux' -import { orderAnalytics } from '../../../components/analytics' import { addPopup, AddPopupPayload } from '../../application/reducer' import { AppState } from '../../index' import { AddPendingOrderParams } from '../actions' diff --git a/apps/cowswap-frontend/src/legacy/state/orders/middleware/popupMiddleware.ts b/apps/cowswap-frontend/src/legacy/state/orders/middleware/popupMiddleware.ts index b90d059b41..c007d14c4d 100644 --- a/apps/cowswap-frontend/src/legacy/state/orders/middleware/popupMiddleware.ts +++ b/apps/cowswap-frontend/src/legacy/state/orders/middleware/popupMiddleware.ts @@ -1,8 +1,8 @@ +import { isTruthy } from '@cowprotocol/common-utils' + import { isAnyOf } from '@reduxjs/toolkit' import { Middleware } from 'redux' -import { isTruthy } from 'legacy/utils/misc' - import { batchCancelOrdersPopup } from './batchCancelOrdersPopup' import { batchExpireOrdersPopup } from './batchExpireOrdersPopup' import { batchFulfillOrderPopup } from './batchFulfillOrderPopup' diff --git a/apps/cowswap-frontend/src/legacy/state/orders/middleware/soundMiddleware.test.ts b/apps/cowswap-frontend/src/legacy/state/orders/middleware/soundMiddleware.test.ts index 87a094ec6e..76ba9c1439 100644 --- a/apps/cowswap-frontend/src/legacy/state/orders/middleware/soundMiddleware.test.ts +++ b/apps/cowswap-frontend/src/legacy/state/orders/middleware/soundMiddleware.test.ts @@ -1,8 +1,8 @@ +import { getCowSoundError, getCowSoundSend, getCowSoundSuccess } from '@cowprotocol/common-utils' + import { AnyAction, Dispatch, MiddlewareAPI } from 'redux' import { instance, mock, resetCalls, when } from 'ts-mockito' -import { getCowSoundError, getCowSoundSend, getCowSoundSuccess } from 'legacy/utils/sound' - import { soundMiddleware } from './soundMiddleware' import { AppState } from '../../index' @@ -11,7 +11,7 @@ const mockStore = mock>() const nextMock = jest.fn() const actionMock = mock() -jest.mock('legacy/utils/sound') +jest.mock('@cowprotocol/common-utils') describe('soundMiddleware', () => { beforeEach(() => { diff --git a/apps/cowswap-frontend/src/legacy/state/orders/middleware/soundMiddleware.ts b/apps/cowswap-frontend/src/legacy/state/orders/middleware/soundMiddleware.ts index 5a80d95192..23eb9683de 100644 --- a/apps/cowswap-frontend/src/legacy/state/orders/middleware/soundMiddleware.ts +++ b/apps/cowswap-frontend/src/legacy/state/orders/middleware/soundMiddleware.ts @@ -1,8 +1,9 @@ // On each Pending, Expired, Fulfilled order action a corresponding sound is dispatched +import { getCowSoundError, getCowSoundSend, getCowSoundSuccess } from '@cowprotocol/common-utils' + import { isAnyOf } from '@reduxjs/toolkit' import { AnyAction, Dispatch, Middleware, MiddlewareAPI } from 'redux' -import { getCowSoundError, getCowSoundSend, getCowSoundSuccess } from '../../../utils/sound' import { addPopup } from '../../application/reducer' import { AppState } from '../../index' import { AddPendingOrderParams, BatchOrdersUpdateParams, UpdateOrderParams } from '../actions' diff --git a/apps/cowswap-frontend/src/legacy/state/orders/middleware/updateOrderPopup.ts b/apps/cowswap-frontend/src/legacy/state/orders/middleware/updateOrderPopup.ts index ec774ddeb2..8d86c9828f 100644 --- a/apps/cowswap-frontend/src/legacy/state/orders/middleware/updateOrderPopup.ts +++ b/apps/cowswap-frontend/src/legacy/state/orders/middleware/updateOrderPopup.ts @@ -1,11 +1,10 @@ +import { orderAnalytics } from '@cowprotocol/analytics' +import { BlockExplorerLinkType } from '@cowprotocol/common-utils' import { OrderClass } from '@cowprotocol/cow-sdk' import { MiddlewareAPI } from '@reduxjs/toolkit' import { Dispatch } from 'redux' -import { BlockExplorerLinkType } from 'legacy/utils' - -import { orderAnalytics } from '../../../components/analytics' import { addPopup } from '../../application/reducer' import { AppState } from '../../index' import { UpdateOrderParams } from '../actions' diff --git a/apps/cowswap-frontend/src/legacy/state/orders/mocks.ts b/apps/cowswap-frontend/src/legacy/state/orders/mocks.ts index 53bfe946f0..229a3b7894 100644 --- a/apps/cowswap-frontend/src/legacy/state/orders/mocks.ts +++ b/apps/cowswap-frontend/src/legacy/state/orders/mocks.ts @@ -1,12 +1,12 @@ +import { RADIX_DECIMAL } from '@cowprotocol/common-const' import { OrderClass, OrderKind } from '@cowprotocol/cow-sdk' import { Token } from '@uniswap/sdk-core' -import { RADIX_DECIMAL } from 'legacy/constants' -import store from 'legacy/state' -import { serializeToken } from 'legacy/state/user/hooks' - import { Order, OrderStatus, SerializedOrder, addPendingOrder, AddPendingOrderParams } from './actions' +import { cowSwapStore } from '../index' +import { serializeToken } from '../user/hooks' + const randomNumberInRange = (min: number, max: number) => { return Math.random() * (max - min) + min } @@ -122,6 +122,6 @@ export const mockOrderDispatches = { }, } - store.dispatch(addPendingOrder(actionParams)) + cowSwapStore.dispatch(addPendingOrder(actionParams)) }, } diff --git a/apps/cowswap-frontend/src/legacy/state/orders/priceUtils.ts b/apps/cowswap-frontend/src/legacy/state/orders/priceUtils.ts index 4c06b8fca2..4c01fee136 100644 --- a/apps/cowswap-frontend/src/legacy/state/orders/priceUtils.ts +++ b/apps/cowswap-frontend/src/legacy/state/orders/priceUtils.ts @@ -1,8 +1,8 @@ // Copied from @cowprotocol/cow-js -import { BigNumber } from 'bignumber.js' +import { DEFAULT_DECIMALS } from '@cowprotocol/common-const' -import { DEFAULT_DECIMALS } from 'legacy/constants' +import { BigNumber } from 'bignumber.js' interface PriceTokenInfo { amount: BigNumber | string diff --git a/apps/cowswap-frontend/src/legacy/state/orders/reducer.ts b/apps/cowswap-frontend/src/legacy/state/orders/reducer.ts index ad959f0526..26d7908258 100644 --- a/apps/cowswap-frontend/src/legacy/state/orders/reducer.ts +++ b/apps/cowswap-frontend/src/legacy/state/orders/reducer.ts @@ -3,8 +3,6 @@ import { SupportedChainId as ChainId } from '@cowprotocol/cow-sdk' import { createReducer, PayloadAction } from '@reduxjs/toolkit' import { Writable } from 'types' -import { flatOrdersStateNetwork } from 'modules/orders/utils/flatOrdersStateNetwork' - import { OrderID } from 'api/gnosisProtocol' import { getIsComposableCowDiscreteOrder } from 'utils/orderUtils/getIsComposableCowDiscreteOrder' import { getIsComposableCowParentOrder } from 'utils/orderUtils/getIsComposableCowParentOrder' @@ -35,6 +33,7 @@ import { CONFIRMED_STATES, } from './actions' import { ContractDeploymentBlocks, MAX_ITEMS_PER_STATUS } from './consts' +import { flatOrdersStateNetwork } from './flatOrdersStateNetwork' export interface OrderObject { id: OrderID diff --git a/apps/cowswap-frontend/src/legacy/state/orders/utils.test.ts b/apps/cowswap-frontend/src/legacy/state/orders/utils.test.ts index f2335c134d..9cef5fc005 100644 --- a/apps/cowswap-frontend/src/legacy/state/orders/utils.test.ts +++ b/apps/cowswap-frontend/src/legacy/state/orders/utils.test.ts @@ -1,10 +1,9 @@ +import { USDC_MAINNET as USDC, USDT } from '@cowprotocol/common-const' import { OrderKind, OrderStatus, SigningScheme } from '@cowprotocol/cow-sdk' import { Price } from '@uniswap/sdk-core' import ms from 'ms.macro' -import { USDC_MAINNET as USDC, USDT } from 'legacy/constants/tokens' - import { generateOrder } from './mocks' import { classifyOrder, getOrderMarketPrice, isOrderUnfillable } from './utils' diff --git a/apps/cowswap-frontend/src/legacy/state/orders/utils.ts b/apps/cowswap-frontend/src/legacy/state/orders/utils.ts index 7c0fde7b4a..3461931b06 100644 --- a/apps/cowswap-frontend/src/legacy/state/orders/utils.ts +++ b/apps/cowswap-frontend/src/legacy/state/orders/utils.ts @@ -1,21 +1,20 @@ +import { ONE_HUNDRED_PERCENT, PENDING_ORDERS_BUFFER, ZERO_FRACTION } from '@cowprotocol/common-const' +import { buildPriceFromCurrencyAmounts } from '@cowprotocol/common-utils' import { EnrichedOrder, OrderClass, OrderKind, OrderStatus } from '@cowprotocol/cow-sdk' import { Currency, CurrencyAmount, Price } from '@uniswap/sdk-core' import JSBI from 'jsbi' -import { PENDING_ORDERS_BUFFER, ZERO_FRACTION } from 'legacy/constants' -import { ONE_HUNDRED_PERCENT } from 'legacy/constants/misc' -import { AppDispatch } from 'legacy/state' -import { Order, updateOrder, UpdateOrderParams as UpdateOrderParamsAction } from 'legacy/state/orders/actions' -import { OUT_OF_MARKET_PRICE_DELTA_PERCENTAGE } from 'legacy/state/orders/consts' -import { UpdateOrderParams } from 'legacy/state/orders/hooks' -import { serializeToken } from 'legacy/state/user/hooks' - -import { buildPriceFromCurrencyAmounts } from 'modules/utils/orderUtils/buildPriceFromCurrencyAmounts' - import { getIsComposableCowParentOrder } from 'utils/orderUtils/getIsComposableCowParentOrder' import { getOrderSurplus } from 'utils/orderUtils/getOrderSurplus' +import { Order, updateOrder, UpdateOrderParams as UpdateOrderParamsAction } from './actions' +import { OUT_OF_MARKET_PRICE_DELTA_PERCENTAGE } from './consts' +import { UpdateOrderParams } from './hooks' + +import { AppDispatch } from '../index' +import { serializeToken } from '../user/hooks' + export type OrderTransitionStatus = | 'unknown' | 'fulfilled' diff --git a/apps/cowswap-frontend/src/legacy/state/price/actions.ts b/apps/cowswap-frontend/src/legacy/state/price/actions.ts index 0d4d8bfe8e..10457c4fcf 100644 --- a/apps/cowswap-frontend/src/legacy/state/price/actions.ts +++ b/apps/cowswap-frontend/src/legacy/state/price/actions.ts @@ -2,9 +2,8 @@ import { SupportedChainId as ChainId } from '@cowprotocol/cow-sdk' import { createAction } from '@reduxjs/toolkit' -import { LegacyFeeQuoteParams } from 'api/gnosisProtocol/legacy/types' - import { QuoteInformationObject } from './reducer' +import { LegacyFeeQuoteParams } from './types' export type UpdateQuoteParams = Omit diff --git a/apps/cowswap-frontend/src/legacy/state/price/hooks.ts b/apps/cowswap-frontend/src/legacy/state/price/hooks.ts index f8b611598c..798c0e7bd9 100644 --- a/apps/cowswap-frontend/src/legacy/state/price/hooks.ts +++ b/apps/cowswap-frontend/src/legacy/state/price/hooks.ts @@ -4,11 +4,6 @@ import { SupportedChainId as ChainId } from '@cowprotocol/cow-sdk' import { useDispatch, useSelector } from 'react-redux' -import { AppDispatch, AppState } from 'legacy/state' -import { useSwapState } from 'legacy/state/swap/hooks' - -import { useWalletInfo } from 'modules/wallet' - import { updateQuote, UpdateQuoteParams, @@ -22,6 +17,8 @@ import { } from './actions' import { QuoteInformationObject, QuotesMap } from './reducer' +import { AppDispatch, AppState } from '../index' + type GetNewQuoteCallback = (params: GetQuoteParams) => void type RefreshQuoteCallback = (params: RefreshQuoteParams) => void type AddPriceCallback = (params: UpdateQuoteParams) => void @@ -77,16 +74,6 @@ export const useGetQuoteAndStatus = (params: QuoteParams): UseGetQuoteAndStatus return { quote, isGettingNewQuote, isRefreshingQuote } } -// syntactic sugar for not needing to pass swapstate -export function useIsQuoteRefreshing() { - const { chainId } = useWalletInfo() - const { - INPUT: { currencyId }, - } = useSwapState() - const { isRefreshingQuote } = useGetQuoteAndStatus({ token: currencyId, chainId }) - return isRefreshingQuote -} - export const useGetNewQuote = (): GetNewQuoteCallback => { const dispatch = useDispatch() return useCallback((params: GetQuoteParams) => dispatch(getNewQuote(params)), [dispatch]) diff --git a/apps/cowswap-frontend/src/legacy/state/price/middleware.ts b/apps/cowswap-frontend/src/legacy/state/price/middleware.ts index 7632c2ba63..43cc24900d 100644 --- a/apps/cowswap-frontend/src/legacy/state/price/middleware.ts +++ b/apps/cowswap-frontend/src/legacy/state/price/middleware.ts @@ -1,10 +1,11 @@ -import { Middleware, isAnyOf } from '@reduxjs/toolkit' +import { initialPriceLoadAnalytics } from '@cowprotocol/analytics' -import { initialPriceLoadAnalytics } from 'legacy/components/analytics' -import { AppState } from 'legacy/state' +import { Middleware, isAnyOf } from '@reduxjs/toolkit' import * as PriceActions from './actions' +import { AppState } from '../index' + const isUpdateQuoteAction = isAnyOf(PriceActions.updateQuote) export const priceMiddleware: Middleware, AppState> = (store) => (next) => (action) => { diff --git a/apps/cowswap-frontend/src/legacy/state/price/reducer.ts b/apps/cowswap-frontend/src/legacy/state/price/reducer.ts index 73f9c2bf8b..1751d9522c 100644 --- a/apps/cowswap-frontend/src/legacy/state/price/reducer.ts +++ b/apps/cowswap-frontend/src/legacy/state/price/reducer.ts @@ -4,16 +4,17 @@ import { OrderKind } from '@cowprotocol/cow-sdk' import { createReducer, PayloadAction, current } from '@reduxjs/toolkit' import { FeeInformation, PriceInformation } from 'types' -import { Writable } from 'legacy/types' - -import { LegacyFeeQuoteParams } from 'api/gnosisProtocol/legacy/types' - import { updateQuote, setQuoteError, getNewQuote, refreshQuote, QuoteError } from './actions' +import { LegacyFeeQuoteParams } from './types' import { PrefillStateRequired } from '../orders/reducer' // API Doc: https://protocol-rinkeby.dev.gnosisdev.com/api +type Writable = { + -readonly [K in keyof T]: T[K] +} + export const EMPTY_FEE = { feeAsCurrency: undefined, amount: '0', diff --git a/apps/cowswap-frontend/src/api/gnosisProtocol/legacy/types.ts b/apps/cowswap-frontend/src/legacy/state/price/types.ts similarity index 77% rename from apps/cowswap-frontend/src/api/gnosisProtocol/legacy/types.ts rename to apps/cowswap-frontend/src/legacy/state/price/types.ts index 59f74cd80c..49094cc816 100644 --- a/apps/cowswap-frontend/src/api/gnosisProtocol/legacy/types.ts +++ b/apps/cowswap-frontend/src/legacy/state/price/types.ts @@ -1,9 +1,17 @@ -import { SupportedChainId as ChainId, PriceQuality } from '@cowprotocol/cow-sdk' -import { EnrichedOrder } from '@cowprotocol/cow-sdk' +import { AppData, AppDataHash, EnrichedOrder, PriceQuality, SupportedChainId as ChainId } from '@cowprotocol/cow-sdk' -import { FeeInformation, PriceInformation } from 'types' +type GpPriceStrategy = 'COWSWAP' | 'LEGACY' -import { GpPriceStrategy } from 'legacy/state/gas/atoms' +interface PriceInformation { + token: string + amount: string | null + quoteId?: number +} + +export interface FeeInformation { + expirationDate: string + amount: string +} interface FeeQuoteParams extends Pick { amount: string @@ -38,6 +46,8 @@ export interface LegacyFeeQuoteParams extends FeeQuoteParams { priceQuality: PriceQuality isBestQuote?: boolean isEthFlow: boolean + appData?: AppData + appDataHash?: AppDataHash } export type LegacyPriceQuoteParams = Omit & { diff --git a/apps/cowswap-frontend/src/legacy/state/profile/hooks.tsx b/apps/cowswap-frontend/src/legacy/state/profile/hooks.tsx index 07704d829e..c8d83b3c2b 100644 --- a/apps/cowswap-frontend/src/legacy/state/profile/hooks.tsx +++ b/apps/cowswap-frontend/src/legacy/state/profile/hooks.tsx @@ -1,9 +1,9 @@ import { useCallback } from 'react' -import { useAppDispatch, useAppSelector } from 'legacy/state/hooks' - import { closeAnnouncement } from './actions' +import { useAppDispatch, useAppSelector } from '../hooks' + export function useAnnouncementVisible(contentHash?: string): boolean { const announcementVisible = useAppSelector((state) => state.profile.announcementVisible) diff --git a/apps/cowswap-frontend/src/legacy/state/swap/TradeGp.ts b/apps/cowswap-frontend/src/legacy/state/swap/TradeGp.ts index 66ea956c4d..d98caa57cd 100644 --- a/apps/cowswap-frontend/src/legacy/state/swap/TradeGp.ts +++ b/apps/cowswap-frontend/src/legacy/state/swap/TradeGp.ts @@ -1,9 +1,17 @@ -import { CurrencyAmount, Currency, TradeType, Price, Percent } from '@uniswap/sdk-core' +import { ONE_FRACTION } from '@cowprotocol/common-const' +import { CanonicalMarketParams, getCanonicalMarket } from '@cowprotocol/common-utils' +import { Currency, CurrencyAmount, Percent, Price, TradeType } from '@uniswap/sdk-core' -import { FeeInformation, PriceInformation } from 'types' +interface PriceInformation { + token: string + amount: string | null + quoteId?: number +} -import { ONE_FRACTION } from 'legacy/constants/misc' -import { CanonicalMarketParams, getCanonicalMarket } from 'legacy/utils/misc' +interface FeeInformation { + expirationDate: string + amount: string +} export type FeeForTrade = { feeAsCurrency: CurrencyAmount } & Pick @@ -86,7 +94,7 @@ export default class TradeGp { * The output amount for the trade assuming no slippage. */ readonly outputAmount: CurrencyAmount - readonly outputAmountWithoutFee?: CurrencyAmount + readonly outputAmountWithoutFee: CurrencyAmount /** * Trade fee */ diff --git a/apps/cowswap-frontend/src/legacy/state/swap/actions.ts b/apps/cowswap-frontend/src/legacy/state/swap/actions.ts index 200de24486..8c0b06d0c9 100644 --- a/apps/cowswap-frontend/src/legacy/state/swap/actions.ts +++ b/apps/cowswap-frontend/src/legacy/state/swap/actions.ts @@ -1,9 +1,6 @@ import { createAction } from '@reduxjs/toolkit' -export enum Field { - INPUT = 'INPUT', - OUTPUT = 'OUTPUT', -} +import { Field } from '../types' export interface ReplaceOnlyTradeRawStatePayload { readonly chainId: number | null diff --git a/apps/cowswap-frontend/src/legacy/state/swap/extension.ts b/apps/cowswap-frontend/src/legacy/state/swap/extension.ts index d6cfdf4f0b..15d82fc17d 100644 --- a/apps/cowswap-frontend/src/legacy/state/swap/extension.ts +++ b/apps/cowswap-frontend/src/legacy/state/swap/extension.ts @@ -3,10 +3,10 @@ import { Currency, CurrencyAmount, TradeType } from '@uniswap/sdk-core' import JSBI from 'jsbi' -import { QuoteInformationObject } from 'legacy/state/price/reducer' - import TradeGp, { _constructTradePrice } from './TradeGp' +import { QuoteInformationObject } from '../price/reducer' + interface TradeParams { parsedAmount?: CurrencyAmount inputCurrency?: Currency | null diff --git a/apps/cowswap-frontend/src/legacy/state/swap/reducer.ts b/apps/cowswap-frontend/src/legacy/state/swap/reducer.ts index 994ea43f08..6b7b0fe0a7 100644 --- a/apps/cowswap-frontend/src/legacy/state/swap/reducer.ts +++ b/apps/cowswap-frontend/src/legacy/state/swap/reducer.ts @@ -1,12 +1,11 @@ +import { NATIVE_CURRENCY_BUY_TOKEN, WRAPPED_NATIVE_CURRENCY } from '@cowprotocol/common-const' +import { parsedQueryString } from '@cowprotocol/common-hooks' +import { getIsNativeToken, getIsWrapOrUnwrap } from '@cowprotocol/common-utils' import { SupportedChainId as ChainId } from '@cowprotocol/cow-sdk' import { createReducer } from '@reduxjs/toolkit' -import { NATIVE_CURRENCY_BUY_TOKEN } from 'legacy/constants' -import { WRAPPED_NATIVE_CURRENCY } from 'legacy/constants/tokens' -import { parsedQueryString } from 'legacy/hooks/useParsedQueryString' import { - Field, replaceOnlyTradeRawState, replaceSwapState, selectCurrency, @@ -14,13 +13,11 @@ import { setRecipientAddress, switchCurrencies, typeInput, -} from 'legacy/state/swap/actions' - -import { getIsNativeToken } from 'utils/getIsNativeToken' -import { getIsWrapOrUnwrap } from 'utils/getIsWrapOrUnwrap' - +} from './actions' import { queryParametersToSwapState } from './utils' +import { Field } from '../types' + export interface SwapState { // Mod: added chainId chainId: number | null diff --git a/apps/cowswap-frontend/src/legacy/state/swap/trade.test.ts b/apps/cowswap-frontend/src/legacy/state/swap/trade.test.ts index 2e1e27ef02..e0209d8d12 100644 --- a/apps/cowswap-frontend/src/legacy/state/swap/trade.test.ts +++ b/apps/cowswap-frontend/src/legacy/state/swap/trade.test.ts @@ -1,11 +1,9 @@ +import { DEFAULT_PRECISION, LONG_PRECISION, WRAPPED_NATIVE_CURRENCY as WETH } from '@cowprotocol/common-const' import { OrderKind } from '@cowprotocol/cow-sdk' import { SupportedChainId as ChainId } from '@cowprotocol/cow-sdk' import { parseUnits } from '@ethersproject/units' import { CurrencyAmount, Fraction, Price, Currency, Percent, Token, TradeType } from '@uniswap/sdk-core' -import { DEFAULT_PRECISION, LONG_PRECISION } from 'legacy/constants' -import { WRAPPED_NATIVE_CURRENCY as WETH } from 'legacy/constants/tokens' - import { stringToCurrency } from './extension' import Trade, { _constructTradePrice } from './TradeGp' import TradeGp from './TradeGp' diff --git a/apps/cowswap-frontend/src/legacy/state/swap/utils.ts b/apps/cowswap-frontend/src/legacy/state/swap/utils.ts index 503ecd6f26..43bdd3004b 100644 --- a/apps/cowswap-frontend/src/legacy/state/swap/utils.ts +++ b/apps/cowswap-frontend/src/legacy/state/swap/utils.ts @@ -1,14 +1,14 @@ +import { TOKEN_SHORTHANDS, WRAPPED_NATIVE_CURRENCY } from '@cowprotocol/common-const' +import { isAddress } from '@cowprotocol/common-utils' import { SupportedChainId } from '@cowprotocol/cow-sdk' import { Currency } from '@uniswap/sdk-core' import { ParsedQs } from 'qs' -import { TOKEN_SHORTHANDS, WRAPPED_NATIVE_CURRENCY } from 'legacy/constants/tokens' -import { isAddress } from 'legacy/utils' - -import { Field } from './actions' import { SwapState } from './reducer' +import { Field } from '../types' + export function isWrappingTrade( sellCurrency: Currency | null | undefined, buyCurrency: Currency | null | undefined, diff --git a/apps/cowswap-frontend/src/legacy/components/TransactionConfirmationModal/types.ts b/apps/cowswap-frontend/src/legacy/state/types.ts similarity index 73% rename from apps/cowswap-frontend/src/legacy/components/TransactionConfirmationModal/types.ts rename to apps/cowswap-frontend/src/legacy/state/types.ts index 3b873c4d6c..a9dc73eaa8 100644 --- a/apps/cowswap-frontend/src/legacy/components/TransactionConfirmationModal/types.ts +++ b/apps/cowswap-frontend/src/legacy/state/types.ts @@ -8,3 +8,8 @@ export enum ConfirmOperationType { CONVERT_VCOW, CLAIM_VESTED_COW, } + +export enum Field { + INPUT = 'INPUT', + OUTPUT = 'OUTPUT', +} diff --git a/apps/cowswap-frontend/src/legacy/state/user/hooks.tsx b/apps/cowswap-frontend/src/legacy/state/user/hooks.tsx index b6a85b8eb2..d4a328ff5a 100644 --- a/apps/cowswap-frontend/src/legacy/state/user/hooks.tsx +++ b/apps/cowswap-frontend/src/legacy/state/user/hooks.tsx @@ -1,20 +1,13 @@ import { useCallback, useMemo } from 'react' +import { L2_DEADLINE_FROM_NOW, NATIVE_CURRENCY_BUY_TOKEN, SupportedLocale } from '@cowprotocol/common-const' +import { calculateValidTo } from '@cowprotocol/common-utils' +import { useWalletInfo } from '@cowprotocol/wallet' import { Currency, Percent, Token } from '@uniswap/sdk-core' import JSBI from 'jsbi' import { shallowEqual } from 'react-redux' -import { NATIVE_CURRENCY_BUY_TOKEN } from 'legacy/constants' -import { SupportedLocale } from 'legacy/constants/locales' -import { L2_DEADLINE_FROM_NOW } from 'legacy/constants/misc' -import { AppState } from 'legacy/state' -import { useAppDispatch, useAppSelector } from 'legacy/state/hooks' - -import { useWalletInfo } from 'modules/wallet' - -import { calculateValidTo } from 'utils/time' - import { addSerializedToken, initFavouriteTokens, @@ -30,7 +23,9 @@ import { } from './reducer' import { SerializedToken } from './types' -import { useSwapActionHandlers } from '../swap/hooks' +import { useAppDispatch, useAppSelector } from '../hooks' +import { AppState } from '../index' +import { setRecipient } from '../swap/actions' export function deserializeToken(serializedToken: SerializedToken): Token { return new Token( @@ -107,7 +102,12 @@ export function useIsRecipientToggleVisible(): boolean { export function useRecipientToggleManager(): [boolean, (value?: boolean) => void] { const dispatch = useAppDispatch() const isVisible = useIsRecipientToggleVisible() - const { onChangeRecipient } = useSwapActionHandlers() + const onChangeRecipient = useCallback( + (recipient: string | null) => { + dispatch(setRecipient({ recipient })) + }, + [dispatch] + ) const toggleVisibility = useCallback( (value?: boolean) => { diff --git a/apps/cowswap-frontend/src/legacy/state/user/reducer.ts b/apps/cowswap-frontend/src/legacy/state/user/reducer.ts index a9d8b4f11d..428a2f6d38 100644 --- a/apps/cowswap-frontend/src/legacy/state/user/reducer.ts +++ b/apps/cowswap-frontend/src/legacy/state/user/reducer.ts @@ -1,15 +1,13 @@ +import { COMMON_BASES, DEFAULT_DEADLINE_FROM_NOW, SupportedLocale } from '@cowprotocol/common-const' import { SupportedChainId } from '@cowprotocol/cow-sdk' +import { ConnectionType } from '@cowprotocol/wallet' import { Token } from '@uniswap/sdk-core' import { createSlice } from '@reduxjs/toolkit' -import { SupportedLocale } from 'legacy/constants/locales' -import { DEFAULT_DEADLINE_FROM_NOW } from 'legacy/constants/misc' -import { COMMON_BASES } from 'legacy/constants/routing' -import { updateVersion } from 'legacy/state/global/actions' -import { SerializedPair, SerializedToken } from 'legacy/state/user/types' +import { SerializedPair, SerializedToken } from './types' -import { ConnectionType } from 'modules/wallet' +import { updateVersion } from '../global/actions' // MOD imports // import { serializeToken } from './hooks' diff --git a/apps/cowswap-frontend/src/legacy/theme/baseTheme.tsx b/apps/cowswap-frontend/src/legacy/theme/baseTheme.tsx index 546a74ea30..a7b9aff9c3 100644 --- a/apps/cowswap-frontend/src/legacy/theme/baseTheme.tsx +++ b/apps/cowswap-frontend/src/legacy/theme/baseTheme.tsx @@ -1,14 +1,17 @@ +import Cursor1 from '@cowprotocol/assets/cow-swap/cursor1.gif' +import Cursor2 from '@cowprotocol/assets/cow-swap/cursor2.gif' +import Cursor3 from '@cowprotocol/assets/cow-swap/cursor3.gif' +import Cursor4 from '@cowprotocol/assets/cow-swap/cursor4.gif' +import { ButtonSize } from '@cowprotocol/ui' + import { transparentize, lighten, darken } from 'polished' import { createGlobalStyle, css } from 'styled-components/macro' -import Cursor1 from 'legacy/assets/cow-swap/cursor1.gif' -import Cursor2 from 'legacy/assets/cow-swap/cursor2.gif' -import Cursor3 from 'legacy/assets/cow-swap/cursor3.gif' -import Cursor4 from 'legacy/assets/cow-swap/cursor4.gif' import { colorsUniswap } from 'legacy/theme/colorsUniswap' -import { ButtonSize } from 'legacy/theme/enum' import { Colors } from 'legacy/theme/styled' +import { UI } from 'common/constants/theme' + // TODO: This shouldn't be in the base theme // Modal override items // import { HeaderText } from 'legacy/components/WalletModal/Option' @@ -387,45 +390,89 @@ export const UniFixedGlobalStyle = css` export const UniThemedGlobalStyle = css` :root { - // CSS Variables =============================== - // Colors - --cow-color-white: ${({ theme }) => theme.white}; - --cow-color-blue: ${({ theme }) => theme.blueDark2}; - --cow-color-border: ${({ theme }) => theme.grey1}; - --cow-color-lightBlue: ${({ theme }) => theme.information}; - --cow-color-lightBlue-opacity-90: ${({ theme }) => transparentize(0.1, theme.information)}; // 90% opacity - --cow-color-lightBlue-opacity-80: ${({ theme }) => transparentize(0.2, theme.information)}; // 80% opacity - --cow-color-yellow: ${({ theme }) => theme.alert}; - --cow-color-yellow-light: ${({ theme }) => theme.alert2}; - --cow-color-green: ${({ theme }) => theme.success}; - - // States - --cow-color-information: var(--cow-color-lightBlue); - --cow-color-information-bg: ${({ theme }) => (theme.darkMode ? transparentize(0.9, theme.information) : transparentize(0.85, theme.information))}; - --cow-color-information-text: ${({ theme }) => (theme.darkMode ? lighten(0.2, theme.information) : darken(0.2, theme.information))}; - - --cow-color-alert: var(--cow-color-yellow); - --cow-color-alert-bg: ${({ theme }) => (theme.darkMode ? transparentize(0.9, theme.alert) : transparentize(0.85, theme.alert))}; - --cow-color-alert-text: ${({ theme }) => (theme.darkMode ? lighten(0.2, theme.alert) : darken(0.2, theme.alert))}; - - --cow-color-alert2: var(--cow-color-yellow-light); - --cow-color-alert2-bg: var(--cow-color-alert2); - --cow-color-alert2-text: var(--cow-color-blue); - - --cow-color-success: var(--cow-color-green); - --cow-color-success-bg: ${({ theme }) => (theme.darkMode ? transparentize(0.9, theme.success) : transparentize(0.85, theme.success))}; - --cow-color-success-text: ${({ theme }) => (theme.darkMode ? lighten(0.2, theme.success) : darken(0.1, theme.success))}; + ${UI.COLOR_WHITE}: ${({ theme }) => theme.white}; + ${UI.COLOR_BLUE}: ${({ theme }) => theme.blueDark2}; + ${UI.COLOR_GREY}: ${({ theme }) => theme.grey1}; + ${UI.COLOR_LIGHT_BLUE}: ${({ theme }) => theme.blueLight1}; + ${UI.COLOR_LIGHT_BLUE_OPACITY_90}: ${({ theme }) => theme.information}; + ${UI.COLOR_LIGHT_BLUE_OPACITY_80}: ${({ theme }) => transparentize(0.2, theme.information)}; // 80% opacity + ${UI.COLOR_YELLOW}: ${({ theme }) => theme.alert}; + ${UI.COLOR_YELLOW_LIGHT}: ${({ theme }) => theme.alert2}; + ${UI.COLOR_GREEN}: ${({ theme }) => theme.success}; + ${UI.COLOR_RED}: ${({ theme }) => theme.danger}; + + // Base + ${UI.COLOR_BORDER}: var(${UI.COLOR_GREY}); + ${UI.COLOR_CONTAINER_BG_01}: ${({ theme }) => theme.bg1}; + ${UI.COLOR_CONTAINER_BG_02}: ${({ theme }) => theme.bg2}; + ${UI.MODAL_BACKDROP}: var(${UI.COLOR_TEXT1}); + ${UI.BORDER_RADIUS_NORMAL}: 24px; + ${UI.PADDING_NORMAL}: 24px; + ${UI.BOX_SHADOW_NORMAL}: 0 1.5rem 1rem #00000008,0 .75rem .75rem #0000000a,0 .25rem .375rem #0000000d; + + // Icons + ${UI.ICON_SIZE_NORMAL}: 24px; + ${UI.ICON_SIZE_LARGE}: 36px; + ${UI.ICON_COLOR_NORMAL}: var(${UI.COLOR_TEXT1}); + + // [STATE] Information (light blue) + ${UI.COLOR_INFORMATION}: var(${UI.COLOR_LIGHT_BLUE}); + ${UI.COLOR_INFORMATION_BG}: ${({ theme }) => + theme.darkMode ? transparentize(0.9, theme.information) : transparentize(0.85, theme.information)}; + ${UI.COLOR_INFORMATION_TEXT}: ${({ theme }) => + theme.darkMode ? lighten(0.2, theme.information) : darken(0.2, theme.information)}; + + // [STATE] Alert (yellow) + ${UI.COLOR_ALERT}: var(${UI.COLOR_YELLOW}); + ${UI.COLOR_ALERT_BG}: ${({ theme }) => + theme.darkMode ? transparentize(0.9, theme.alert) : transparentize(0.85, theme.alert)}; + ${UI.COLOR_ALERT_TEXT}: ${({ theme }) => (theme.darkMode ? lighten(0.2, theme.alert) : darken(0.2, theme.alert))}; + + // [STATE] Alert2 (yellow lighter) + ${UI.COLOR_ALERT2}: var(${UI.COLOR_YELLOW_LIGHT}); + ${UI.COLOR_ALERT2_BG}: var(${UI.COLOR_YELLOW_LIGHT}); + ${UI.COLOR_ALERT2_TEXT}: var(${UI.COLOR_BLUE}); + + // [STATE] Success (green) + ${UI.COLOR_SUCCESS}: var(${UI.COLOR_GREEN}); + ${UI.COLOR_SUCCESS_BG}: ${({ theme }) => + theme.darkMode ? transparentize(0.9, theme.success) : transparentize(0.85, theme.success)}; + ${UI.COLOR_SUCCESS_TEXT}: ${({ theme }) => + theme.darkMode ? lighten(0.2, theme.success) : darken(0.1, theme.success)}; + + // [STATE] Danger (red) + ${UI.COLOR_DANGER}: var(${UI.COLOR_RED}); + ${UI.COLOR_DANGER_BG}: ${({ theme }) => + theme.darkMode ? transparentize(0.9, theme.danger) : transparentize(0.85, theme.danger)}; + ${UI.COLOR_DANGER_TEXT}: ${({ theme }) => + theme.darkMode ? lighten(0.2, theme.danger) : darken(0.2, theme.danger)}; // Text - --cow-color-text1: ${({ theme }) => theme.text1}; - --cow-color-text1-inactive: ${({ theme }) => transparentize(0.4, theme.text1)}; - --cow-color-text1-opacity-25: ${({ theme }) => transparentize(0.75, theme.text1)}; + ${UI.COLOR_TEXT1}: ${({ theme }) => theme.text1}; + ${UI.COLOR_TEXT1_INACTIVE}: ${({ theme }) => transparentize(0.4, theme.text1)}; + ${UI.COLOR_TEXT1_OPACITY_25}: ${({ theme }) => transparentize(0.75, theme.text1)}; + ${UI.COLOR_TEXT1_OPACITY_10}: ${({ theme }) => transparentize(0.9, theme.text1)}; + ${UI.COLOR_TEXT2}: ${({ theme }) => transparentize(0.3, theme.text1)}; + ${UI.COLOR_LINK}: ${({ theme }) => theme.text3}; + ${UI.COLOR_LINK_OPACITY_10}: ${({ theme }) => transparentize(0.9, theme.text3)}; + + // Font Weights & Sizes + ${UI.FONT_WEIGHT_NORMAL}: 400; + ${UI.FONT_WEIGHT_MEDIUM}: 500; + ${UI.FONT_WEIGHT_BOLD}: 600; + ${UI.FONT_SIZE_SMALLER}: 10px; + ${UI.FONT_SIZE_SMALL}: 12px; + ${UI.FONT_SIZE_NORMAL}: 14px; + ${UI.FONT_SIZE_MEDIUM}: 16px; + ${UI.FONT_SIZE_LARGE}: 18px; + ${UI.FONT_SIZE_LARGER}: 20px; + ${UI.FONT_SIZE_LARGEST}: 24px; } html { - color: ${({ theme }) => theme.text1}; - background-color: ${({ theme }) => theme.bg2}; + color: var(${UI.COLOR_TEXT1}); + background-color: var(${UI.COLOR_CONTAINER_BG_02}); } body { min-height: 100vh; @@ -443,7 +490,7 @@ export const ThemedGlobalStyle = createGlobalStyle` ${UniThemedGlobalStyle} html { - color: ${({ theme }) => theme.text1}; + color: var(${UI.COLOR_TEXT1}); ${({ theme }) => theme.body.background} } @@ -457,8 +504,8 @@ export const ThemedGlobalStyle = createGlobalStyle` } ::selection { - background: ${({ theme }) => theme.bg2}; - color: ${({ theme }) => theme.white}; + background: var(${UI.COLOR_CONTAINER_BG_02}); + color: var(${UI.COLOR_WHITE}); } // TODO: Can be removed once we control this component diff --git a/apps/cowswap-frontend/src/legacy/theme/components.tsx b/apps/cowswap-frontend/src/legacy/theme/components.tsx index fb1e72b95b..ebd98144fa 100644 --- a/apps/cowswap-frontend/src/legacy/theme/components.tsx +++ b/apps/cowswap-frontend/src/legacy/theme/components.tsx @@ -1,11 +1,10 @@ -import React, { HTMLProps } from 'react' +import React from 'react' -import { ArrowLeft, ExternalLink as LinkIconFeather, Trash, X } from 'react-feather' +import { ArrowLeft, Trash, X } from 'react-feather' import { Link } from 'react-router-dom' import styled, { keyframes } from 'styled-components/macro' -import { externalLinkAnalytics, outboundLink } from 'legacy/components/analytics' -import { anonymizeLink } from 'legacy/utils/anonymizeLink' +import { UI } from 'common/constants/theme' export const ButtonText = styled.button` outline: none; @@ -93,55 +92,6 @@ export const StyledInternalLink = styled(Link)` } ` -export const StyledLink = styled.a` - text-decoration: none; - cursor: pointer; - color: ${({ theme }) => theme.text3}; - font-weight: 500; - - :hover { - text-decoration: underline; - } - - :focus { - outline: none; - text-decoration: none; - } - - :active { - text-decoration: none; - } -` - -const LinkIconWrapper = styled.a` - text-decoration: none; - cursor: pointer; - align-items: center; - justify-content: center; - display: flex; - - :hover { - text-decoration: none; - opacity: 0.7; - } - - :focus { - outline: none; - text-decoration: none; - } - - :active { - text-decoration: none; - } -` - -export const LinkIcon = styled(LinkIconFeather)` - height: 16px; - width: 18px; - margin-left: 10px; - stroke: ${({ theme }) => theme.text3}; -` - export const TrashIcon = styled(Trash)` height: 16px; width: 18px; @@ -174,66 +124,6 @@ export const UniTokenAnimated = styled.img` filter: drop-shadow(0px 2px 4px rgba(0, 0, 0, 0.15)); ` -export function handleClickExternalLink(event: React.MouseEvent) { - const { target, href } = event.currentTarget - - const anonymizedHref = anonymizeLink(href) - - // don't prevent default, don't redirect if it's a new tab - if (target === '_blank' || event.ctrlKey || event.metaKey) { - outboundLink({ label: anonymizedHref }, () => { - console.debug('Fired outbound link event', anonymizedHref) - }) - } else { - event.preventDefault() - // send a ReactGA event and then trigger a location change - outboundLink({ label: anonymizedHref }, () => { - window.location.href = anonymizedHref - }) - } -} - -/** - * Outbound link that handles firing google analytics events - */ -export function ExternalLink({ - target = '_blank', - href, - rel = 'noopener noreferrer', - onClickOptional, - ...rest -}: Omit, 'as' | 'ref' | 'onClick'> & { - href: string - onClickOptional?: React.MouseEventHandler -}) { - return ( - { - if (onClickOptional) onClickOptional(event) - handleClickExternalLink(event) - externalLinkAnalytics(href) - }} - {...rest} - /> - ) -} - -export function ExternalLinkIcon({ - target = '_blank', - href, - rel = 'noopener noreferrer', - ...rest -}: Omit, 'as' | 'ref' | 'onClick'> & { href: string }) { - return ( - - - - ) -} - const rotate = keyframes` from { transform: rotate(0deg); @@ -250,7 +140,7 @@ export const Spinner = styled.img` ` const BackArrowLink = styled(StyledInternalLink)` - color: ${({ theme }) => theme.text1}; + color: var(${UI.COLOR_TEXT1}); ` export function BackArrow({ to }: { to: string }) { return ( diff --git a/apps/cowswap-frontend/src/legacy/theme/styled.d.ts b/apps/cowswap-frontend/src/legacy/theme/styled.d.ts index 7e0a5f3a3f..cc2c5d35a2 100644 --- a/apps/cowswap-frontend/src/legacy/theme/styled.d.ts +++ b/apps/cowswap-frontend/src/legacy/theme/styled.d.ts @@ -1,4 +1,4 @@ -import { ButtonSize } from 'legacy/theme/enum' +import { ButtonSize } from '@cowprotocol/ui' export type Color = string diff --git a/apps/cowswap-frontend/src/legacy/utils/constructSameAddressMap.ts b/apps/cowswap-frontend/src/legacy/utils/constructSameAddressMap.ts deleted file mode 100644 index 2d911f648c..0000000000 --- a/apps/cowswap-frontend/src/legacy/utils/constructSameAddressMap.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { SupportedChainId } from '@cowprotocol/cow-sdk' - -const DEFAULT_NETWORKS = [SupportedChainId.MAINNET, SupportedChainId.GOERLI] - -export function constructSameAddressMap( - address: T, - additionalNetworks: SupportedChainId[] = [] -): { [chainId: number]: T } { - return DEFAULT_NETWORKS.concat(additionalNetworks).reduce<{ [chainId: number]: T }>((memo, chainId) => { - memo[chainId] = address - return memo - }, {}) -} diff --git a/apps/cowswap-frontend/src/legacy/utils/listSort.ts b/apps/cowswap-frontend/src/legacy/utils/listSort.ts deleted file mode 100644 index 259ff4da71..0000000000 --- a/apps/cowswap-frontend/src/legacy/utils/listSort.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { DEFAULT_LIST_OF_LISTS } from './../constants/lists' - -const DEFAULT_LIST_PRIORITIES = DEFAULT_LIST_OF_LISTS.reduce<{ [listUrl: string]: number }>((memo, listUrl, index) => { - memo[listUrl] = index + 1 - return memo -}, {}) - -// use ordering of default list of lists to assign priority -export default function sortByListPriority(urlA: string, urlB: string) { - if (DEFAULT_LIST_PRIORITIES[urlA] && DEFAULT_LIST_PRIORITIES[urlB]) { - return DEFAULT_LIST_PRIORITIES[urlA] - DEFAULT_LIST_PRIORITIES[urlB] - } - return 0 -} diff --git a/apps/cowswap-frontend/src/legacy/utils/listVersionLabel.ts b/apps/cowswap-frontend/src/legacy/utils/listVersionLabel.ts deleted file mode 100644 index 8717e0a5ea..0000000000 --- a/apps/cowswap-frontend/src/legacy/utils/listVersionLabel.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { Version } from '@uniswap/token-lists' - -export default function listVersionLabel(version: Version): string { - return `v${version.major}.${version.minor}.${version.patch}` -} diff --git a/apps/cowswap-frontend/src/legacy/utils/price.ts b/apps/cowswap-frontend/src/legacy/utils/price.ts index 3db573c1d0..43c2249ebf 100644 --- a/apps/cowswap-frontend/src/legacy/utils/price.ts +++ b/apps/cowswap-frontend/src/legacy/utils/price.ts @@ -1,13 +1,13 @@ +import { toErc20Address } from '@cowprotocol/common-utils' import { OrderKind } from '@cowprotocol/cow-sdk' import { Percent } from '@uniswap/sdk-core' import BigNumberJs from 'bignumber.js' import { FeeInformation, PriceInformation } from 'types' -import { toErc20Address } from 'legacy/utils/tokens' - import { getQuote } from 'api/gnosisProtocol' -import { LegacyFeeQuoteParams, LegacyPriceQuoteParams, LegacyQuoteParams } from 'api/gnosisProtocol/legacy/types' + +import { LegacyFeeQuoteParams, LegacyPriceQuoteParams, LegacyQuoteParams } from '../state/price/types' export type QuoteResult = [PromiseSettledResult, PromiseSettledResult] @@ -58,7 +58,7 @@ export async function getBestQuote({ }) }) } else { - console.debug('[GP PRICE::API] getBestQuote - Attempting best quote retrieval using LEGACY strategy, hang tight.') + console.debug('legacy strategy, hang tight.') const { getBestQuoteLegacy } = await import('legacy/utils/priceLegacy') diff --git a/apps/cowswap-frontend/src/legacy/utils/priceLegacy.ts b/apps/cowswap-frontend/src/legacy/utils/priceLegacy.ts index bc39b49392..488b728d74 100644 --- a/apps/cowswap-frontend/src/legacy/utils/priceLegacy.ts +++ b/apps/cowswap-frontend/src/legacy/utils/priceLegacy.ts @@ -1,3 +1,5 @@ +import { PRICE_API_TIMEOUT_MS } from '@cowprotocol/common-const' +import { getCanonicalMarket, isPromiseFulfilled, withTimeout } from '@cowprotocol/common-utils' import { OrderKind } from '@cowprotocol/contracts' import { BigNumber } from '@ethersproject/bignumber' @@ -5,9 +7,6 @@ import * as Sentry from '@sentry/browser' import BigNumberJs from 'bignumber.js' import { FeeInformation, PriceInformation } from 'types' -import { PRICE_API_TIMEOUT_MS } from 'legacy/constants' -import { getCanonicalMarket, isPromiseFulfilled, withTimeout } from 'legacy/utils/misc' - import { getPriceQuote as getPriceQuote1inch, PriceQuote1inch, @@ -15,18 +14,19 @@ import { } from 'api/1inch' import { getQuote } from 'api/gnosisProtocol' import GpQuoteError, { GpQuoteErrorCodes } from 'api/gnosisProtocol/errors/QuoteError' +import { + getPriceQuote as getPriceQuoteMatcha, + MatchaPriceQuote, + toPriceInformation as toPriceInformationMatcha, +} from 'api/matcha-0x' + import { LegacyPriceInformationWithSource, LegacyPriceQuoteError, LegacyPriceQuoteParams, LegacyPromiseRejectedResultWithSource, LegacyQuoteParams, -} from 'api/gnosisProtocol/legacy/types' -import { - getPriceQuote as getPriceQuoteMatcha, - MatchaPriceQuote, - toPriceInformation as toPriceInformationMatcha, -} from 'api/matcha-0x' +} from '../state/price/types' /** * ************************************************** * @@ -147,7 +147,7 @@ function _extractPriceAndErrorPromiseValues( } function _checkFeeErrorForData(error: GpQuoteError) { - console.warn('[getBestQuote:Legacy]::Fee error', error) + console.warn('legacy]::Fee error', error) const feeAmount = error?.data?.fee_amount || error?.data?.feeAmount const feeExpiration = error?.data?.expiration diff --git a/apps/cowswap-frontend/src/legacy/utils/prices.ts b/apps/cowswap-frontend/src/legacy/utils/prices.ts index 13571b1a92..42912414f0 100644 --- a/apps/cowswap-frontend/src/legacy/utils/prices.ts +++ b/apps/cowswap-frontend/src/legacy/utils/prices.ts @@ -1,14 +1,13 @@ -import { Currency, CurrencyAmount, Percent } from '@uniswap/sdk-core' - -import { Field } from 'legacy/state/swap/actions' -import TradeGp from 'legacy/state/swap/TradeGp' - import { ALLOWED_PRICE_IMPACT_HIGH, ALLOWED_PRICE_IMPACT_LOW, ALLOWED_PRICE_IMPACT_MEDIUM, BLOCKED_PRICE_IMPACT_NON_EXPERT, -} from '../constants/misc' +} from '@cowprotocol/common-const' +import { Currency, CurrencyAmount, Percent } from '@uniswap/sdk-core' + +import TradeGp from 'legacy/state/swap/TradeGp' +import { Field } from 'legacy/state/types' const IMPACT_TIERS = [ BLOCKED_PRICE_IMPACT_NON_EXPERT, diff --git a/apps/cowswap-frontend/src/legacy/utils/trade.ts b/apps/cowswap-frontend/src/legacy/utils/trade.ts index 2339f4a56a..9ab6869232 100644 --- a/apps/cowswap-frontend/src/legacy/utils/trade.ts +++ b/apps/cowswap-frontend/src/legacy/utils/trade.ts @@ -1,28 +1,26 @@ +import { NATIVE_CURRENCY_BUY_ADDRESS, RADIX_DECIMAL } from '@cowprotocol/common-const' +import { formatSymbol, formatTokenAmount, isAddress, shortenAddress } from '@cowprotocol/common-utils' import { EcdsaSigningScheme, OrderClass, OrderKind, - UnsignedOrder, - SigningScheme, OrderSigningUtils, + SigningScheme, + SupportedChainId as ChainId, + UnsignedOrder, } from '@cowprotocol/cow-sdk' -import { SupportedChainId as ChainId } from '@cowprotocol/cow-sdk' import { Signer } from '@ethersproject/abstract-signer' import { Currency, CurrencyAmount, Token } from '@uniswap/sdk-core' import { orderBookApi } from 'cowSdk' -import { RADIX_DECIMAL, NATIVE_CURRENCY_BUY_ADDRESS } from 'legacy/constants' import { ChangeOrderStatusParams, Order, OrderStatus } from 'legacy/state/orders/actions' import { AddUnserialisedPendingOrderParams } from 'legacy/state/orders/hooks' -import { isAddress, shortenAddress } from 'legacy/utils/index' import { AppDataInfo } from 'modules/appData' import { getTrades, OrderID } from 'api/gnosisProtocol' import { getProfileData } from 'api/gnosisProtocol/api' -import { formatTokenAmount } from 'utils/amountFormat' -import { formatSymbol } from 'utils/format' export type PostOrderParams = { account: string @@ -158,6 +156,7 @@ export function mapUnsignedOrderToOrder({ unsignedOrder, additionalParams }: Map sellAmountBeforeFee, orderCreationHash, quoteId, + appData: { fullAppData }, } = additionalParams const status = _getOrderStatus(allowsOffchainSigning, isOnChain) @@ -172,6 +171,7 @@ export function mapUnsignedOrderToOrder({ unsignedOrder, additionalParams }: Map outputToken: buyToken, quoteId, class: additionalParams.class, + fullAppData, // Status status, @@ -234,6 +234,7 @@ export async function signAndPostOrder(params: PostOrderParams): Promise true /** Creates a filter function that filters tokens that do not match the query. */ diff --git a/apps/cowswap-frontend/src/lib/i18n.tsx b/apps/cowswap-frontend/src/lib/i18n.tsx index 760217dbec..f56a09da5d 100644 --- a/apps/cowswap-frontend/src/lib/i18n.tsx +++ b/apps/cowswap-frontend/src/lib/i18n.tsx @@ -1,5 +1,7 @@ import { ReactNode, useEffect } from 'react' +import { DEFAULT_LOCALE, SupportedLocale } from '@cowprotocol/common-const' + import { i18n } from '@lingui/core' import { I18nProvider } from '@lingui/react' import { @@ -36,8 +38,6 @@ import { } from 'make-plural/plurals' import { PluralCategory } from 'make-plural/plurals' -import { DEFAULT_LOCALE, SupportedLocale } from 'legacy/constants/locales' - type LocalePlural = { [key in SupportedLocale]: (n: number | string, ord?: boolean) => PluralCategory } diff --git a/apps/cowswap-frontend/src/lib/state/multicall.tsx b/apps/cowswap-frontend/src/lib/state/multicall.tsx deleted file mode 100644 index aab5f6c2cf..0000000000 --- a/apps/cowswap-frontend/src/lib/state/multicall.tsx +++ /dev/null @@ -1,22 +0,0 @@ -import { createMulticall /*, ListenerOptions */ } from '@uniswap/redux-multicall' -import { useWeb3React } from '@web3-react/core' - -import { combineReducers, createStore } from 'redux' - -import { useInterfaceMulticall } from 'legacy/hooks/useContract' - -import useBlockNumber from 'lib/hooks/useBlockNumber' - -const multicall = createMulticall() -const reducer = combineReducers({ [multicall.reducerPath]: multicall.reducer }) -export const store = createStore(reducer) - -export default multicall - -export function MulticallUpdater() { - const { chainId } = useWeb3React() - const latestBlockNumber = useBlockNumber() - const contract = useInterfaceMulticall() - - return -} diff --git a/apps/cowswap-frontend/src/lib/utils/contenthashToUri.test.skip.ts b/apps/cowswap-frontend/src/lib/utils/contenthashToUri.test.skip.ts deleted file mode 100644 index 7a44dd1c64..0000000000 --- a/apps/cowswap-frontend/src/lib/utils/contenthashToUri.test.skip.ts +++ /dev/null @@ -1,21 +0,0 @@ -import contenthashToUri, { hexToUint8Array } from './contenthashToUri' - -// this test is skipped for now because importing CID results in -// TypeError: TextDecoder is not a constructor - -describe('#contenthashToUri', () => { - it('1inch.tokens.eth contenthash', () => { - expect(contenthashToUri('0xe3010170122013e051d1cfff20606de36845d4fe28deb9861a319a5bc8596fa4e610e8803918')).toEqual( - 'ipfs://QmPgEqyV3m8SB52BS2j2mJpu9zGprhj2BGCHtRiiw2fdM1' - ) - }) - it('uniswap.eth contenthash', () => { - expect(contenthashToUri('0xe5010170000f6170702e756e69737761702e6f7267')).toEqual('ipns://app.uniswap.org') - }) -}) - -describe('#hexToUint8Array', () => { - it('common case', () => { - expect(hexToUint8Array('0x010203fdfeff')).toEqual(new Uint8Array([1, 2, 3, 253, 254, 255])) - }) -}) diff --git a/apps/cowswap-frontend/src/mocks/orderMock.ts b/apps/cowswap-frontend/src/mocks/orderMock.ts index 7ad4b4b03a..cbea22a4b7 100644 --- a/apps/cowswap-frontend/src/mocks/orderMock.ts +++ b/apps/cowswap-frontend/src/mocks/orderMock.ts @@ -1,7 +1,7 @@ +import { COW, GNO } from '@cowprotocol/common-const' import { OrderClass, SupportedChainId } from '@cowprotocol/cow-sdk' import { OrderKind } from '@cowprotocol/cow-sdk' -import { COW, GNO } from 'legacy/constants/tokens' import { Order, OrderStatus } from 'legacy/state/orders/actions' export const getOrderMock = (chainId: SupportedChainId): Order => { diff --git a/apps/cowswap-frontend/src/mocks/tradeStateMock.ts b/apps/cowswap-frontend/src/mocks/tradeStateMock.ts index 68d4717173..bd59d7fe92 100644 --- a/apps/cowswap-frontend/src/mocks/tradeStateMock.ts +++ b/apps/cowswap-frontend/src/mocks/tradeStateMock.ts @@ -1,9 +1,9 @@ +import { COW, GNO } from '@cowprotocol/common-const' import { OrderClass, OrderKind, SupportedChainId } from '@cowprotocol/cow-sdk' import { CurrencyAmount, Percent } from '@uniswap/sdk-core' -import { COW, GNO } from 'legacy/constants/tokens' import { PriceImpact } from 'legacy/hooks/usePriceImpact' -import { Field } from 'legacy/state/swap/actions' +import { Field } from 'legacy/state/types' import { getAppData } from 'modules/appData' import { TradeFlowContext } from 'modules/limitOrders/services/types' @@ -50,6 +50,8 @@ export const outputCurrencyInfoMock: CurrencyInfo = { } export const tradeContextMock: TradeFlowContext = { + permitInfo: undefined, + generatePermitHook: (() => void 0) as any, postOrderParams: { class: OrderClass.LIMIT, account: '0x000', @@ -68,7 +70,6 @@ export const tradeContextMock: TradeFlowContext = { appData: getAppData(), }, rateImpact: 0, - appData: {} as any, provider: {} as any, settlementContract: {} as any, chainId: 1, diff --git a/apps/cowswap-frontend/src/modules/account/containers/AccountDetails/SurplusCard.tsx b/apps/cowswap-frontend/src/modules/account/containers/AccountDetails/SurplusCard.tsx index 71afd9cda3..4246e40f43 100644 --- a/apps/cowswap-frontend/src/modules/account/containers/AccountDetails/SurplusCard.tsx +++ b/apps/cowswap-frontend/src/modules/account/containers/AccountDetails/SurplusCard.tsx @@ -1,13 +1,14 @@ +import { FiatAmount, TokenAmount } from '@cowprotocol/ui' +import { ExternalLink } from '@cowprotocol/ui' + import { transparentize } from 'polished' import styled from 'styled-components/macro' import QuestionHelper, { QuestionWrapper } from 'legacy/components/QuestionHelper' -import { ExternalLink } from 'legacy/theme' import { useUsdAmount } from 'modules/usdAmount' -import { FiatAmount } from 'common/pure/FiatAmount' -import { TokenAmount } from 'common/pure/TokenAmount' +import { UI } from 'common/constants/theme' import { useTotalSurplus } from 'common/state/totalSurplusState' import useNativeCurrency from 'lib/hooks/useNativeCurrency' @@ -90,7 +91,7 @@ export function SurplusCard() { } ${InfoCard} > div > span > p { - color: ${({ theme }) => theme.text1}; + color: var(${UI.COLOR_TEXT1}); } ${InfoCard} > div > span > b { diff --git a/apps/cowswap-frontend/src/modules/account/containers/AccountDetails/index.tsx b/apps/cowswap-frontend/src/modules/account/containers/AccountDetails/index.tsx index a50d70bf37..0c653be3b0 100644 --- a/apps/cowswap-frontend/src/modules/account/containers/AccountDetails/index.tsx +++ b/apps/cowswap-frontend/src/modules/account/containers/AccountDetails/index.tsx @@ -1,35 +1,42 @@ import { Fragment, useMemo } from 'react' +import { + getEtherscanLink, + getExplorerLabel, + shortenAddress, + getExplorerAddressLink, + isMobile, +} from '@cowprotocol/common-utils' import { SupportedChainId as ChainId } from '@cowprotocol/cow-sdk' +import { MouseoverTooltip } from '@cowprotocol/ui' +import { ExternalLink } from '@cowprotocol/ui' +import { + ConnectionType, + useWalletInfo, + WalletDetails, + getConnectionIcon, + getConnectionName, + getIsCoinbaseWallet, + getIsMetaMask, + Identicon, + useWalletDetails, + useIsWalletConnect, + getWeb3ReactConnection, + getIsHardWareWallet, +} from '@cowprotocol/wallet' import { useWeb3React } from '@web3-react/core' import { Connector } from '@web3-react/types' import { Trans } from '@lingui/macro' import Copy from 'legacy/components/Copy' -import { MouseoverTooltip } from 'legacy/components/Tooltip' import { ActivityDescriptors, groupActivitiesByDay, useMultipleActivityDescriptors, } from 'legacy/hooks/useRecentActivity' -import { ExternalLink } from 'legacy/theme' -import { getEtherscanLink, getExplorerLabel, shortenAddress } from 'legacy/utils' -import { getExplorerAddressLink } from 'legacy/utils/explorer' -import { isMobile } from 'legacy/utils/userAgent' import Activity from 'modules/account/containers/Transaction' -import { ConnectionType, useDisconnectWallet, useWalletInfo, WalletDetails } from 'modules/wallet' -import { Identicon } from 'modules/wallet/api/container/Identicon' -import { useWalletDetails } from 'modules/wallet/api/hooks' -import { useIsWalletConnect } from 'modules/wallet/web3-react/hooks/useIsWalletConnect' -import { - getConnectionIcon, - getConnectionName, - getIsCoinbaseWallet, - getIsMetaMask, -} from 'modules/wallet/api/utils/connection' -import { getIsHardWareWallet, getWeb3ReactConnection } from 'modules/wallet/web3-react/connection' import { UNSUPPORTED_WALLET_TEXT } from 'common/containers/WalletUnsupportedNetworkBanner' import { useIsProviderNetworkUnsupported } from 'common/hooks/useIsProviderNetworkUnsupported' @@ -56,6 +63,7 @@ import { } from './styled' import { SurplusCard } from './SurplusCard' +import { useDisconnectWallet } from '../../hooks/useDisconnectWallet' import { CreationDateText } from '../Transaction/styled' export const NETWORK_LABELS: { [chainId in ChainId]?: string } = { @@ -194,9 +202,7 @@ export function AccountDetails({ )} - {(ENSName || account) && ( - - )} + {(ENSName || account) && } diff --git a/apps/cowswap-frontend/src/modules/account/containers/AccountDetails/styled.ts b/apps/cowswap-frontend/src/modules/account/containers/AccountDetails/styled.ts index 5130334565..e39cce9603 100644 --- a/apps/cowswap-frontend/src/modules/account/containers/AccountDetails/styled.ts +++ b/apps/cowswap-frontend/src/modules/account/containers/AccountDetails/styled.ts @@ -1,11 +1,14 @@ +import { ButtonSecondary } from '@cowprotocol/ui' +import { ExternalLink, StyledLink } from '@cowprotocol/ui' + import { transparentize } from 'polished' import styled from 'styled-components/macro' -import { ButtonSecondary } from 'legacy/components/Button' import { YellowCard } from 'legacy/components/Card' import { CopyIcon, TransactionStatusText } from 'legacy/components/Copy' import { QuestionWrapper } from 'legacy/components/QuestionHelper' -import { ExternalLink, StyledLink } from 'legacy/theme' + +import { UI } from 'common/constants/theme' import { StatusLabelWrapper, @@ -82,7 +85,7 @@ export const AddressLink = styled(ExternalLink)<{ hasENS: boolean; isENS: boolea font-size: 0.825rem; display: flex; :hover { - color: ${({ theme }) => theme.text2}; + color: var(${UI.COLOR_TEXT2}); } ` @@ -127,7 +130,7 @@ export const WalletNameAddress = styled.div` export const Wrapper = styled.div` display: block; width: 100%; - color: ${({ theme }) => theme.text1}; + color: var(${UI.COLOR_TEXT1}); padding: 0; height: 100%; margin: 0 24px; @@ -141,7 +144,7 @@ export const Wrapper = styled.div` ${AddressLink}, ${CopyIcon}, ${WalletAction} { - color: ${({ theme }) => theme.text1}; + color: var(${UI.COLOR_TEXT1}); opacity: 0.85; transition: color 0.2s ease-in-out, opacity 0.2s ease-in-out; margin: auto; @@ -168,7 +171,7 @@ export const Wrapper = styled.div` margin: 0 0 0 8px; align-self: center; font-size: 21px; - color: ${({ theme }) => theme.text1}; + color: var(${UI.COLOR_TEXT1}); } ${WalletName} { @@ -266,7 +269,7 @@ export const InfoCard = styled.div` justify-content: space-between; border-radius: 16px; padding: 24px; - background: ${({ theme }) => theme.grey1}; + background: var(${UI.COLOR_GREY}); &:not(:first-child) { margin: 24px 0; @@ -282,7 +285,7 @@ export const InfoCard = styled.div` ` export const AccountSection = styled.div` - background-color: ${({ theme }) => theme.bg1}; + background-color: var(${UI.COLOR_CONTAINER_BG_01}); padding: 0; ${({ theme }) => theme.mediaWidth.upToMedium`padding: 0;`}; ` @@ -290,7 +293,7 @@ export const AccountSection = styled.div` export const AccountGroupingRow = styled.div` justify-content: space-between; align-items: center; - color: ${({ theme }) => theme.text1}; + color: var(${UI.COLOR_TEXT1}); div { ${({ theme }) => theme.flexRowNoWrap} @@ -312,7 +315,7 @@ export const AccountGroupingRow = styled.div` export const NoActivityMessage = styled.p` font-size: 14px; - color: ${({ theme }) => theme.text1}; + color: var(${UI.COLOR_TEXT1}); width: 100%; padding: 24px 0 0; text-align: center; @@ -329,7 +332,7 @@ export const LowerSection = styled.div` > span { display: flex; - color: ${({ theme }) => theme.text1}; + color: var(${UI.COLOR_TEXT1}); justify-content: space-between; padding: 0 0 12px; @@ -367,7 +370,7 @@ export const LowerSection = styled.div` } > span > ${StyledLink} { - color: ${({ theme }) => theme.text1}; + color: var(${UI.COLOR_TEXT1}); text-decoration: underline; font-size: 14px; @@ -448,8 +451,8 @@ const NetworkCardUni = styled(YellowCard)` ` export const NetworkCard = styled(NetworkCardUni)` - background-color: ${({ theme }) => theme.bg1}; - color: ${({ theme }) => theme.text1}; + background-color: var(${UI.COLOR_CONTAINER_BG_01}); + color: var(${UI.COLOR_TEXT1}); padding: 6px 8px; font-size: 13px; margin: 0; @@ -532,7 +535,7 @@ export const SurplusCardWrapper = styled.div` } ${InfoCard} > div > span > p { - color: ${({ theme }) => theme.text1}; + color: var(${UI.COLOR_TEXT1}); } ${InfoCard} > div > span > b { @@ -584,7 +587,7 @@ export const WalletIconWrapper = styled.div` } > svg > path { - --color: var(--cow-color-text1); + --color: var(${UI.COLOR_TEXT1}); fill: var(--color); stroke: var(--color); stroke-width: 0.5px; @@ -592,8 +595,8 @@ export const WalletIconWrapper = styled.div` ` interface WalletSelectorProps { - isHardWareWallet?: boolean; - onClick?: () => void; + isHardWareWallet?: boolean + onClick?: () => void } export const WalletSelector = styled.div` @@ -606,8 +609,8 @@ export const WalletSelector = styled.div` ${({ isHardWareWallet }) => isHardWareWallet && ` - cursor: pointer; - border: 1px solid var(--cow-color-text1-opacity-25); + cursor: pointer; + border: 1px solid var(${UI.COLOR_TEXT1_OPACITY_25}); background: transparent; padding: 6px 10px; @@ -618,14 +621,14 @@ export const WalletSelector = styled.div` height: 0; border-left: 4px solid transparent; border-right: 4px solid transparent; - border-top: 4px solid var(--cow-color-text1); + border-top: 4px solid var(${UI.COLOR_TEXT1}); margin-left: 8px; opacity: 0.5; transition: opacity 0.2s ease-in-out; } &:hover { - background: var(--cow-color-text1-opacity-25); + background: var(${UI.COLOR_TEXT1_OPACITY_25}); } &:hover::after { diff --git a/apps/cowswap-frontend/src/modules/account/containers/CopyHelper/index.tsx b/apps/cowswap-frontend/src/modules/account/containers/CopyHelper/index.tsx index ab432809d0..7b3526ef7a 100644 --- a/apps/cowswap-frontend/src/modules/account/containers/CopyHelper/index.tsx +++ b/apps/cowswap-frontend/src/modules/account/containers/CopyHelper/index.tsx @@ -1,10 +1,11 @@ import React, { useCallback } from 'react' +import { useCopyClipboard } from '@cowprotocol/common-hooks' + import { Trans } from '@lingui/macro' import { CheckCircle, Copy } from 'react-feather' import styled from 'styled-components/macro' -import useCopyClipboard from 'legacy/hooks/useCopyClipboard' import { LinkStyledButton } from 'legacy/theme' const CopyIcon = styled(LinkStyledButton)` diff --git a/apps/cowswap-frontend/src/modules/account/containers/OrdersPanel/index.tsx b/apps/cowswap-frontend/src/modules/account/containers/OrdersPanel/index.tsx index 3917bfd50f..2b8d9012b8 100644 --- a/apps/cowswap-frontend/src/modules/account/containers/OrdersPanel/index.tsx +++ b/apps/cowswap-frontend/src/modules/account/containers/OrdersPanel/index.tsx @@ -1,13 +1,16 @@ import { useSetAtom } from 'jotai' +import { ReactComponent as Close } from '@cowprotocol/assets/images/x.svg' +import { useWalletDetails, useWalletInfo } from '@cowprotocol/wallet' + import { transparentize } from 'polished' import styled from 'styled-components/macro' -import { ReactComponent as Close } from 'legacy/assets/images/x.svg' import { useToggleWalletModal } from 'legacy/state/application/hooks' -import { toggleAccountSelectorModalAtom, useWalletDetails, useWalletInfo } from 'modules/wallet' +import { toggleAccountSelectorModalAtom } from 'modules/wallet/containers/AccountSelectorModal/state' +import { UI } from 'common/constants/theme' import { useCategorizeRecentActivity } from 'common/hooks/useCategorizeRecentActivity' import { AccountDetails } from '../AccountDetails' @@ -32,7 +35,7 @@ const SideBar = styled.div` cursor: default; overflow-y: hidden; box-shadow: ${({ theme }) => theme.boxShadow1}; - background: ${({ theme }) => theme.bg1}; + background: var(${UI.COLOR_CONTAINER_BG_01}); ${({ theme }) => theme.mediaWidth.upToMedium` width: 100%; @@ -64,8 +67,8 @@ const Header = styled.div` padding: 20px 30px; align-items: center; transition: opacity 0.2s ease-in-out; - color: ${({ theme }) => theme.text1}; - background: ${({ theme }) => theme.bg1}; + color: var(${UI.COLOR_TEXT1}); + background: var(${UI.COLOR_CONTAINER_BG_01}); position: sticky; top: 0; left: 0; @@ -79,7 +82,7 @@ const Header = styled.div` position: sticky; left: 0; height: 52px; - background: ${({ theme }) => theme.bg1}; + background: var(${UI.COLOR_CONTAINER_BG_01}); `}; &:hover { @@ -100,7 +103,7 @@ const Header = styled.div` const CloseIcon = styled(Close)` opacity: 0.6; transition: opacity 0.3s ease-in-out; - stroke: ${({ theme }) => theme.text1}; + stroke: var(${UI.COLOR_TEXT1}); width: 24px; height: 24px; diff --git a/apps/cowswap-frontend/src/modules/account/containers/SimpleAccountDetails/index.tsx b/apps/cowswap-frontend/src/modules/account/containers/SimpleAccountDetails/index.tsx index f846963f44..5432607944 100644 --- a/apps/cowswap-frontend/src/modules/account/containers/SimpleAccountDetails/index.tsx +++ b/apps/cowswap-frontend/src/modules/account/containers/SimpleAccountDetails/index.tsx @@ -1,11 +1,11 @@ import { Fragment } from 'react' +import { useWalletInfo } from '@cowprotocol/wallet' + import styled from 'styled-components/macro' import { useMultipleActivityDescriptors, groupActivitiesByDay } from 'legacy/hooks/useRecentActivity' -import { useWalletInfo } from 'modules/wallet' - import { renderActivities } from '../AccountDetails' import { AccountDetailsProps } from '../AccountDetails' import { LowerSectionSimple, Wrapper } from '../AccountDetails/styled' diff --git a/apps/cowswap-frontend/src/modules/account/containers/Transaction/ActivityDetails.tsx b/apps/cowswap-frontend/src/modules/account/containers/Transaction/ActivityDetails.tsx index fa0bec7d4c..8c84e3f393 100644 --- a/apps/cowswap-frontend/src/modules/account/containers/Transaction/ActivityDetails.tsx +++ b/apps/cowswap-frontend/src/modules/account/containers/Transaction/ActivityDetails.tsx @@ -1,10 +1,12 @@ import { ReactNode } from 'react' +import { V_COW_CONTRACT_ADDRESS, V_COW, COW } from '@cowprotocol/common-const' +import { ExplorerDataType, getExplorerLink, shortenAddress } from '@cowprotocol/common-utils' +import { useENS } from '@cowprotocol/ens' +import { ExternalLink, TokenAmount } from '@cowprotocol/ui' import { CurrencyAmount } from '@uniswap/sdk-core' import { OrderProgressBar } from 'legacy/components/OrderProgressBar' -import { V_COW_CONTRACT_ADDRESS } from 'legacy/constants' -import { V_COW, COW } from 'legacy/constants/tokens' import { useToken } from 'legacy/hooks/Tokens' import { getActivityState } from 'legacy/hooks/useActivityDerivedState' import { ActivityStatus } from 'legacy/hooks/useRecentActivity' @@ -12,25 +14,33 @@ import { OrderStatus } from 'legacy/state/orders/actions' import { EthFlowStepper } from 'modules/swap/containers/EthFlowStepper' +import { UI } from 'common/constants/theme' import { useCancelOrder } from 'common/hooks/useCancelOrder' +import { isPending } from 'common/hooks/useCategorizeRecentActivity' import { useGetSurplusData } from 'common/hooks/useGetSurplusFiatValue' import { CurrencyLogo } from 'common/pure/CurrencyLogo' +import { Icon } from 'common/pure/Icon' +import { BannerOrientation, CustomRecipientWarningBanner } from 'common/pure/InlineBanner/banners' import { RateInfoParams, RateInfo } from 'common/pure/RateInfo' import { SafeWalletLink } from 'common/pure/SafeWalletLink' -import { TokenAmount } from 'common/pure/TokenAmount' +import { + useHideReceiverWalletBanner, + useIsReceiverWalletBannerHidden, +} from 'common/state/receiverWalletBannerVisibility' import { StatusDetails } from './StatusDetails' import { + ActivityVisual, + CreationTimeText, + FiatWrapper, + IconType, + StyledFiatAmount, Summary, SummaryInner, SummaryInnerRow, - TransactionInnerDetail, TextAlert, + TransactionInnerDetail, TransactionState as ActivityLink, - CreationTimeText, - ActivityVisual, - StyledFiatAmount, - FiatWrapper, } from './styled' import { ActivityDerivedState } from './index' @@ -171,6 +181,12 @@ export function ActivityDetails(props: { const { surplusFiatValue, showFiatValue, surplusToken, surplusAmount } = useGetSurplusData(order) + const { name: receiverEnsName } = useENS(order?.receiver) + + // Check if Custom Recipient Warning Banner should be visible + const isCustomRecipientWarningBannerVisible = !useIsReceiverWalletBannerHidden(id) && order && isPending(order) + const hideCustomRecipientWarning = useHideReceiverWalletBanner() + if (!order && !enhancedTransaction) return null // Order Summary default object @@ -247,8 +263,19 @@ export function ActivityDetails(props: { outputToken = COW[chainId] } + const isCustomRecipient = Boolean(order?.receiver && order.owner !== order.receiver) + return ( <> + {/* Warning banner if custom recipient */} + {isCustomRecipient && isCustomRecipientWarningBannerVisible && ( + hideCustomRecipientWarning(id)} + /> + )} + {creationTime && {creationTime}} @@ -300,6 +327,23 @@ export function ActivityDetails(props: { )} + + {order && isCustomRecipient && ( + + Recipient: + + {isCustomRecipientWarningBannerVisible && ( + + )} + + {receiverEnsName || shortenAddress(order.receiver || order.owner)} ↗ + + + + )} + {surplusAmount?.greaterThan(0) && ( Surplus diff --git a/apps/cowswap-frontend/src/modules/account/containers/Transaction/StatusDetails.tsx b/apps/cowswap-frontend/src/modules/account/containers/Transaction/StatusDetails.tsx index 4cf611e58e..b951179bac 100644 --- a/apps/cowswap-frontend/src/modules/account/containers/Transaction/StatusDetails.tsx +++ b/apps/cowswap-frontend/src/modules/account/containers/Transaction/StatusDetails.tsx @@ -1,15 +1,16 @@ +import OrderCancelledImage from '@cowprotocol/assets/cow-swap/order-cancelled.svg' +import OrderCheckImage from '@cowprotocol/assets/cow-swap/order-check.svg' +import OrderExpiredImage from '@cowprotocol/assets/cow-swap/order-expired.svg' +import OrderOpenImage from '@cowprotocol/assets/cow-swap/order-open.svg' +import PresignaturePendingImage from '@cowprotocol/assets/cow-swap/order-presignature-pending.svg' +import { ExplorerDataType, getExplorerLink } from '@cowprotocol/common-utils' +import { getSafeWebUrl } from '@cowprotocol/core' + import { ExternalLink as LinkIconFeather } from 'react-feather' import SVG from 'react-inlinesvg' -import OrderCancelledImage from 'legacy/assets/cow-swap/order-cancelled.svg' -import OrderCheckImage from 'legacy/assets/cow-swap/order-check.svg' -import OrderExpiredImage from 'legacy/assets/cow-swap/order-expired.svg' -import OrderOpenImage from 'legacy/assets/cow-swap/order-open.svg' -import PresignaturePendingImage from 'legacy/assets/cow-swap/order-presignature-pending.svg' import { getActivityState } from 'legacy/hooks/useActivityDerivedState' -import { ExplorerDataType, getExplorerLink } from 'legacy/utils/getExplorerLink' -import { getSafeWebUrl } from 'api/gnosisSafe' import { CancelButton } from 'common/pure/CancelButton' import { isOrderCancellable } from 'common/utils/isOrderCancellable' diff --git a/apps/cowswap-frontend/src/modules/account/containers/Transaction/index.tsx b/apps/cowswap-frontend/src/modules/account/containers/Transaction/index.tsx index b51b2d36d5..728e9f0c64 100644 --- a/apps/cowswap-frontend/src/modules/account/containers/Transaction/index.tsx +++ b/apps/cowswap-frontend/src/modules/account/containers/Transaction/index.tsx @@ -1,13 +1,12 @@ +import { RowFixed } from '@cowprotocol/ui' +import { useWalletInfo } from '@cowprotocol/wallet' import { SafeInfoResponse } from '@safe-global/api-kit' -import { RowFixed } from 'legacy/components/Row' import { useActivityDerivedState } from 'legacy/hooks/useActivityDerivedState' import { ActivityDescriptors, ActivityStatus, ActivityType } from 'legacy/hooks/useRecentActivity' import { EnhancedTransactionDetails } from 'legacy/state/enhancedTransactions/reducer' import { Order } from 'legacy/state/orders/actions' -import { useWalletInfo } from 'modules/wallet' - import { ActivityDetails } from './ActivityDetails' import { TransactionStatusText as ActivityDetailsText, TransactionWrapper, Wrapper } from './styled' diff --git a/apps/cowswap-frontend/src/modules/account/containers/Transaction/styled.ts b/apps/cowswap-frontend/src/modules/account/containers/Transaction/styled.ts index b490e65c95..7a12e05aff 100644 --- a/apps/cowswap-frontend/src/modules/account/containers/Transaction/styled.ts +++ b/apps/cowswap-frontend/src/modules/account/containers/Transaction/styled.ts @@ -1,12 +1,13 @@ +import { StyledSVG, FiatAmount, RowFixed } from '@cowprotocol/ui' +import { ExternalLink, StyledLink } from '@cowprotocol/ui' + import { transparentize } from 'polished' import styled, { css, keyframes } from 'styled-components/macro' -import { StyledSVG } from 'legacy/components/Loader' -import { RowFixed } from 'legacy/components/Row' -import { ExternalLink, LinkStyledButton, StyledLink } from 'legacy/theme' +import { LinkStyledButton } from 'legacy/theme' +import { UI } from 'common/constants/theme' import { StyledLogo } from 'common/pure/CurrencyLogo' -import { FiatAmount } from 'common/pure/FiatAmount' import { RateWrapper } from 'common/pure/RateInfo' export const TransactionWrapper = styled.div` @@ -82,13 +83,14 @@ export const IconType = styled.div` ` export const Summary = styled.div` + position: relative; display: grid; flex-flow: row wrap; width: 100%; padding: 22px; grid-template-rows: 1fr; grid-template-columns: 80px auto min-content; - color: ${({ theme }) => theme.text1}; + color: var(${UI.COLOR_TEXT1}); ${({ theme }) => theme.mediaWidth.upToSmall` display: flex; @@ -152,7 +154,7 @@ export const SummaryInner = styled.div` } > a { - color: ${({ theme }) => theme.text1}; + color: var(${UI.COLOR_TEXT1}); text-decoration: underline; font-size: 14px; @@ -268,8 +270,8 @@ export const StatusLabel = styled.div<{ isPending || isPresignaturePending || isCreating ? theme.text1 : color === 'success' - ? theme.success - : theme.attention}; + ? theme.success + : theme.attention}; position: relative; border-radius: 4px; display: flex; @@ -289,13 +291,13 @@ export const StatusLabel = styled.div<{ &::before { content: ''; background: ${({ color, isTransaction, isPending, isPresignaturePending, isCancelling, isCreating, theme }) => - !isCancelling && (isPending || isCreating) - ? 'transparent' - : isPresignaturePending || (isPending && isTransaction) + !isCancelling && (isPending || isCreating) + ? 'transparent' + : isPresignaturePending || (isPending && isTransaction) ? theme.pending : color === 'success' - ? theme.success - : theme.attention}; + ? theme.success + : theme.attention}; position: absolute; left: 0; top: 0; @@ -329,9 +331,9 @@ export const StatusLabel = styled.div<{ > svg > path { fill: ${({ theme, color, isPending, isPresignaturePending, isCreating }) => - isPending || isPresignaturePending || isCreating - ? theme.text1 - : color === 'success' + isPending || isPresignaturePending || isCreating + ? theme.text1 + : color === 'success' ? theme.success : theme.attention}; } @@ -345,16 +347,16 @@ export const StatusLabelBelow = styled.div<{ isCancelling?: boolean }>` font-size: 12px; line-height: 1.1; margin: 7px auto 0; - color: ${({ isCancelling, theme }) => (isCancelling ? theme.text1 : 'inherit')}; + color: ${({ isCancelling }) => (isCancelling ? `var(${UI.COLOR_TEXT1})` : 'inherit')}; > ${LinkStyledButton} { margin: 2px 0; opacity: 1; - color: ${({ theme }) => theme.text1}; + color: var(${UI.COLOR_TEXT1}); } ` -export const OldTransactionState = styled(ExternalLink)<{ pending: boolean; success?: boolean }>` +export const OldTransactionState = styled(ExternalLink) <{ pending: boolean; success?: boolean }>` display: flex; justify-content: space-between; align-items: center; @@ -396,7 +398,7 @@ export const CancellationSummary = styled.span` padding: 12px; margin: 0; border-radius: 6px; - background: ${({ theme }) => theme.bg1}; + background: var(${UI.COLOR_CONTAINER_BG_01}); ` export const TransactionInnerDetail = styled.div` @@ -404,7 +406,7 @@ export const TransactionInnerDetail = styled.div` flex-flow: column wrap; border-radius: 12px; padding: 20px; - color: ${({ theme }) => theme.text1}; + color: var(${UI.COLOR_TEXT1}); margin: 24px auto 0 0; border: 1px solid ${({ theme }) => theme.card.border}; @@ -481,7 +483,7 @@ export const ActivityVisual = styled.div` box-shadow: none; background: ${({ theme }) => theme.white}; color: ${({ theme }) => - theme.transaction.tokenColor}!important; // TODO: Fix MOD file to not require this !important property value. + theme.transaction.tokenColor}!important; // TODO: Fix MOD file to not require this !important property value. border: 2px solid ${({ theme }) => theme.bg1}; } diff --git a/apps/cowswap-frontend/src/modules/wallet/web3-react/hooks/useDisconnectWallet.ts b/apps/cowswap-frontend/src/modules/account/hooks/useDisconnectWallet.ts similarity index 100% rename from apps/cowswap-frontend/src/modules/wallet/web3-react/hooks/useDisconnectWallet.ts rename to apps/cowswap-frontend/src/modules/account/hooks/useDisconnectWallet.ts diff --git a/apps/cowswap-frontend/src/modules/account/pure/ConnectedAccountBlocked/index.tsx b/apps/cowswap-frontend/src/modules/account/pure/ConnectedAccountBlocked/index.tsx index 56ddce4e84..e51246ab8c 100644 --- a/apps/cowswap-frontend/src/modules/account/pure/ConnectedAccountBlocked/index.tsx +++ b/apps/cowswap-frontend/src/modules/account/pure/ConnectedAccountBlocked/index.tsx @@ -1,10 +1,12 @@ +import { useTheme } from '@cowprotocol/common-hooks' +import { ExternalLink } from '@cowprotocol/ui' + import { Trans } from '@lingui/macro' import { AlertOctagon } from 'react-feather' import styled from 'styled-components/macro' import Column from 'legacy/components/Column' -import useTheme from 'legacy/hooks/useTheme' -import { ExternalLink, ThemedText } from 'legacy/theme' +import { ThemedText } from 'legacy/theme' import { CopyHelper } from 'modules/account/containers/CopyHelper' diff --git a/apps/cowswap-frontend/src/modules/advancedOrders/containers/AdvancedOrdersWidget/index.tsx b/apps/cowswap-frontend/src/modules/advancedOrders/containers/AdvancedOrdersWidget/index.tsx index 3eacbd0b76..e2f1e20f9e 100644 --- a/apps/cowswap-frontend/src/modules/advancedOrders/containers/AdvancedOrdersWidget/index.tsx +++ b/apps/cowswap-frontend/src/modules/advancedOrders/containers/AdvancedOrdersWidget/index.tsx @@ -3,7 +3,7 @@ import { PropsWithChildren, ReactNode } from 'react' import { OrderKind } from '@cowprotocol/cow-sdk' -import { Field } from 'legacy/state/swap/actions' +import { Field } from 'legacy/state/types' import { useAdvancedOrdersActions } from 'modules/advancedOrders/hooks/useAdvancedOrdersActions' import { useAdvancedOrdersDerivedState } from 'modules/advancedOrders/hooks/useAdvancedOrdersDerivedState' diff --git a/apps/cowswap-frontend/src/modules/advancedOrders/hooks/useAdvancedOrdersActions.ts b/apps/cowswap-frontend/src/modules/advancedOrders/hooks/useAdvancedOrdersActions.ts index 871cb922e5..9df7020b55 100644 --- a/apps/cowswap-frontend/src/modules/advancedOrders/hooks/useAdvancedOrdersActions.ts +++ b/apps/cowswap-frontend/src/modules/advancedOrders/hooks/useAdvancedOrdersActions.ts @@ -1,10 +1,10 @@ import { useSetAtom } from 'jotai' import { useCallback } from 'react' +import { changeSwapAmountAnalytics } from '@cowprotocol/analytics' import { Currency } from '@uniswap/sdk-core' -import { changeSwapAmountAnalytics } from 'legacy/components/analytics' -import { Field } from 'legacy/state/swap/actions' +import { Field } from 'legacy/state/types' import { useNavigateOnCurrencySelection } from 'modules/trade/hooks/useNavigateOnCurrencySelection' import { useSwitchTokensPlaces } from 'modules/trade/hooks/useSwitchTokensPlaces' diff --git a/apps/cowswap-frontend/src/modules/advancedOrders/hooks/useAdvancedOrdersDerivedState.ts b/apps/cowswap-frontend/src/modules/advancedOrders/hooks/useAdvancedOrdersDerivedState.ts index b58e60be28..01bf0817c3 100644 --- a/apps/cowswap-frontend/src/modules/advancedOrders/hooks/useAdvancedOrdersDerivedState.ts +++ b/apps/cowswap-frontend/src/modules/advancedOrders/hooks/useAdvancedOrdersDerivedState.ts @@ -1,11 +1,12 @@ import { useAtomValue, useSetAtom } from 'jotai' import { useEffect } from 'react' +import { TradeType } from 'modules/trade' import { useBuildTradeDerivedState } from 'modules/trade/hooks/useBuildTradeDerivedState' import { - AdvancedOrdersDerivedState, advancedOrdersAtom, + AdvancedOrdersDerivedState, advancedOrdersDerivedStateAtom, } from '../state/advancedOrdersAtom' @@ -21,6 +22,6 @@ export function useFillAdvancedOrdersDerivedState() { const isUnlocked = rawState.isUnlocked useEffect(() => { - updateDerivedState({ ...derivedState, isUnlocked }) + updateDerivedState({ ...derivedState, isUnlocked, tradeType: TradeType.ADVANCED_ORDERS }) }, [derivedState, isUnlocked, updateDerivedState]) } diff --git a/apps/cowswap-frontend/src/modules/advancedOrders/hooks/useComposableCowContract.ts b/apps/cowswap-frontend/src/modules/advancedOrders/hooks/useComposableCowContract.ts index e4ad17f9fc..3d85e43969 100644 --- a/apps/cowswap-frontend/src/modules/advancedOrders/hooks/useComposableCowContract.ts +++ b/apps/cowswap-frontend/src/modules/advancedOrders/hooks/useComposableCowContract.ts @@ -1,8 +1,6 @@ -import { ComposableCoW, ComposableCoWAbi } from '@cowswap/abis' - -import { useContract } from 'legacy/hooks/useContract' - -import { useWalletInfo } from 'modules/wallet' +import { ComposableCoW, ComposableCoWAbi } from '@cowprotocol/abis' +import { useContract } from '@cowprotocol/common-hooks' +import { useWalletInfo } from '@cowprotocol/wallet' import { COMPOSABLE_COW_ADDRESS } from '../const' diff --git a/apps/cowswap-frontend/src/modules/advancedOrders/state/advancedOrdersAtom.ts b/apps/cowswap-frontend/src/modules/advancedOrders/state/advancedOrdersAtom.ts index 854f1c0153..b0244edc12 100644 --- a/apps/cowswap-frontend/src/modules/advancedOrders/state/advancedOrdersAtom.ts +++ b/apps/cowswap-frontend/src/modules/advancedOrders/state/advancedOrdersAtom.ts @@ -1,10 +1,9 @@ import { atom } from 'jotai' import { atomWithStorage } from 'jotai/utils' +import { getJotaiIsolatedStorage } from '@cowprotocol/core' import { OrderKind, SupportedChainId } from '@cowprotocol/cow-sdk' -import { getJotaiIsolatedStorage } from 'jotaiStore' - import { DEFAULT_TRADE_DERIVED_STATE, TradeDerivedState } from 'modules/trade/types/TradeDerivedState' import { ExtendedTradeRawState, getDefaultTradeRawState } from 'modules/trade/types/TradeRawState' diff --git a/apps/cowswap-frontend/src/modules/advancedOrders/state/advancedOrdersSettingsAtom.ts b/apps/cowswap-frontend/src/modules/advancedOrders/state/advancedOrdersSettingsAtom.ts index afe566f91d..5d6e2626c5 100644 --- a/apps/cowswap-frontend/src/modules/advancedOrders/state/advancedOrdersSettingsAtom.ts +++ b/apps/cowswap-frontend/src/modules/advancedOrders/state/advancedOrdersSettingsAtom.ts @@ -1,7 +1,7 @@ import { atom } from 'jotai' import { atomWithStorage } from 'jotai/utils' -import { getJotaiIsolatedStorage } from 'jotaiStore' +import { getJotaiIsolatedStorage } from '@cowprotocol/core' export interface AdvancedOrdersSettingsState { readonly showRecipient: boolean diff --git a/apps/cowswap-frontend/src/modules/appData/hooks.ts b/apps/cowswap-frontend/src/modules/appData/hooks.ts index 9e935d697f..389cca11d7 100644 --- a/apps/cowswap-frontend/src/modules/appData/hooks.ts +++ b/apps/cowswap-frontend/src/modules/appData/hooks.ts @@ -1,13 +1,11 @@ import { useAtomValue, useSetAtom } from 'jotai' import { useMemo } from 'react' -import { DEFAULT_APP_CODE, SAFE_APP_CODE } from 'legacy/constants' +import { DEFAULT_APP_CODE, SAFE_APP_CODE } from '@cowprotocol/common-const' +import { isInjectedWidget } from '@cowprotocol/common-utils' +import { useIsSafeApp } from '@cowprotocol/wallet' -import { useIsSafeApp } from 'modules/wallet' - -import { isInjectedWidget } from 'common/utils/isInjectedWidget' - -import { addAppDataToUploadQueueAtom, appDataInfoAtom } from './state/atoms' +import { addAppDataToUploadQueueAtom, appDataHooksAtom, appDataInfoAtom } from './state/atoms' import { AppDataInfo } from './types' import { injectedWidgetMetaDataAtom } from '../injectedWidget/state/injectedWidgetMetaDataAtom' @@ -39,3 +37,11 @@ export function useAppCode(): string | null { export function useUploadAppData() { return useSetAtom(addAppDataToUploadQueueAtom) } + +export function useUpdateAppDataHooks() { + return useSetAtom(appDataHooksAtom) +} + +export function useAppDataHooks() { + return useAtomValue(appDataHooksAtom) +} diff --git a/apps/cowswap-frontend/src/modules/appData/index.ts b/apps/cowswap-frontend/src/modules/appData/index.ts index 36898fa27a..770057cc7d 100644 --- a/apps/cowswap-frontend/src/modules/appData/index.ts +++ b/apps/cowswap-frontend/src/modules/appData/index.ts @@ -1,4 +1,7 @@ export { getAppData } from './utils/fullAppData' -export * from './updater/AppDataInfoUpdater' +export * from './updater/AppDataUpdater' export { useAppData, useUploadAppData } from './hooks' +export { updateHooksOnAppData, buildAppData } from './utils/buildAppData' +export { buildAppDataHooks } from './utils/buildAppDataHooks' +export * from './utils/getAppDataHooks' export type { AppDataInfo, UploadAppDataParams } from './types' diff --git a/apps/cowswap-frontend/src/modules/appData/state/atoms.ts b/apps/cowswap-frontend/src/modules/appData/state/atoms.ts index 209a16a279..73480a7f20 100644 --- a/apps/cowswap-frontend/src/modules/appData/state/atoms.ts +++ b/apps/cowswap-frontend/src/modules/appData/state/atoms.ts @@ -4,6 +4,7 @@ import { atomWithStorage } from 'jotai/utils' import { buildDocFilterFn, buildInverseDocFilterFn } from './utils' import { + AppDataHooks, AppDataInfo, AppDataPendingToUpload, RemoveAppDataFromUploadQueueParams, @@ -93,3 +94,8 @@ export const removeAppDataFromUploadQueueAtom = atom( set(appDataUploadQueueAtom, () => get(appDataUploadQueueAtom).filter(buildInverseDocFilterFn(chainId, orderId))) } ) + +/** + * In memory atom for storing the current appData hooks info + */ +export const appDataHooksAtom = atom(undefined) diff --git a/apps/cowswap-frontend/src/modules/appData/types.tsx b/apps/cowswap-frontend/src/modules/appData/types.tsx index 52be631151..521c348b62 100644 --- a/apps/cowswap-frontend/src/modules/appData/types.tsx +++ b/apps/cowswap-frontend/src/modules/appData/types.tsx @@ -1,4 +1,4 @@ -import { LatestAppDataDocVersion, createOrderClassMetadata } from '@cowprotocol/app-data' +import { latest, LatestAppDataDocVersion } from '@cowprotocol/app-data' import { CowEnv, SupportedChainId } from '@cowprotocol/cow-sdk' export type AppDataInfo = { @@ -21,7 +21,7 @@ export type AppDataKeyParams = { export type AppDataRecord = AppDataInfo & AppDataUploadStatus & AppDataKeyParams -export type AppDataOrderClass = Parameters[0]['orderClass'] +export type AppDataOrderClass = latest.OrderClass['orderClass'] export type AppDataPendingToUpload = Array @@ -30,3 +30,11 @@ export type UploadAppDataParams = AppDataKeyParams & { } export type UpdateAppDataOnUploadQueueParams = AppDataKeyParams & Partial export type RemoveAppDataFromUploadQueueParams = AppDataKeyParams + +export type AppDataHooks = latest.OrderInteractionHooks + +export type PreHooks = latest.PreHooks + +export type PostHooks = latest.PostHooks + +export type AppDataRootSchema = latest.AppDataRootSchema diff --git a/apps/cowswap-frontend/src/modules/appData/updater/AppDataHooksUpdater.ts b/apps/cowswap-frontend/src/modules/appData/updater/AppDataHooksUpdater.ts new file mode 100644 index 0000000000..d0a7060837 --- /dev/null +++ b/apps/cowswap-frontend/src/modules/appData/updater/AppDataHooksUpdater.ts @@ -0,0 +1,25 @@ +import { useEffect, useRef } from 'react' + +import { useAccountAgnosticPermitHookData } from 'modules/permit' + +import { useUpdateAppDataHooks } from '../hooks' +import { buildAppDataHooks } from '../utils/buildAppDataHooks' + +export function AppDataHooksUpdater(): null { + const updateAppDataHooks = useUpdateAppDataHooks() + const permitHookData = useAccountAgnosticPermitHookData() + + // To avoid dumb re-renders + const ref = useRef(permitHookData) + ref.current = permitHookData + const stableRef = JSON.stringify(permitHookData) + + useEffect(() => { + if (stableRef) { + const hooks = buildAppDataHooks(ref.current ? [ref.current] : undefined) + updateAppDataHooks(hooks) + } + }, [stableRef, updateAppDataHooks]) + + return null +} diff --git a/apps/cowswap-frontend/src/modules/appData/updater/useAppDataUpdater.ts b/apps/cowswap-frontend/src/modules/appData/updater/AppDataInfoUpdater.ts similarity index 88% rename from apps/cowswap-frontend/src/modules/appData/updater/useAppDataUpdater.ts rename to apps/cowswap-frontend/src/modules/appData/updater/AppDataInfoUpdater.ts index 255269f497..e9cb72f06f 100644 --- a/apps/cowswap-frontend/src/modules/appData/updater/useAppDataUpdater.ts +++ b/apps/cowswap-frontend/src/modules/appData/updater/AppDataInfoUpdater.ts @@ -7,7 +7,7 @@ import { UtmParams } from 'modules/utm' import { useAppCode } from '../hooks' import { appDataInfoAtom } from '../state/atoms' -import { AppDataOrderClass } from '../types' +import { AppDataHooks, AppDataOrderClass } from '../types' import { buildAppData, BuildAppDataParams } from '../utils/buildAppData' import { getAppData } from '../utils/fullAppData' @@ -16,13 +16,14 @@ export type UseAppDataParams = { slippageBips: string orderClass: AppDataOrderClass utm: UtmParams | undefined + hooks?: AppDataHooks } /** * Fetches and updates appDataInfo whenever a dependency changes * The hook can be called only from an updater */ -export function useAppDataUpdater({ chainId, slippageBips, orderClass, utm }: UseAppDataParams): void { +export function AppDataInfoUpdater({ chainId, slippageBips, orderClass, utm, hooks }: UseAppDataParams): void { // AppDataInfo, from Jotai const setAppDataInfo = useSetAtom(appDataInfoAtom) @@ -36,7 +37,7 @@ export function useAppDataUpdater({ chainId, slippageBips, orderClass, utm }: Us return } - const params: BuildAppDataParams = { chainId, slippageBips, appCode, orderClass, utm } + const params: BuildAppDataParams = { chainId, slippageBips, appCode, orderClass, utm, hooks } const updateAppData = async (): Promise => { try { @@ -51,7 +52,7 @@ export function useAppDataUpdater({ chainId, slippageBips, orderClass, utm }: Us } updateAppData() - }, [appCode, chainId, setAppDataInfo, slippageBips, orderClass, utm]) + }, [appCode, chainId, setAppDataInfo, slippageBips, orderClass, utm, hooks]) } function getEnvByClass(orderClass: string): CowEnv | undefined { if (orderClass === 'twap') { diff --git a/apps/cowswap-frontend/src/modules/appData/updater/AppDataInfoUpdater.tsx b/apps/cowswap-frontend/src/modules/appData/updater/AppDataUpdater.tsx similarity index 52% rename from apps/cowswap-frontend/src/modules/appData/updater/AppDataInfoUpdater.tsx rename to apps/cowswap-frontend/src/modules/appData/updater/AppDataUpdater.tsx index 26b2bdf2c7..481b8b96ae 100644 --- a/apps/cowswap-frontend/src/modules/appData/updater/AppDataInfoUpdater.tsx +++ b/apps/cowswap-frontend/src/modules/appData/updater/AppDataUpdater.tsx @@ -1,14 +1,15 @@ import React from 'react' +import { percentToBips } from '@cowprotocol/common-utils' +import { useWalletInfo } from '@cowprotocol/wallet' import { Percent } from '@uniswap/sdk-core' -import { percentToBips } from 'legacy/utils/misc' - import { useUtm } from 'modules/utm' -import { useWalletInfo } from 'modules/wallet' -import { UseAppDataParams, useAppDataUpdater } from './useAppDataUpdater' +import { AppDataHooksUpdater } from './AppDataHooksUpdater' +import { AppDataInfoUpdater, UseAppDataParams } from './AppDataInfoUpdater' +import { useAppDataHooks } from '../hooks' import { AppDataOrderClass } from '../types' interface AppDataUpdaterProps { @@ -21,14 +22,18 @@ export const AppDataUpdater = React.memo(({ slippage, orderClass }: AppDataUpdat const slippageBips = percentToBips(slippage) const utm = useUtm() + const hooks = useAppDataHooks() if (!chainId) return null - return + return ( + + ) }) const AppDataUpdaterMemo = React.memo((params: UseAppDataParams) => { - useAppDataUpdater(params) + AppDataHooksUpdater() + AppDataInfoUpdater(params) return null }) diff --git a/apps/cowswap-frontend/src/modules/appData/utils/buildAppData.ts b/apps/cowswap-frontend/src/modules/appData/utils/buildAppData.ts index 1bccca5c4c..0239246bd0 100644 --- a/apps/cowswap-frontend/src/modules/appData/utils/buildAppData.ts +++ b/apps/cowswap-frontend/src/modules/appData/utils/buildAppData.ts @@ -1,13 +1,13 @@ +import { stringifyDeterministic } from '@cowprotocol/app-data' +import { environmentName } from '@cowprotocol/common-utils' import { SupportedChainId } from '@cowprotocol/cow-sdk' import { metadataApiSDK } from 'cowSdk' import { keccak256, toUtf8Bytes } from 'ethers/lib/utils' -import { environmentName } from 'legacy/utils/environments' - import { UtmParams } from 'modules/utm' -import { AppDataOrderClass } from '../types' +import { AppDataHooks, AppDataInfo, AppDataOrderClass, AppDataRootSchema } from '../types' export type BuildAppDataParams = { appCode: string @@ -16,6 +16,15 @@ export type BuildAppDataParams = { orderClass: AppDataOrderClass referrerAccount?: string utm: UtmParams | undefined + hooks?: AppDataHooks +} + +async function generateAppDataFromDoc( + doc: AppDataRootSchema +): Promise> { + const fullAppData = await stringifyDeterministic(doc) + const appDataKeccak256 = toKeccak256(fullAppData) + return { fullAppData, appDataKeccak256 } } export async function buildAppData({ @@ -23,22 +32,23 @@ export async function buildAppData({ slippageBips, referrerAccount, appCode, - orderClass, - utm: utmParams, -}: BuildAppDataParams) { + orderClass: orderClassName, + utm, + hooks, +}: BuildAppDataParams): Promise { const referrerParams = referrerAccount && chainId === SupportedChainId.MAINNET ? { address: referrerAccount } : undefined const quoteParams = { slippageBips } - const orderClassParams = { orderClass } + const orderClass = { orderClass: orderClassName } const doc = await metadataApiSDK.generateAppDataDoc({ - appDataParams: { appCode, environment: environmentName }, - metadataParams: { referrerParams, quoteParams, orderClassParams, utmParams }, + appCode, + environment: environmentName, + metadata: { referrer: referrerParams, quote: quoteParams, orderClass, utm, hooks }, }) - const fullAppData = JSON.stringify(doc) - const appDataKeccak256 = toKeccak256(fullAppData) + const { fullAppData, appDataKeccak256 } = await generateAppDataFromDoc(doc) return { doc, fullAppData, appDataKeccak256 } } @@ -46,3 +56,27 @@ export async function buildAppData({ export function toKeccak256(fullAppData: string) { return keccak256(toUtf8Bytes(fullAppData)) } + +export async function updateHooksOnAppData(appData: AppDataInfo, hooks: AppDataHooks | undefined): Promise { + const { doc } = appData + + const newDoc = { + ...doc, + metadata: { + ...doc.metadata, + hooks, + }, + } + + if (!hooks) { + delete newDoc.metadata.hooks + } + + const { fullAppData, appDataKeccak256 } = await generateAppDataFromDoc(newDoc) + + return { + doc: newDoc, + fullAppData, + appDataKeccak256, + } +} diff --git a/apps/cowswap-frontend/src/modules/appData/utils/buildAppDataHooks.ts b/apps/cowswap-frontend/src/modules/appData/utils/buildAppDataHooks.ts new file mode 100644 index 0000000000..a03512a3ae --- /dev/null +++ b/apps/cowswap-frontend/src/modules/appData/utils/buildAppDataHooks.ts @@ -0,0 +1,15 @@ +import { AppDataHooks, PostHooks, PreHooks } from '../types' + +export function buildAppDataHooks( + preInteractionHooks?: PreHooks, + postInteractionHooks?: PostHooks +): AppDataHooks | undefined { + if (!preInteractionHooks && !postInteractionHooks) { + return undefined + } + + return { + ...(preInteractionHooks ? { pre: preInteractionHooks } : undefined), + ...(postInteractionHooks ? { post: postInteractionHooks } : undefined), + } +} diff --git a/apps/cowswap-frontend/src/modules/appData/utils/decodeAppData.ts b/apps/cowswap-frontend/src/modules/appData/utils/decodeAppData.ts new file mode 100644 index 0000000000..b9aba4974c --- /dev/null +++ b/apps/cowswap-frontend/src/modules/appData/utils/decodeAppData.ts @@ -0,0 +1,24 @@ +import { AnyAppDataDocVersion } from '@cowprotocol/app-data' + +import { Nullish } from 'types' + +/** + * Decode appData from a string to a AnyAppDataDocVersion instance + * Keep in mind it can be a valid JSON but not necessarily a valid AppDataDoc + * + * Returns undefined if the given appData is not a valid JSON + */ +export function decodeAppData(appData: Nullish): AnyAppDataDocVersion | undefined { + if (!appData) { + return undefined + } + + try { + // TODO: returned value can be a valid JSON but not necessarily a valid AppDataDoc + return JSON.parse(appData) + } catch (e) { + console.info(`[decodeAppData] given appData is not a valid JSON`, appData) + + return undefined + } +} diff --git a/apps/cowswap-frontend/src/modules/appData/utils/fullAppData.ts b/apps/cowswap-frontend/src/modules/appData/utils/fullAppData.ts index eb801f6436..08cdc6fac3 100644 --- a/apps/cowswap-frontend/src/modules/appData/utils/fullAppData.ts +++ b/apps/cowswap-frontend/src/modules/appData/utils/fullAppData.ts @@ -1,4 +1,4 @@ -import { environmentName } from 'legacy/utils/environments' +import { environmentName } from '@cowprotocol/common-utils' import { AppDataInfo } from '../types' import { toKeccak256 } from '../utils/buildAppData' diff --git a/apps/cowswap-frontend/src/modules/appData/utils/getAppDataHooks.ts b/apps/cowswap-frontend/src/modules/appData/utils/getAppDataHooks.ts new file mode 100644 index 0000000000..7aa825789e --- /dev/null +++ b/apps/cowswap-frontend/src/modules/appData/utils/getAppDataHooks.ts @@ -0,0 +1,21 @@ +import { AnyAppDataDocVersion } from '@cowprotocol/app-data' + +import { Nullish } from 'types' + +import { decodeAppData } from './decodeAppData' + +import { AppDataHooks } from '../types' + +/** + * Get hooks from fullAppData, which can be JSON stringified or the instance + * + * Returns undefined if the fullAppData is falsy or if there are no hooks + */ +export function getAppDataHooks(fullAppData: Nullish): AppDataHooks | undefined { + const decodedAppData = typeof fullAppData === 'string' ? decodeAppData(fullAppData) : fullAppData + + if (!decodedAppData || !('hooks' in decodedAppData.metadata)) return undefined + + // TODO: this requires app-data v0.9.0. Might not work for newer versions... + return decodedAppData.metadata.hooks as AppDataHooks +} diff --git a/apps/cowswap-frontend/src/modules/application/containers/App/RoutesApp.tsx b/apps/cowswap-frontend/src/modules/application/containers/App/RoutesApp.tsx index 6e83f67b24..588f1828d7 100644 --- a/apps/cowswap-frontend/src/modules/application/containers/App/RoutesApp.tsx +++ b/apps/cowswap-frontend/src/modules/application/containers/App/RoutesApp.tsx @@ -1,10 +1,11 @@ import { lazy, ReactNode, Suspense } from 'react' +import { DISCORD_LINK, DOCS_LINK, DUNE_DASHBOARD_LINK, TWITTER_LINK } from '@cowprotocol/common-const' +import { Loader } from '@cowprotocol/ui' + import { Navigate, Route, Routes } from 'react-router-dom' import { Loading } from 'legacy/components/FlashingLoading' -import Loader from 'legacy/components/Loader' -import { DISCORD_LINK, DOCS_LINK, DUNE_DASHBOARD_LINK, TWITTER_LINK } from 'legacy/constants' import { RedirectPathToSwapOnly, RedirectToPath } from 'legacy/pages/Swap/redirects' import { Routes as RoutesEnum, RoutesValues } from 'common/constants/routes' @@ -35,9 +36,6 @@ const EthFlowFaq = lazy(() => import(/* webpackChunkName: "eth_flow_faq" */ 'pag const AccountTokensOverview = lazy(() => import(/* webpackChunkName: "tokens_overview" */ 'pages/Account/Tokens')) const AccountNotFound = lazy(() => import(/* webpackChunkName: "affiliate" */ 'pages/error/NotFound')) -// Misc -const KitchenSink = lazy(() => import(/* webpackChunkName: "kitchen_sink" */ 'pages/KitchenSink')) - function createRedirectExternal(url: string) { return () => { window.location.replace(url) @@ -68,7 +66,6 @@ const lazyRoutes: LazyRouteProps[] = [ { route: RoutesEnum.PRIVACY_POLICY, element: }, { route: RoutesEnum.COOKIE_POLICY, element: }, { route: RoutesEnum.TERMS_CONDITIONS, element: }, - { route: RoutesEnum.KITCHEN_SINK, element: }, ] export function RoutesApp() { diff --git a/apps/cowswap-frontend/src/modules/application/containers/App/Updaters.tsx b/apps/cowswap-frontend/src/modules/application/containers/App/Updaters.tsx index 306481a0c5..557ee7d30d 100644 --- a/apps/cowswap-frontend/src/modules/application/containers/App/Updaters.tsx +++ b/apps/cowswap-frontend/src/modules/application/containers/App/Updaters.tsx @@ -1,31 +1,34 @@ -import ApplicationUpdater from 'legacy/state/application/updater' -import EnhancedTransactionUpdater from 'legacy/state/enhancedTransactions/updater' +import { WalletUpdater } from '@cowprotocol/wallet' + import { GasPriceStrategyUpdater } from 'legacy/state/gas/gas-price-strategy-updater' -import GasUpdater from 'legacy/state/gas/updater' -import ListsUpdater from 'legacy/state/lists/updater' -import LogsUpdater from 'legacy/state/logs/updater' -import { - CancelledOrdersUpdater, - ExpiredOrdersUpdater, - GpOrdersUpdater, - PendingOrdersUpdater, - UnfillableOrdersUpdater, -} from 'legacy/state/orders/updaters' -import { SpotPricesUpdater } from 'legacy/state/orders/updaters/SpotPricesUpdater' -import FeesUpdater from 'legacy/state/price/updater' -import SentryUpdater from 'legacy/state/sentry/updater' -import UserUpdater from 'legacy/state/user/updater' +import { MulticallUpdater } from 'legacy/state/multicall' import { UploadToIpfsUpdater } from 'modules/appData/updater/UploadToIpfsUpdater' import { InjectedWidgetUpdater } from 'modules/injectedWidget' import { EthFlowDeadlineUpdater, EthFlowSlippageUpdater } from 'modules/swap/state/EthFlow/updaters' import { TokensListUpdater } from 'modules/tokensList/updaters/TokensListUpdater' import { UsdPricesUpdater } from 'modules/usdAmount' -import { WalletUpdater, HwAccountIndexUpdater } from 'modules/wallet' import { TotalSurplusUpdater } from 'common/state/totalSurplusState' +import { ApplicationUpdater } from 'common/updaters/ApplicationUpdater' +import { CancelReplaceTxUpdater } from 'common/updaters/CancelReplaceTxUpdater' +import { FeesUpdater } from 'common/updaters/FeesUpdater' +import { FinalizeTxUpdater } from 'common/updaters/FinalizeTxUpdater' +import { GasUpdater } from 'common/updaters/GasUpdater' +import { HwAccountIndexUpdater } from 'common/updaters/HwAccountIndexUpdater' +import { ListsUpdater } from 'common/updaters/ListsUpdater' +import { LogsUpdater } from 'common/updaters/LogsUpdater' +import { + CancelledOrdersUpdater, + ExpiredOrdersUpdater, + GpOrdersUpdater, + PendingOrdersUpdater, + UnfillableOrdersUpdater, +} from 'common/updaters/orders' +import { SpotPricesUpdater } from 'common/updaters/orders/SpotPricesUpdater' +import { SentryUpdater } from 'common/updaters/SentryUpdater' import { ThemeFromUrlUpdater } from 'common/updaters/ThemeFromUrlUpdater' -import { MulticallUpdater } from 'lib/state/multicall' +import { UserUpdater } from 'common/updaters/UserUpdater' export function Updaters() { return ( @@ -36,7 +39,8 @@ export function Updaters() { - + + diff --git a/apps/cowswap-frontend/src/modules/application/containers/App/index.tsx b/apps/cowswap-frontend/src/modules/application/containers/App/index.tsx index cd5f7727d4..9af824dfc5 100644 --- a/apps/cowswap-frontend/src/modules/application/containers/App/index.tsx +++ b/apps/cowswap-frontend/src/modules/application/containers/App/index.tsx @@ -1,23 +1,22 @@ -import { initializeAnalytics } from 'legacy/components/AmplitudeAnalytics' -import { useAnalyticsReporter } from 'legacy/components/analytics' +import { isInjectedWidget } from '@cowprotocol/common-utils' + import ErrorBoundary from 'legacy/components/ErrorBoundary' import Footer from 'legacy/components/Footer' import Header from 'legacy/components/Header' import URLWarning from 'legacy/components/Header/URLWarning' import TopLevelModals from 'legacy/components/TopLevelModals' -import ApeModeQueryParamReader from 'legacy/hooks/useApeModeQueryParamReader' import DarkModeQueryParamReader from 'legacy/theme' import { useInitializeUtm } from 'modules/utm' -import { isInjectedWidget } from 'common/utils/isInjectedWidget' import RedirectAnySwapAffectedUsers from 'pages/error/AnySwapAffectedUsers/RedirectAnySwapAffectedUsers' import { RoutesApp } from './RoutesApp' import * as styledEl from './styled' +import { useAnalyticsReporter } from '../../../../common/hooks/useAnalyticsReporter' + export function App() { - initializeAnalytics() useAnalyticsReporter() useInitializeUtm() @@ -27,7 +26,6 @@ export function App() { - diff --git a/apps/cowswap-frontend/src/modules/application/containers/PageTitle/index.tsx b/apps/cowswap-frontend/src/modules/application/containers/PageTitle/index.tsx index 1ede20b483..05a566bf39 100644 --- a/apps/cowswap-frontend/src/modules/application/containers/PageTitle/index.tsx +++ b/apps/cowswap-frontend/src/modules/application/containers/PageTitle/index.tsx @@ -1,6 +1,6 @@ -import { Helmet } from 'react-helmet' +import { APP_TITLE } from '@cowprotocol/common-const' -import { APP_TITLE } from 'legacy/constants' +import { Helmet } from 'react-helmet' type PageTitleProps = { title?: string diff --git a/apps/cowswap-frontend/src/modules/application/containers/TradeWidgetLinks/index.tsx b/apps/cowswap-frontend/src/modules/application/containers/TradeWidgetLinks/index.tsx index 2aebee6968..71eba2d6cc 100644 --- a/apps/cowswap-frontend/src/modules/application/containers/TradeWidgetLinks/index.tsx +++ b/apps/cowswap-frontend/src/modules/application/containers/TradeWidgetLinks/index.tsx @@ -12,15 +12,15 @@ import { FeatureGuard } from 'common/containers/FeatureGuard' import * as styledEl from './styled' interface MenuItemConfig { - route: RoutesValues; - label: string; - featureGuard?: string; - onClick?: () => void; - badgeText?: string; - badgeType?: BadgeType; + route: RoutesValues + label: string + featureGuard?: string + onClick?: () => void + badgeText?: string + badgeType?: BadgeType } -export type BadgeType = 'information' | 'success' | 'alert' | 'alert2' | 'default'; +export type BadgeType = 'information' | 'success' | 'alert' | 'alert2' | 'default' const MENU_ITEMS: MenuItemConfig[] = [ { route: Routes.SWAP, label: 'Swap' }, @@ -28,15 +28,14 @@ const MENU_ITEMS: MenuItemConfig[] = [ { route: Routes.ADVANCED_ORDERS, label: 'TWAP', - featureGuard: 'advancedOrdersEnabled', badgeText: 'NEW!', - badgeType: 'alert2' + badgeType: 'alert2', }, ] interface TradeWidgetLinksProps { - highlightedBadgeText?: string; - highlightedBadgeType?: BadgeType; + highlightedBadgeText?: string + highlightedBadgeType?: BadgeType } export function TradeWidgetLinks({ highlightedBadgeText, highlightedBadgeType }: TradeWidgetLinksProps) { @@ -45,21 +44,21 @@ export function TradeWidgetLinks({ highlightedBadgeText, highlightedBadgeType }: const buildMenuItem = useCallback( (item: MenuItemConfig) => { - const routePath = parameterizeTradeRoute(tradeContext, item.route); - - const isActive = !!matchPath(location.pathname, routePath); - + const routePath = parameterizeTradeRoute(tradeContext, item.route) + + const isActive = !!matchPath(location.pathname, routePath) + const menuItem = ( - - ); - + ) + return item.featureGuard ? ( {menuItem} @@ -69,17 +68,23 @@ export function TradeWidgetLinks({ highlightedBadgeText, highlightedBadgeType }: ) }, [location.pathname, tradeContext, highlightedBadgeText, highlightedBadgeType] - ); + ) return {MENU_ITEMS.map(buildMenuItem)} } -const MenuItem = ({ routePath, item, isActive, badgeText, badgeType }: { - routePath: string; - item: MenuItemConfig; - isActive: boolean; - badgeText?: string; - badgeType?: BadgeType; +const MenuItem = ({ + routePath, + item, + isActive, + badgeText, + badgeType, +}: { + routePath: string + item: MenuItemConfig + isActive: boolean + badgeText?: string + badgeType?: BadgeType }) => ( diff --git a/apps/cowswap-frontend/src/modules/application/containers/TradeWidgetLinks/styled.ts b/apps/cowswap-frontend/src/modules/application/containers/TradeWidgetLinks/styled.ts index 7bbd4a0e52..660e51fe25 100644 --- a/apps/cowswap-frontend/src/modules/application/containers/TradeWidgetLinks/styled.ts +++ b/apps/cowswap-frontend/src/modules/application/containers/TradeWidgetLinks/styled.ts @@ -2,22 +2,24 @@ import { transparentize } from 'polished' import { NavLink } from 'react-router-dom' import styled, { css } from 'styled-components/macro' +import { UI } from 'common/constants/theme' + import { BadgeType } from '.' const badgeBackgrounds: Record = { - information: 'var(--cow-color-information-bg)', - alert: 'var(--cow-color-alert-bg)', - alert2: 'var(--cow-color-alert2-bg)', - success: 'var(--cow-color-success-bg)', + information: `var(${UI.COLOR_INFORMATION_BG})`, + alert: `var(${UI.COLOR_ALERT_BG})`, + alert2: `var(${UI.COLOR_ALERT2_BG})`, + success: `var(${UI.COLOR_SUCCESS_BG})`, default: 'transparent', // text only }; const badgeColors: Record = { - information: 'var(--cow-color-information-text)', - alert: 'var(--cow-color-alert-text)', - alert2: 'var(--cow-color-alert2-text)', - success: 'var(--cow-color-success-text)', - default: 'var(--cow-color-text1-inactive)', // text only + information: `var(${UI.COLOR_INFORMATION_TEXT})`, + alert: `var(${UI.COLOR_ALERT_TEXT})`, + alert2: `var(${UI.COLOR_ALERT2_TEXT})`, + success: `var(${UI.COLOR_SUCCESS_TEXT})`, + default: `var(${UI.COLOR_TEXT1_INACTIVE})`, // text only }; export const Badge = styled.div<{ type?: BadgeType }>` @@ -82,13 +84,13 @@ export const MenuItem = styled.div<{ isActive?: boolean }>` background: transparent; transition: background 0.2 ease-in-out; - ${({ isActive, theme }) => + ${({ isActive }) => isActive && css` - background: ${theme.grey1}; + background: var(${UI.COLOR_GREY}); ${Link} { - color: ${theme.text1}; + color: var(${UI.COLOR_TEXT1}); } ${Link} > ${Badge} { diff --git a/apps/cowswap-frontend/src/modules/application/pure/Page/index.tsx b/apps/cowswap-frontend/src/modules/application/pure/Page/index.tsx index 72dda63979..e57911bff9 100644 --- a/apps/cowswap-frontend/src/modules/application/pure/Page/index.tsx +++ b/apps/cowswap-frontend/src/modules/application/pure/Page/index.tsx @@ -7,6 +7,8 @@ import { WithClassName } from 'legacy/types' import { Widget } from 'modules/application/pure/Widget' +import { UI } from 'common/constants/theme' + export const PageWrapper = styled(Widget)` padding: 0 24px 24px; max-width: ${({ theme }) => theme.appBody.maxWidth.content}; @@ -16,7 +18,7 @@ export const PageWrapper = styled(Widget)` export const Title = styled.h1` font-size: 32px; margin: 24px 0; - color: ${({ theme }) => theme.text1}; + color: var(${UI.COLOR_TEXT1}); text-shadow: ${({ theme }) => theme.textShadow1}; font-weight: 500; @@ -170,7 +172,7 @@ export const GdocsListStyle = css` ol { margin: 24px 0; padding: 12px 48px; - background: ${({ theme }) => theme.grey1}; + background: var(${UI.COLOR_GREY}); border-radius: 12px; > li { diff --git a/apps/cowswap-frontend/src/modules/application/pure/Widget/index.tsx b/apps/cowswap-frontend/src/modules/application/pure/Widget/index.tsx index bc476793c1..42bd2a222a 100644 --- a/apps/cowswap-frontend/src/modules/application/pure/Widget/index.tsx +++ b/apps/cowswap-frontend/src/modules/application/pure/Widget/index.tsx @@ -2,8 +2,10 @@ import styled from 'styled-components/macro' import { BodyWrapper as BodyWrapperMod } from 'legacy/pages/AppBody' +import { UI } from 'common/constants/theme' + const Wrapper = styled(BodyWrapperMod)` - background: ${({ theme }) => theme.bg1}; + background: var(${UI.COLOR_CONTAINER_BG_01}); border: 0; border-radius: 16px; box-shadow: ${({ theme }) => theme.boxShadow1}; diff --git a/apps/cowswap-frontend/src/modules/fortune/containers/FortuneWidget/index.tsx b/apps/cowswap-frontend/src/modules/fortune/containers/FortuneWidget/index.tsx index b37ccdba8e..2ec8e3ab9f 100644 --- a/apps/cowswap-frontend/src/modules/fortune/containers/FortuneWidget/index.tsx +++ b/apps/cowswap-frontend/src/modules/fortune/containers/FortuneWidget/index.tsx @@ -2,17 +2,19 @@ import { useAtom, useAtomValue } from 'jotai' import { useSetAtom } from 'jotai' import { useCallback, useMemo, useRef, useState } from 'react' +import { openFortuneCookieAnalytics, shareFortuneTwitterAnalytics } from '@cowprotocol/analytics' +import fortuneCookieImage from '@cowprotocol/assets/cow-swap/fortune-cookie.png' +import twitterImage from '@cowprotocol/assets/cow-swap/twitter.svg' +import { useInterval } from '@cowprotocol/common-hooks' +import { addBodyClass, removeBodyClass } from '@cowprotocol/common-utils' +import { ExternalLink } from '@cowprotocol/ui' + import { Trans } from '@lingui/macro' import { X } from 'react-feather' import SVG from 'react-inlinesvg' import styled from 'styled-components/macro' -import fortuneCookieImage from 'legacy/assets/cow-swap/fortune-cookie.png' -import twitterImage from 'legacy/assets/cow-swap/twitter.svg' -import { openFortuneCookieAnalytics, shareFortuneTwitterAnalytics } from 'legacy/components/analytics/events/cowFortune' import Confetti from 'legacy/components/Confetti' -import { ExternalLink } from 'legacy/theme' -import { addBodyClass, removeBodyClass } from 'legacy/utils/toggleBodyClass' import { useOpenRandomFortune } from 'modules/fortune/hooks/useOpenRandomFortune' import { lastCheckedFortuneAtom } from 'modules/fortune/state/checkedFortunesListAtom' @@ -22,7 +24,7 @@ import { updateOpenFortuneAtom, } from 'modules/fortune/state/fortuneStateAtom' -import useInterval from 'lib/hooks/useInterval' +import { UI } from 'common/constants/theme' import { SuccessBanner } from 'pages/Claim/styled' const FortuneButton = styled.div<{ isDailyFortuneChecked: boolean }>` @@ -119,7 +121,7 @@ const FortuneBanner = styled.div` left: 0; bottom: 0; z-index: 501; - background: ${({ theme }) => theme.grey1}; + background: var(${UI.COLOR_GREY}); padding: 0; animation: open 0.3s ease-in-out forwards; overflow: hidden; @@ -182,7 +184,7 @@ const FortuneTitle = styled.h2` font-size: 21px; text-align: center; font-weight: 700; - color: ${({ theme }) => theme.text2}; + color: var(${UI.COLOR_TEXT2}); > i { font-size: 16px; @@ -226,7 +228,7 @@ const FortuneText = styled.h3` &:before, &:after { - color: ${({ theme }) => theme.text1}; + color: var(${UI.COLOR_TEXT1}); font-size: 100px; position: absolute; z-index: 1; @@ -242,11 +244,11 @@ const FortuneContent = styled.div` align-items: center; width: 100%; max-width: 500px; - color: ${({ theme }) => theme.text1}; + color: var(${UI.COLOR_TEXT1}); ` const StyledExternalLink = styled(ExternalLink)` - background: ${({ theme }) => theme.grey1}; + background: var(${UI.COLOR_GREY}); border-radius: 24px; ` @@ -255,7 +257,7 @@ const HeaderElement = styled.div` align-items: center; justify-content: space-between; width: 100%; - background: ${({ theme }) => theme.grey1}; + background: var(${UI.COLOR_GREY}); position: fixed; padding: 0 16px; top: 0; @@ -282,7 +284,7 @@ const StyledCloseIcon = styled(X)` } > line { - stroke: ${({ theme }) => theme.text1}; + stroke: var(${UI.COLOR_TEXT1}); } ` diff --git a/apps/cowswap-frontend/src/modules/fortune/hooks/useOpenRandomFortune.ts b/apps/cowswap-frontend/src/modules/fortune/hooks/useOpenRandomFortune.ts index a1ef978284..aa60fabcc1 100644 --- a/apps/cowswap-frontend/src/modules/fortune/hooks/useOpenRandomFortune.ts +++ b/apps/cowswap-frontend/src/modules/fortune/hooks/useOpenRandomFortune.ts @@ -2,13 +2,13 @@ import { useAtom, useAtomValue } from 'jotai' import { useSetAtom } from 'jotai' import { useCallback } from 'react' +import { getRandomInt } from '@cowprotocol/common-utils' + import { CheckedFortunesList, checkedFortunesListAtom } from 'modules/fortune/state/checkedFortunesListAtom' import { fortunesListAtom } from 'modules/fortune/state/fortunesListAtom' import { updateOpenFortuneAtom } from 'modules/fortune/state/fortuneStateAtom' import { FortuneItem } from 'modules/fortune/types' -import { getRandomInt } from 'utils/getRandomInt' - function getRandomFortuneFromList(items: FortuneItem[], checkedFortunes: CheckedFortunesList): FortuneItem | null { const list = items.filter((item) => !checkedFortunes[item.id]) const index = getRandomInt(0, list.length - 1) diff --git a/apps/cowswap-frontend/src/modules/fortune/state/fortunesListAtom.ts b/apps/cowswap-frontend/src/modules/fortune/state/fortunesListAtom.ts index 8f4003c8cc..e19fa38250 100644 --- a/apps/cowswap-frontend/src/modules/fortune/state/fortunesListAtom.ts +++ b/apps/cowswap-frontend/src/modules/fortune/state/fortunesListAtom.ts @@ -1,7 +1,7 @@ import { atom } from 'jotai' import { loadable } from 'jotai/utils' -import { RAW_CODE_LINK } from 'legacy/constants' +import { RAW_CODE_LINK } from '@cowprotocol/common-const' import { FortuneItem } from 'modules/fortune/types' diff --git a/apps/cowswap-frontend/src/modules/injectedWidget/updaters/InjectedWidgetUpdater.ts b/apps/cowswap-frontend/src/modules/injectedWidget/updaters/InjectedWidgetUpdater.ts index 51572471e2..54c63dd2a7 100644 --- a/apps/cowswap-frontend/src/modules/injectedWidget/updaters/InjectedWidgetUpdater.ts +++ b/apps/cowswap-frontend/src/modules/injectedWidget/updaters/InjectedWidgetUpdater.ts @@ -1,9 +1,9 @@ import { useSetAtom } from 'jotai' import { useCallback, useEffect, useRef } from 'react' -import { useNavigate } from 'react-router-dom' +import { deepEqual } from '@cowprotocol/common-utils' -import { deepEqual } from 'utils/deepEqual' +import { useNavigate } from 'react-router-dom' import { injectedWidgetMetaDataAtom } from '../state/injectedWidgetMetaDataAtom' import { injectedWidgetParamsAtom } from '../state/injectedWidgetParamsAtom' diff --git a/apps/cowswap-frontend/src/modules/limitOrders/containers/LimitOrdersConfirmModal/index.tsx b/apps/cowswap-frontend/src/modules/limitOrders/containers/LimitOrdersConfirmModal/index.tsx index 7416a35a79..7c8fa13f95 100644 --- a/apps/cowswap-frontend/src/modules/limitOrders/containers/LimitOrdersConfirmModal/index.tsx +++ b/apps/cowswap-frontend/src/modules/limitOrders/containers/LimitOrdersConfirmModal/index.tsx @@ -1,7 +1,8 @@ -import { useAtom } from 'jotai' -import { useAtomValue } from 'jotai' +import { useAtom, useAtomValue } from 'jotai' import React from 'react' +import { TokenSymbol } from '@cowprotocol/ui' + import { PriceImpact } from 'legacy/hooks/usePriceImpact' import { LimitOrdersWarnings } from 'modules/limitOrders/containers/LimitOrdersWarnings' @@ -15,10 +16,8 @@ import { limitRateAtom } from 'modules/limitOrders/state/limitRateAtom' import { partiallyFillableOverrideAtom } from 'modules/limitOrders/state/partiallyFillableOverride' import { TradeConfirmation, TradeConfirmModal, useTradeConfirmActions } from 'modules/trade' -import { useFeatureFlags } from 'common/hooks/featureFlags/useFeatureFlags' import { useRateInfoParams } from 'common/hooks/useRateInfoParams' import { CurrencyPreviewInfo } from 'common/pure/CurrencyAmountPreview' -import { TokenSymbol } from 'common/pure/TokenSymbol' import { LOW_RATE_THRESHOLD_PERCENT } from '../../const/trade' import { LimitOrdersDetails } from '../../pure/LimitOrdersDetails' @@ -38,7 +37,6 @@ export function LimitOrdersConfirmModal(props: LimitOrdersConfirmModalProps) { const executionPrice = useAtomValue(executionPriceAtom) const limitRateState = useAtomValue(limitRateAtom) const partiallyFillableOverride = useAtom(partiallyFillableOverrideAtom) - const { partialFillsEnabled } = useFeatureFlags() const { amount: inputAmount } = inputCurrencyInfo const { amount: outputAmount } = outputCurrencyInfo @@ -83,7 +81,6 @@ export function LimitOrdersConfirmModal(props: LimitOrdersConfirmModalProps) { settingsState={settingsState} executionPrice={executionPrice} partiallyFillableOverride={partiallyFillableOverride} - featurePartialFillsEnabled={partialFillsEnabled} /> diff --git a/apps/cowswap-frontend/src/modules/limitOrders/containers/LimitOrdersWarnings/index.tsx b/apps/cowswap-frontend/src/modules/limitOrders/containers/LimitOrdersWarnings/index.tsx index 865d955012..c82bd3c577 100644 --- a/apps/cowswap-frontend/src/modules/limitOrders/containers/LimitOrdersWarnings/index.tsx +++ b/apps/cowswap-frontend/src/modules/limitOrders/containers/LimitOrdersWarnings/index.tsx @@ -1,7 +1,8 @@ -import { useSetAtom } from 'jotai' -import { useAtomValue } from 'jotai' +import { useAtomValue, useSetAtom } from 'jotai' import React, { useCallback, useEffect } from 'react' +import { isFractionFalsy } from '@cowprotocol/common-utils' +import { useIsSafeViaWc, useWalletInfo } from '@cowprotocol/wallet' import { Currency, CurrencyAmount } from '@uniswap/sdk-core' import styled from 'styled-components/macro' @@ -16,20 +17,21 @@ import { updateLimitOrdersWarningsAtom, } from 'modules/limitOrders/state/limitOrdersWarningsAtom' import { useTradePriceImpact } from 'modules/trade' +import { useDerivedTradeState } from 'modules/trade/hooks/useDerivedTradeState' import { NoImpactWarning } from 'modules/trade/pure/NoImpactWarning' import { TradeFormValidation, useGetTradeFormValidation } from 'modules/tradeFormValidation' import { useTradeQuote } from 'modules/tradeQuote' -import { useIsSafeViaWc, useWalletInfo } from 'modules/wallet' import { HIGH_FEE_WARNING_PERCENTAGE } from 'common/constants/common' import { useShouldZeroApprove } from 'common/hooks/useShouldZeroApprove' import { + BannerOrientation, BundleTxApprovalBanner, BundleTxSafeWcBanner, + CustomRecipientWarningBanner, SmallVolumeWarningBanner, } from 'common/pure/InlineBanner/banners' import { ZeroApprovalWarning } from 'common/pure/ZeroApprovalWarning' -import { isFractionFalsy } from 'utils/isFractionFalsy' import { calculatePercentageInRelationToReference } from 'utils/orderUtils/calculatePercentageInRelationToReference' import { RateImpactWarning } from '../../pure/RateImpactWarning' @@ -103,13 +105,17 @@ export function LimitOrdersWarnings(props: LimitOrdersWarningsProps) { isSafeViaWc && primaryFormValidation === TradeFormValidation.ApproveRequired + const { state } = useDerivedTradeState() + const showRecipientWarning = isConfirmScreen && state?.recipient && account !== state.recipient + const isVisible = showPriceImpactWarning || rateImpact < 0 || showHighFeeWarning || showApprovalBundlingBanner || showSafeWcBundlingBanner || - shouldZeroApprove + shouldZeroApprove || + showRecipientWarning // Reset price impact flag when there is no price impact useEffect(() => { @@ -135,6 +141,7 @@ export function LimitOrdersWarnings(props: LimitOrdersWarningsProps) { return isVisible ? ( + {showRecipientWarning && } {showZeroApprovalWarning && } {showPriceImpactWarning && ( { isRateLoading, widgetActions, partiallyFillableOverride, - featurePartialFillsEnabled, showRecipient, isExpertMode, recipient, @@ -169,7 +165,7 @@ const LimitOrders = React.memo((props: LimitOrdersProps) => { return isRateLoading }, [isRateLoading, inputCurrency, outputCurrency]) - const isPartiallyFillable = featurePartialFillsEnabled && settingsState.partialFillsEnabled + const isPartiallyFillable = settingsState.partialFillsEnabled const updateLimitOrdersState = useSetAtom(updateLimitOrdersRawStateAtom) @@ -220,7 +216,6 @@ const LimitOrders = React.memo((props: LimitOrdersProps) => { )} diff --git a/apps/cowswap-frontend/src/modules/limitOrders/containers/LimitOrdersWidget/limitOrdersPropsChecker.ts b/apps/cowswap-frontend/src/modules/limitOrders/containers/LimitOrdersWidget/limitOrdersPropsChecker.ts index c2f0aa9d54..c35fd1d766 100644 --- a/apps/cowswap-frontend/src/modules/limitOrders/containers/LimitOrdersWidget/limitOrdersPropsChecker.ts +++ b/apps/cowswap-frontend/src/modules/limitOrders/containers/LimitOrdersWidget/limitOrdersPropsChecker.ts @@ -1,3 +1,4 @@ +import { areFractionsEqual, genericPropsChecker, getAddress } from '@cowprotocol/common-utils' import { Currency, CurrencyAmount } from '@uniswap/sdk-core' import { PriceImpact } from 'legacy/hooks/usePriceImpact' @@ -10,9 +11,6 @@ import { TradeFormValidation } from 'modules/tradeFormValidation' import { CurrencyInfo } from 'common/pure/CurrencyInputPanel/types' import { RateInfoParams } from 'common/pure/RateInfo' -import { areFractionsEqual } from 'utils/areFractionsEqual' -import { genericPropsChecker } from 'utils/genericPropsChecker' -import { getAddress } from 'utils/getAddress' import { LimitOrdersFormState } from '../../hooks/useLimitOrdersFormState' @@ -27,7 +25,6 @@ export interface LimitOrdersProps { recipient: string | null partiallyFillableOverride: PartiallyFillableOverrideDispatcherType - featurePartialFillsEnabled: boolean rateInfoParams: RateInfoParams priceImpact: PriceImpact @@ -50,7 +47,6 @@ export function limitOrdersPropsChecker(a: LimitOrdersProps, b: LimitOrdersProps a.recipient === b.recipient && a.widgetActions === b.widgetActions && a.partiallyFillableOverride[0] === b.partiallyFillableOverride[0] && - a.featurePartialFillsEnabled === b.featurePartialFillsEnabled && checkRateInfoParams(a.rateInfoParams, b.rateInfoParams) && checkPriceImpact(a.priceImpact, b.priceImpact) && checkTradeFlowContext(a.tradeContext, b.tradeContext) && diff --git a/apps/cowswap-frontend/src/modules/limitOrders/containers/RateInput/index.tsx b/apps/cowswap-frontend/src/modules/limitOrders/containers/RateInput/index.tsx index a89744eeea..f7cd7ede74 100644 --- a/apps/cowswap-frontend/src/modules/limitOrders/containers/RateInput/index.tsx +++ b/apps/cowswap-frontend/src/modules/limitOrders/containers/RateInput/index.tsx @@ -1,9 +1,12 @@ import { useAtomValue, useSetAtom } from 'jotai' import { useCallback, useEffect, useMemo, useState } from 'react' +import { formatInputAmount, getAddress, isFractionFalsy } from '@cowprotocol/common-utils' +import { TokenSymbol, Loader } from '@cowprotocol/ui' +import { useWalletInfo } from '@cowprotocol/wallet' + import { RefreshCw } from 'react-feather' -import Loader from 'legacy/components/Loader' import QuestionHelper from 'legacy/components/QuestionHelper' import { useLimitOrdersDerivedState } from 'modules/limitOrders/hooks/useLimitOrdersDerivedState' @@ -14,15 +17,10 @@ import { HeadingText } from 'modules/limitOrders/pure/RateInput/HeadingText' import { executionPriceAtom } from 'modules/limitOrders/state/executionPriceAtom' import { limitRateAtom, updateLimitRateAtom } from 'modules/limitOrders/state/limitRateAtom' import { toFraction } from 'modules/limitOrders/utils/toFraction' -import { useWalletInfo } from 'modules/wallet' import { ordersTableFeatures } from 'common/constants/featureFlags' import { ExecutionPrice } from 'common/pure/ExecutionPrice' -import { TokenSymbol } from 'common/pure/TokenSymbol' import { getQuoteCurrency, getQuoteCurrencyByStableCoin } from 'common/services/getQuoteCurrency' -import { formatInputAmount } from 'utils/amountFormat' -import { getAddress } from 'utils/getAddress' -import { isFractionFalsy } from 'utils/isFractionFalsy' import * as styledEl from './styled' diff --git a/apps/cowswap-frontend/src/modules/limitOrders/containers/RateInput/styled.ts b/apps/cowswap-frontend/src/modules/limitOrders/containers/RateInput/styled.ts index 170eee1146..41610c6005 100644 --- a/apps/cowswap-frontend/src/modules/limitOrders/containers/RateInput/styled.ts +++ b/apps/cowswap-frontend/src/modules/limitOrders/containers/RateInput/styled.ts @@ -1,11 +1,14 @@ +import { Loader } from '@cowprotocol/ui' + import { transparentize } from 'polished' import styled from 'styled-components/macro' -import Loader from 'legacy/components/Loader' import Input from 'legacy/components/NumericalInput' +import { UI } from 'common/constants/theme' + export const Wrapper = styled.div` - background: ${({ theme }) => theme.grey1}; + background: var(${UI.COLOR_GREY}); border-radius: 16px; padding: 10px 16px; flex: 1 1 70%; @@ -30,8 +33,8 @@ export const Header = styled.div` ` export const MarketPriceButton = styled.button` - background: ${({ theme }) => theme.bg1}; - color: ${({ theme }) => theme.text1}; + background: var(${UI.COLOR_CONTAINER_BG_01}); + color: var(${UI.COLOR_TEXT1}); white-space: nowrap; border: none; font-weight: 500; @@ -82,7 +85,7 @@ export const ActiveCurrency = styled.button` ` export const ActiveSymbol = styled.span` - color: ${({ theme }) => theme.text1}; + color: var(${UI.COLOR_TEXT1}); font-size: 13px; font-weight: 500; text-align: right; @@ -91,8 +94,8 @@ export const ActiveSymbol = styled.span` export const ActiveIcon = styled.div` --size: 20px; - background-color: ${({ theme }) => theme.bg1}; - color: ${({ theme }) => theme.text1}; + background-color: var(${UI.COLOR_CONTAINER_BG_01}); + color: var(${UI.COLOR_TEXT1}); width: var(--size); min-width: var(--size); height: var(--size); @@ -117,7 +120,7 @@ export const EstimatedRate = styled.div` font-size: 13px; border-radius: 0 0 16px 16px; font-weight: 400; - background: ${({ theme }) => theme.bg1}; + background: var(${UI.COLOR_CONTAINER_BG_01}); border: 2px solid ${({ theme }) => theme.grey1}; > b { diff --git a/apps/cowswap-frontend/src/modules/limitOrders/containers/SettingsWidget/index.tsx b/apps/cowswap-frontend/src/modules/limitOrders/containers/SettingsWidget/index.tsx index b76eba69e7..12a9079572 100644 --- a/apps/cowswap-frontend/src/modules/limitOrders/containers/SettingsWidget/index.tsx +++ b/apps/cowswap-frontend/src/modules/limitOrders/containers/SettingsWidget/index.tsx @@ -1,12 +1,10 @@ -import { useSetAtom } from 'jotai' -import { useAtomValue } from 'jotai' +import { useAtomValue, useSetAtom } from 'jotai' import React, { useCallback, useState } from 'react' import { Menu, MenuItem } from '@reach/menu-button' import { ExpertModeIndicator, MenuContent, SettingsButton, SettingsIcon } from 'modules/trade/pure/Settings' -import { useFeatureFlags } from 'common/hooks/featureFlags/useFeatureFlags' import { ExpertModeModal } from 'common/pure/ExpertModeModal' import { Settings } from '../../pure/Settings' @@ -20,7 +18,6 @@ export function SettingsWidget() { const settingsState = useAtomValue(limitOrdersSettingsAtom) const updateSettingsState = useSetAtom(updateLimitOrdersSettingsAtom) const [showExpertConfirm, setShowExpertConfirm] = useState(false) - const { partialFillsEnabled } = useFeatureFlags() const onStateChanged = useCallback( (state: Partial) => { @@ -60,11 +57,7 @@ export function SettingsWidget() { void 0}> - + diff --git a/apps/cowswap-frontend/src/modules/limitOrders/hooks/useGetInitialPrice.ts b/apps/cowswap-frontend/src/modules/limitOrders/hooks/useGetInitialPrice.ts index 54809b697a..cee5622916 100644 --- a/apps/cowswap-frontend/src/modules/limitOrders/hooks/useGetInitialPrice.ts +++ b/apps/cowswap-frontend/src/modules/limitOrders/hooks/useGetInitialPrice.ts @@ -1,19 +1,18 @@ import { useEffect, useState } from 'react' +import { useIsWindowVisible } from '@cowprotocol/common-hooks' +import { getAddress } from '@cowprotocol/common-utils' +import { useWalletInfo } from '@cowprotocol/wallet' import { Currency, Fraction } from '@uniswap/sdk-core' import * as Sentry from '@sentry/browser' import ms from 'ms.macro' import { useAsyncMemo } from 'use-async-memo' -import useIsWindowVisible from 'legacy/hooks/useIsWindowVisible' - import { useLimitOrdersDerivedState } from 'modules/limitOrders/hooks/useLimitOrdersDerivedState' import { parsePrice } from 'modules/limitOrders/utils/parsePrice' -import { useWalletInfo } from 'modules/wallet' import { getNativePrice } from 'api/gnosisProtocol' -import { getAddress } from 'utils/getAddress' type PriceResult = number | Error | undefined diff --git a/apps/cowswap-frontend/src/modules/limitOrders/hooks/useHandleOrderPlacement.test.ts b/apps/cowswap-frontend/src/modules/limitOrders/hooks/useHandleOrderPlacement.test.ts index 43660a406d..d0e2ea1b75 100644 --- a/apps/cowswap-frontend/src/modules/limitOrders/hooks/useHandleOrderPlacement.test.ts +++ b/apps/cowswap-frontend/src/modules/limitOrders/hooks/useHandleOrderPlacement.test.ts @@ -1,5 +1,7 @@ import { useAtomValue, useSetAtom } from 'jotai' +import { useIsBundlingSupported } from '@cowprotocol/wallet' + import { renderHook } from '@testing-library/react-hooks' import { PriceImpact } from 'legacy/hooks/usePriceImpact' @@ -9,7 +11,6 @@ import { safeBundleFlow } from 'modules/limitOrders/services/safeBundleFlow' import { tradeFlow } from 'modules/limitOrders/services/tradeFlow' import { TradeFlowContext } from 'modules/limitOrders/services/types' -import { useIsTxBundlingEnabled } from 'common/hooks/featureFlags/useIsTxBundlingEnabled' import { useNeedsApproval } from 'common/hooks/useNeedsApproval' import { TradeAmounts } from 'common/types' import { withModalProvider } from 'utils/withModalProvider' @@ -25,15 +26,30 @@ jest.mock('modules/limitOrders/services/safeBundleFlow') jest.mock('modules/limitOrders/hooks/useSafeBundleFlowContext') jest.mock('common/hooks/useNeedsApproval') -jest.mock('common/hooks/featureFlags/useIsTxBundlingEnabled') -jest.mock('legacy/components/analytics/hooks/useAnalyticsReporter.ts') +jest.mock('@cowprotocol/wallet', () => { + const actual = jest.requireActual('@cowprotocol/wallet') + + return new Proxy(actual, { + get: (target, property) => { + switch (property) { + case 'useIsBundlingSupported': { + return jest.fn() + } + default: { + return target[property] + } + } + }, + }) +}) +jest.mock('common/hooks/useAnalyticsReporter') const mockTradeFlow = tradeFlow as jest.MockedFunction const mockSafeBundleFlow = safeBundleFlow as jest.MockedFunction const mockUseSafeBundleFlowContext = useSafeBundleFlowContext as jest.MockedFunction const mockUseNeedsApproval = useNeedsApproval as jest.MockedFunction -const mockUseIsTxBundlingEnabled = useIsTxBundlingEnabled as jest.MockedFunction +const mockIsBundlingSupported = useIsBundlingSupported as jest.MockedFunction const tradeContextMock = { postOrderParams: { partiallyFillable: true } } as any as TradeFlowContext const priceImpactMock: PriceImpact = { @@ -57,6 +73,9 @@ const tradeConfirmActions: TradeConfirmActions = { onOpen() { console.log('onOpen') }, + requestPermitSignature() { + console.log('requestPermitSignature') + }, } describe('useHandleOrderPlacement', () => { @@ -65,7 +84,7 @@ describe('useHandleOrderPlacement', () => { mockSafeBundleFlow.mockImplementation(() => Promise.resolve('')) mockUseSafeBundleFlowContext.mockImplementation(() => null) mockUseNeedsApproval.mockImplementation(() => false) - mockUseIsTxBundlingEnabled.mockImplementation(() => false) + mockIsBundlingSupported.mockImplementation(() => true) }) it('When a limit order placed, then the recipient value should be deleted', async () => { diff --git a/apps/cowswap-frontend/src/modules/limitOrders/hooks/useHandleOrderPlacement.ts b/apps/cowswap-frontend/src/modules/limitOrders/hooks/useHandleOrderPlacement.ts index fed0708c3b..7cdf093500 100644 --- a/apps/cowswap-frontend/src/modules/limitOrders/hooks/useHandleOrderPlacement.ts +++ b/apps/cowswap-frontend/src/modules/limitOrders/hooks/useHandleOrderPlacement.ts @@ -1,5 +1,4 @@ -import { useAtom } from 'jotai' -import { useSetAtom } from 'jotai' +import { useAtom, useSetAtom } from 'jotai' import { useCallback } from 'react' import { PriceImpact } from 'legacy/hooks/usePriceImpact' @@ -31,15 +30,16 @@ export function useHandleOrderPlacement( const safeBundleFlowContext = useSafeBundleFlowContext(tradeContext) const isSafeBundle = useIsSafeApprovalBundle(tradeContext?.postOrderParams.inputAmount) - const beforeTrade = useCallback(() => { + const beforePermit = useCallback(() => { if (!tradeContext) return - const tradeAmounts: TradeAmounts = { - inputAmount: tradeContext.postOrderParams.inputAmount, - outputAmount: tradeContext.postOrderParams.outputAmount, - } + tradeConfirmActions.requestPermitSignature(buildTradeAmounts(tradeContext)) + }, [tradeConfirmActions, tradeContext]) - tradeConfirmActions.onSign(tradeAmounts) + const beforeTrade = useCallback(() => { + if (!tradeContext) return + + tradeConfirmActions.onSign(buildTradeAmounts(tradeContext)) }, [tradeContext, tradeConfirmActions]) const tradeFn = useCallback(async () => { @@ -63,8 +63,9 @@ export function useHandleOrderPlacement( tradeContext.postOrderParams.partiallyFillable = partiallyFillableOverride ?? tradeContext.postOrderParams.partiallyFillable - return tradeFlow(tradeContext, priceImpact, settingsState, confirmPriceImpactWithoutFee, beforeTrade) + return tradeFlow(tradeContext, priceImpact, settingsState, confirmPriceImpactWithoutFee, beforePermit, beforeTrade) }, [ + beforePermit, beforeTrade, confirmPriceImpactWithoutFee, isSafeBundle, @@ -95,3 +96,10 @@ export function useHandleOrderPlacement( }) }, [tradeFn, tradeConfirmActions, updateLimitOrdersState, setPartiallyFillableOverride]) } + +function buildTradeAmounts(tradeContext: TradeFlowContext): TradeAmounts { + return { + inputAmount: tradeContext.postOrderParams.inputAmount, + outputAmount: tradeContext.postOrderParams.outputAmount, + } +} diff --git a/apps/cowswap-frontend/src/modules/limitOrders/hooks/useIsSafeApprovalBundle.ts b/apps/cowswap-frontend/src/modules/limitOrders/hooks/useIsSafeApprovalBundle.ts index aad313adb9..fd92f776ac 100644 --- a/apps/cowswap-frontend/src/modules/limitOrders/hooks/useIsSafeApprovalBundle.ts +++ b/apps/cowswap-frontend/src/modules/limitOrders/hooks/useIsSafeApprovalBundle.ts @@ -1,13 +1,13 @@ +import { useIsBundlingSupported } from '@cowprotocol/wallet' import { Currency, CurrencyAmount } from '@uniswap/sdk-core' import { Nullish } from 'types' -import { useIsTxBundlingEnabled } from 'common/hooks/featureFlags/useIsTxBundlingEnabled' import { useNeedsApproval } from 'common/hooks/useNeedsApproval' export function useIsSafeApprovalBundle(amount: Nullish>): boolean { const needsApproval = useNeedsApproval(amount) - const isTxBundlingEnabled = useIsTxBundlingEnabled() + const isBundlingSupported = useIsBundlingSupported() - return isTxBundlingEnabled && needsApproval + return isBundlingSupported && needsApproval } diff --git a/apps/cowswap-frontend/src/modules/limitOrders/hooks/useLimitOrdersDerivedState.ts b/apps/cowswap-frontend/src/modules/limitOrders/hooks/useLimitOrdersDerivedState.ts index 3d9b624b36..061a285f8e 100644 --- a/apps/cowswap-frontend/src/modules/limitOrders/hooks/useLimitOrdersDerivedState.ts +++ b/apps/cowswap-frontend/src/modules/limitOrders/hooks/useLimitOrdersDerivedState.ts @@ -2,10 +2,11 @@ import { useAtomValue, useSetAtom } from 'jotai' import { useEffect } from 'react' import { - limitOrdersRawStateAtom, LimitOrdersDerivedState, limitOrdersDerivedStateAtom, + limitOrdersRawStateAtom, } from 'modules/limitOrders/state/limitOrdersRawStateAtom' +import { TradeType } from 'modules/trade' import { useBuildTradeDerivedState } from 'modules/trade/hooks/useBuildTradeDerivedState' export function useLimitOrdersDerivedState(): LimitOrdersDerivedState { @@ -20,6 +21,6 @@ export function useFillLimitOrdersDerivedState() { const derivedState = useBuildTradeDerivedState(limitOrdersRawStateAtom) useEffect(() => { - updateDerivedState({ ...derivedState, isUnlocked }) + updateDerivedState({ ...derivedState, isUnlocked, tradeType: TradeType.LIMIT_ORDER }) }, [derivedState, updateDerivedState, isUnlocked]) } diff --git a/apps/cowswap-frontend/src/modules/limitOrders/hooks/useLimitOrdersFormState.ts b/apps/cowswap-frontend/src/modules/limitOrders/hooks/useLimitOrdersFormState.ts index ee996f4d13..0343726766 100644 --- a/apps/cowswap-frontend/src/modules/limitOrders/hooks/useLimitOrdersFormState.ts +++ b/apps/cowswap-frontend/src/modules/limitOrders/hooks/useLimitOrdersFormState.ts @@ -1,12 +1,12 @@ import { useAtomValue } from 'jotai' +import { isFractionFalsy } from '@cowprotocol/common-utils' import { Currency, CurrencyAmount, Fraction } from '@uniswap/sdk-core' import { limitRateAtom } from 'modules/limitOrders/state/limitRateAtom' import { useTradeQuote } from 'modules/tradeQuote' import { useSafeMemo } from 'common/hooks/useSafeMemo' -import { isFractionFalsy } from 'utils/isFractionFalsy' import { useLimitOrdersDerivedState } from './useLimitOrdersDerivedState' diff --git a/apps/cowswap-frontend/src/modules/limitOrders/hooks/useSafeBundleFlowContext.ts b/apps/cowswap-frontend/src/modules/limitOrders/hooks/useSafeBundleFlowContext.ts index 1d33afccf9..dcdf51a474 100644 --- a/apps/cowswap-frontend/src/modules/limitOrders/hooks/useSafeBundleFlowContext.ts +++ b/apps/cowswap-frontend/src/modules/limitOrders/hooks/useSafeBundleFlowContext.ts @@ -1,7 +1,7 @@ -import { useTokenContract } from 'legacy/hooks/useContract' +import { useTokenContract } from '@cowprotocol/common-hooks' +import { useSafeAppsSdk } from '@cowprotocol/wallet' import { SafeBundleFlowContext, TradeFlowContext } from 'modules/limitOrders/services/types' -import { useSafeAppsSdk } from 'modules/wallet/web3-react/hooks/useSafeAppsSdk' import { useTradeSpenderAddress } from 'common/hooks/useTradeSpenderAddress' diff --git a/apps/cowswap-frontend/src/modules/limitOrders/hooks/useSetupLimitOrderAmountsFromUrl.ts b/apps/cowswap-frontend/src/modules/limitOrders/hooks/useSetupLimitOrderAmountsFromUrl.ts index 90cd978d61..a94c20fb14 100644 --- a/apps/cowswap-frontend/src/modules/limitOrders/hooks/useSetupLimitOrderAmountsFromUrl.ts +++ b/apps/cowswap-frontend/src/modules/limitOrders/hooks/useSetupLimitOrderAmountsFromUrl.ts @@ -1,6 +1,9 @@ import { useSetAtom } from 'jotai' import { useCallback, useLayoutEffect, useMemo } from 'react' +import { tryParseCurrencyAmount } from '@cowprotocol/common-utils' +import { FractionUtils } from '@cowprotocol/common-utils' +import { getIntOrFloat } from '@cowprotocol/common-utils' import { OrderKind } from '@cowprotocol/cow-sdk' import { Price } from '@uniswap/sdk-core' @@ -12,10 +15,6 @@ import { useLimitOrdersDerivedState } from 'modules/limitOrders/hooks/useLimitOr import { useUpdateActiveRate } from 'modules/limitOrders/hooks/useUpdateActiveRate' import { TRADE_URL_BUY_AMOUNT_KEY, TRADE_URL_SELL_AMOUNT_KEY } from 'modules/trade/const/tradeUrl' -import tryParseCurrencyAmount from 'lib/utils/tryParseCurrencyAmount' -import { FractionUtils } from 'utils/fractionUtils' -import { getIntOrFloat } from 'utils/getIntOrFloat' - /** * Parse sell/buy amount from URL and apply to Limit orders widget * Example: diff --git a/apps/cowswap-frontend/src/modules/limitOrders/hooks/useTradeFlowContext.ts b/apps/cowswap-frontend/src/modules/limitOrders/hooks/useTradeFlowContext.ts index ce62a2556f..488fa09af8 100644 --- a/apps/cowswap-frontend/src/modules/limitOrders/hooks/useTradeFlowContext.ts +++ b/apps/cowswap-frontend/src/modules/limitOrders/hooks/useTradeFlowContext.ts @@ -1,22 +1,24 @@ import { useAtomValue } from 'jotai' +import { GP_VAULT_RELAYER } from '@cowprotocol/common-const' +import { useGP2SettlementContract } from '@cowprotocol/common-hooks' import { OrderClass } from '@cowprotocol/cow-sdk' +import { useGnosisSafeInfo, useWalletDetails, useWalletInfo } from '@cowprotocol/wallet' import { CurrencyAmount, Token } from '@uniswap/sdk-core' import { useWeb3React } from '@web3-react/core' import { useDispatch } from 'react-redux' -import { useGP2SettlementContract } from 'legacy/hooks/useContract' import { AppDispatch } from 'legacy/state' import { useAppData } from 'modules/appData' import { useRateImpact } from 'modules/limitOrders/hooks/useRateImpact' import { TradeFlowContext } from 'modules/limitOrders/services/types' import { limitOrdersSettingsAtom } from 'modules/limitOrders/state/limitOrdersSettingsAtom' +import { useGeneratePermitHook, useIsTokenPermittable } from 'modules/permit' +import { useEnoughBalanceAndAllowance } from 'modules/tokens' +import { TradeType } from 'modules/trade' import { useTradeQuote } from 'modules/tradeQuote' -import { useGnosisSafeInfo, useWalletDetails, useWalletInfo } from 'modules/wallet' - -import { useFeatureFlags } from 'common/hooks/featureFlags/useFeatureFlags' import { useLimitOrdersDerivedState } from './useLimitOrdersDerivedState' @@ -32,7 +34,15 @@ export function useTradeFlowContext(): TradeFlowContext | null { const quoteState = useTradeQuote() const rateImpact = useRateImpact() const settingsState = useAtomValue(limitOrdersSettingsAtom) - const { partialFillsEnabled } = useFeatureFlags() + const permitInfo = useIsTokenPermittable(state.inputCurrency, TradeType.LIMIT_ORDER) + + const checkAllowanceAddress = GP_VAULT_RELAYER[chainId] + const { enoughAllowance } = useEnoughBalanceAndAllowance({ + account, + amount: state.slippageAdjustedSellAmount || undefined, + checkAllowanceAddress, + }) + const generatePermitHook = useGeneratePermitHook() if ( !chainId || @@ -56,8 +66,7 @@ export function useTradeFlowContext(): TradeFlowContext | null { const feeAmount = CurrencyAmount.fromRawAmount(state.inputCurrency, 0) const quoteId = quoteState.response?.id || undefined - // Depends on the feature flag to allow partial fills or not - const partiallyFillable = partialFillsEnabled && settingsState.partialFillsEnabled + const partiallyFillable = settingsState.partialFillsEnabled return { chainId, @@ -66,8 +75,9 @@ export function useTradeFlowContext(): TradeFlowContext | null { isGnosisSafeWallet, dispatch, provider, - appData, rateImpact, + permitInfo: !enoughAllowance ? permitInfo : undefined, + generatePermitHook, postOrderParams: { class: OrderClass.LIMIT, kind: state.orderKind, diff --git a/apps/cowswap-frontend/src/modules/limitOrders/hooks/useUpdateCurrencyAmount.ts b/apps/cowswap-frontend/src/modules/limitOrders/hooks/useUpdateCurrencyAmount.ts index bbc2ede726..17b695c8f9 100644 --- a/apps/cowswap-frontend/src/modules/limitOrders/hooks/useUpdateCurrencyAmount.ts +++ b/apps/cowswap-frontend/src/modules/limitOrders/hooks/useUpdateCurrencyAmount.ts @@ -1,17 +1,17 @@ import { useSetAtom } from 'jotai' import { useCallback } from 'react' +import { FractionUtils } from '@cowprotocol/common-utils' import { OrderKind } from '@cowprotocol/cow-sdk' import { Fraction } from '@uniswap/sdk-core' import { Writeable } from 'types' -import { Field } from 'legacy/state/swap/actions' +import { Field } from 'legacy/state/types' import { useLimitOrdersDerivedState } from 'modules/limitOrders/hooks/useLimitOrdersDerivedState' import { LimitOrdersRawState, updateLimitOrdersRawStateAtom } from 'modules/limitOrders/state/limitOrdersRawStateAtom' -import { FractionUtils } from 'utils/fractionUtils' import { calculateAmountForRate } from 'utils/orderUtils/calculateAmountForRate' type CurrencyAmountProps = { diff --git a/apps/cowswap-frontend/src/modules/limitOrders/pure/DeadlineSelector/index.tsx b/apps/cowswap-frontend/src/modules/limitOrders/pure/DeadlineSelector/index.tsx index be050ea38d..25fb8a440e 100644 --- a/apps/cowswap-frontend/src/modules/limitOrders/pure/DeadlineSelector/index.tsx +++ b/apps/cowswap-frontend/src/modules/limitOrders/pure/DeadlineSelector/index.tsx @@ -1,11 +1,11 @@ import { ChangeEventHandler, useCallback, useEffect, useMemo, useRef, useState } from 'react' +import { ButtonPrimary, ButtonSecondary } from '@cowprotocol/ui' + import { Trans } from '@lingui/macro' import { Menu } from '@reach/menu-button' import { ChevronDown } from 'react-feather' -import { ButtonPrimary, ButtonSecondary } from 'legacy/components/Button' - import { calculateMinMax, formatDateToLocalTime, diff --git a/apps/cowswap-frontend/src/modules/limitOrders/pure/DeadlineSelector/styled.tsx b/apps/cowswap-frontend/src/modules/limitOrders/pure/DeadlineSelector/styled.tsx index 6c89ca55be..28a6f9e1ef 100644 --- a/apps/cowswap-frontend/src/modules/limitOrders/pure/DeadlineSelector/styled.tsx +++ b/apps/cowswap-frontend/src/modules/limitOrders/pure/DeadlineSelector/styled.tsx @@ -3,8 +3,10 @@ import { transparentize } from 'polished' import { X } from 'react-feather' import styled from 'styled-components/macro' +import { UI } from 'common/constants/theme' + export const Wrapper = styled.div<{ inline?: boolean; minHeight?: string }>` - background: ${({ theme }) => theme.grey1}; + background: var(${UI.COLOR_GREY}); border-radius: 16px; padding: 10px 16px; min-height: ${({ minHeight }) => minHeight || '80px'}; @@ -38,7 +40,7 @@ export const Label = styled.span` ` export const Current = styled(MenuButton)<{ $custom?: boolean }>` - color: ${({ theme }) => theme.text1}; + color: var(${UI.COLOR_TEXT1}); font-size: ${({ $custom }) => ($custom ? '12px' : '100%')}; letter-spacing: ${({ $custom }) => ($custom ? '-0.3px' : '0')}; font-weight: 500; @@ -75,7 +77,7 @@ export const Current = styled(MenuButton)<{ $custom?: boolean }>` export const ListWrapper = styled(MenuList)` display: block; - background: ${({ theme }) => theme.bg1}; + background: var(${UI.COLOR_CONTAINER_BG_01}); box-shadow: ${({ theme }) => theme.boxShadow2}; margin: 15px 0 0 0; padding: 10px 15px; @@ -88,7 +90,7 @@ export const ListWrapper = styled(MenuList)` ` export const ListItem = styled(MenuItem)` - color: ${({ theme }) => theme.text1}; + color: var(${UI.COLOR_TEXT1}); background: none; border: 0; outline: none; @@ -111,17 +113,17 @@ export const CustomInput = styled.input` border-radius: 8px; width: 100%; border: 1px solid ${({ theme }) => transparentize(0.7, theme.text1)}; - color: ${({ theme }) => theme.text1}; + color: var(${UI.COLOR_TEXT1}); padding: 4px 8px; outline: 0; - background: ${({ theme }) => theme.bg1}; + background: var(${UI.COLOR_CONTAINER_BG_01}); &::-webkit-calendar-picker-indicator { filter: ${({ theme }) => (theme.darkMode ? 'invert(1)' : 'invert(0)')}; } &::-webkit-datetime-edit { - color: ${({ theme }) => theme.text1}; + color: var(${UI.COLOR_TEXT1}); } &::-webkit-datetime-edit[disabled] { @@ -177,7 +179,7 @@ export const ModalContent = styled.div` align-items: flex-start; justify-content: center; padding: 16px; - background: ${({ theme }) => theme.grey1}; + background: var(${UI.COLOR_GREY}); border-radius: 12px; ` @@ -193,6 +195,6 @@ export const CloseIcon = styled(X)` } > line { - stroke: ${({ theme }) => theme.text1}; + stroke: var(${UI.COLOR_TEXT1}); } ` diff --git a/apps/cowswap-frontend/src/modules/limitOrders/pure/ExecutionPriceTooltip/index.tsx b/apps/cowswap-frontend/src/modules/limitOrders/pure/ExecutionPriceTooltip/index.tsx index cbefe4f3ea..f31603ba88 100644 --- a/apps/cowswap-frontend/src/modules/limitOrders/pure/ExecutionPriceTooltip/index.tsx +++ b/apps/cowswap-frontend/src/modules/limitOrders/pure/ExecutionPriceTooltip/index.tsx @@ -1,11 +1,10 @@ +import { FiatAmount, TokenAmount } from '@cowprotocol/ui' import { Currency, CurrencyAmount, Fraction, Price } from '@uniswap/sdk-core' import { useUsdAmount } from 'modules/usdAmount' import { ExecutionPrice } from 'common/pure/ExecutionPrice' -import { FiatAmount } from 'common/pure/FiatAmount' import { RateTooltipHeader } from 'common/pure/OrderExecutionStatusList' -import { TokenAmount } from 'common/pure/TokenAmount' import { convertAmountToCurrency } from 'utils/orderUtils/calculateExecutionPrice' import * as styledEl from './styled' diff --git a/apps/cowswap-frontend/src/modules/limitOrders/pure/ExecutionPriceTooltip/styled.ts b/apps/cowswap-frontend/src/modules/limitOrders/pure/ExecutionPriceTooltip/styled.ts index beea28b1ad..fa195df8dd 100644 --- a/apps/cowswap-frontend/src/modules/limitOrders/pure/ExecutionPriceTooltip/styled.ts +++ b/apps/cowswap-frontend/src/modules/limitOrders/pure/ExecutionPriceTooltip/styled.ts @@ -1,12 +1,14 @@ import { transparentize } from 'polished' import styled from 'styled-components/macro' +import { UI } from 'common/constants/theme' + export const FeeTooltipWrapper = styled.div` display: flex; flex-flow: column wrap; align-items: center; justify-content: center; - color: ${({ theme }) => theme.text1}; + color: var(${UI.COLOR_TEXT1}); ` export const FeeItem = styled.div<{ highlighted?: boolean; borderTop?: boolean }>` diff --git a/apps/cowswap-frontend/src/modules/limitOrders/pure/InfoBanner/index.tsx b/apps/cowswap-frontend/src/modules/limitOrders/pure/InfoBanner/index.tsx index d41eb8b05b..b65af754c7 100644 --- a/apps/cowswap-frontend/src/modules/limitOrders/pure/InfoBanner/index.tsx +++ b/apps/cowswap-frontend/src/modules/limitOrders/pure/InfoBanner/index.tsx @@ -1,10 +1,10 @@ import { useState, useEffect } from 'react' +import AlertIcon from '@cowprotocol/assets/cow-swap/alert-circle.svg' + import SVG from 'react-inlinesvg' import { HashLink } from 'react-router-hash-link' -import AlertIcon from 'legacy/assets/cow-swap/alert-circle.svg' - import * as styledEl from './styled' export function InfoBanner() { diff --git a/apps/cowswap-frontend/src/modules/limitOrders/pure/InfoBanner/styled.ts b/apps/cowswap-frontend/src/modules/limitOrders/pure/InfoBanner/styled.ts index fe70965313..8c51cd42aa 100644 --- a/apps/cowswap-frontend/src/modules/limitOrders/pure/InfoBanner/styled.ts +++ b/apps/cowswap-frontend/src/modules/limitOrders/pure/InfoBanner/styled.ts @@ -2,6 +2,8 @@ import { transparentize, lighten } from 'polished' import { X } from 'react-feather' import styled from 'styled-components/macro' +import { UI } from 'common/constants/theme' + export const InfoPopup = styled.div` display: flex; position: relative; @@ -34,7 +36,7 @@ export const InfoPopup = styled.div` } .content > a { - color: ${({ theme }) => theme.text1}; + color: var(${UI.COLOR_TEXT1}); text-decoration: underline; &::after { diff --git a/apps/cowswap-frontend/src/modules/limitOrders/pure/LimitOrdersDetails/index.cosmos.tsx b/apps/cowswap-frontend/src/modules/limitOrders/pure/LimitOrdersDetails/index.cosmos.tsx index 776d046c24..66d3058a37 100644 --- a/apps/cowswap-frontend/src/modules/limitOrders/pure/LimitOrdersDetails/index.cosmos.tsx +++ b/apps/cowswap-frontend/src/modules/limitOrders/pure/LimitOrdersDetails/index.cosmos.tsx @@ -1,12 +1,9 @@ import { SetStateAction } from 'jotai' -import { SupportedChainId } from '@cowprotocol/cow-sdk' -import { OrderKind } from '@cowprotocol/cow-sdk' -import { OrderClass } from '@cowprotocol/cow-sdk' +import { COW, GNO } from '@cowprotocol/common-const' +import { OrderClass, OrderKind, SupportedChainId } from '@cowprotocol/cow-sdk' import { CurrencyAmount } from '@uniswap/sdk-core' -import { COW, GNO } from 'legacy/constants/tokens' - import { getAppData } from 'modules/appData' import { defaultLimitOrdersSettings } from 'modules/limitOrders/state/limitOrdersSettingsAtom' import { initLimitRateState } from 'modules/limitOrders/state/limitRateAtom' @@ -19,6 +16,8 @@ const inputCurrency = COW[SupportedChainId.MAINNET] const outputCurrency = GNO[SupportedChainId.MAINNET] const tradeContext: TradeFlowContext = { + permitInfo: undefined, + generatePermitHook: () => Promise.resolve(undefined), postOrderParams: { class: OrderClass.LIMIT, account: '0x000', @@ -37,7 +36,6 @@ const tradeContext: TradeFlowContext = { appData: getAppData(), }, rateImpact: 0, - appData: {} as any, provider: {} as any, settlementContract: {} as any, chainId: 1, @@ -63,7 +61,6 @@ const Fixtures = { executionPrice={null} limitRateState={initLimitRateState()} partiallyFillableOverride={[true, (_?: SetStateAction) => void 0]} - featurePartialFillsEnabled /> ), } diff --git a/apps/cowswap-frontend/src/modules/limitOrders/pure/LimitOrdersDetails/index.tsx b/apps/cowswap-frontend/src/modules/limitOrders/pure/LimitOrdersDetails/index.tsx index 91644315f6..a201d11707 100644 --- a/apps/cowswap-frontend/src/modules/limitOrders/pure/LimitOrdersDetails/index.tsx +++ b/apps/cowswap-frontend/src/modules/limitOrders/pure/LimitOrdersDetails/index.tsx @@ -1,14 +1,16 @@ import React, { useMemo, useState } from 'react' +import ArrowDownImage from '@cowprotocol/assets/cow-swap/arrowDownRight.svg' +import { DEFAULT_DATE_FORMAT } from '@cowprotocol/common-const' +import { formatInputAmount } from '@cowprotocol/common-utils' +import { isAddress, shortenAddress } from '@cowprotocol/common-utils' import { Currency, Price } from '@uniswap/sdk-core' import SVG from 'react-inlinesvg' import styled from 'styled-components/macro' -import ArrowDownImage from 'legacy/assets/cow-swap/arrowDownRight.svg' import { InfoIcon } from 'legacy/components/InfoIcon' import QuestionHelper from 'legacy/components/QuestionHelper' -import { isAddress, shortenAddress } from 'legacy/utils' import { ExecutionPriceTooltip } from 'modules/limitOrders/pure/ExecutionPriceTooltip' import { OrderType } from 'modules/limitOrders/pure/OrderType' @@ -19,17 +21,16 @@ import { PartiallyFillableOverrideDispatcherType } from 'modules/limitOrders/sta import { calculateLimitOrdersDeadline } from 'modules/limitOrders/utils/calculateLimitOrdersDeadline' import { ordersTableFeatures } from 'common/constants/featureFlags' -import { DEFAULT_DATE_FORMAT } from 'common/constants/intl' +import { UI } from 'common/constants/theme' import { ExecutionPrice } from 'common/pure/ExecutionPrice' import { RateInfoParams } from 'common/pure/RateInfo' -import { formatInputAmount } from 'utils/amountFormat' import * as styledEl from './styled' const Wrapper = styled.div` font-size: 13px; font-weight: 400; - color: ${({ theme }) => theme.text1}; + color: var(${UI.COLOR_TEXT1}); padding: 8px; ` @@ -37,7 +38,7 @@ const ArrowDownRight = styled.div` display: flex; opacity: 0.3; margin: 0 3px 0 0; - color: ${({ theme }) => theme.text1}; + color: var(${UI.COLOR_TEXT1}); ` export interface LimitOrdersDetailsProps { rateInfoParams: RateInfoParams @@ -46,19 +47,11 @@ export interface LimitOrdersDetailsProps { executionPrice: Price | null limitRateState: LimitRateState partiallyFillableOverride: PartiallyFillableOverrideDispatcherType - featurePartialFillsEnabled: boolean } export function LimitOrdersDetails(props: LimitOrdersDetailsProps) { - const { - executionPrice, - tradeContext, - settingsState, - rateInfoParams, - limitRateState, - partiallyFillableOverride, - featurePartialFillsEnabled, - } = props + const { executionPrice, tradeContext, settingsState, rateInfoParams, limitRateState, partiallyFillableOverride } = + props const { account, recipient, recipientAddressOrName, partiallyFillable } = tradeContext.postOrderParams const { feeAmount, activeRate, marketRate } = limitRateState @@ -135,11 +128,7 @@ export function LimitOrdersDetails(props: LimitOrdersDetailsProps) { Active */} - + {recipientAddressOrName && recipient !== account && (
diff --git a/apps/cowswap-frontend/src/modules/limitOrders/pure/LimitOrdersDetails/styled.tsx b/apps/cowswap-frontend/src/modules/limitOrders/pure/LimitOrdersDetails/styled.tsx index 4d77475eab..5cb898a3ef 100644 --- a/apps/cowswap-frontend/src/modules/limitOrders/pure/LimitOrdersDetails/styled.tsx +++ b/apps/cowswap-frontend/src/modules/limitOrders/pure/LimitOrdersDetails/styled.tsx @@ -2,6 +2,7 @@ import styled from 'styled-components/macro' import { QuestionWrapper } from 'legacy/components/QuestionHelper' +import { UI } from 'common/constants/theme' import { RateInfo } from 'common/pure/RateInfo' export const DetailsRow = styled.div` @@ -41,7 +42,7 @@ export const DetailsRow = styled.div` export const StyledRateInfo = styled(RateInfo)` font-size: 13px; font-weight: 400; - color: ${({ theme }) => theme.text1}; + color: var(${UI.COLOR_TEXT1}); min-height: 24px; gap: 3px; ` diff --git a/apps/cowswap-frontend/src/modules/limitOrders/pure/OrderType/index.tsx b/apps/cowswap-frontend/src/modules/limitOrders/pure/OrderType/index.tsx index 153fd3e834..cc33942ac7 100644 --- a/apps/cowswap-frontend/src/modules/limitOrders/pure/OrderType/index.tsx +++ b/apps/cowswap-frontend/src/modules/limitOrders/pure/OrderType/index.tsx @@ -1,6 +1,7 @@ +import IMAGE_CARET_DOWN from '@cowprotocol/assets/cow-swap/carret-down.svg' + import { Menu } from '@reach/menu-button' -import IMAGE_CARET_DOWN from 'legacy/assets/cow-swap/carret-down.svg' import { InfoIcon } from 'legacy/components/InfoIcon' import { DetailsRow } from 'modules/limitOrders/pure/LimitOrdersDetails/styled' @@ -10,7 +11,6 @@ import * as styledEl from './styled' export type OrderTypeProps = { isPartiallyFillable: boolean - featurePartialFillsEnabled: boolean partiallyFillableOverride: PartiallyFillableOverrideDispatcherType className?: string } @@ -41,11 +41,7 @@ export function OrderType(props: OrderTypeProps) { const LABELS = ['Partially fillable', 'Fill or kill'] -function OrderTypePicker({ - isPartiallyFillable, - featurePartialFillsEnabled, - partiallyFillableOverride, -}: OrderTypeProps) { +function OrderTypePicker({ isPartiallyFillable, partiallyFillableOverride }: OrderTypeProps) { const [override, setOverride] = partiallyFillableOverride const showPartiallyFillable = override ?? isPartiallyFillable @@ -53,21 +49,18 @@ function OrderTypePicker({ const [labelText] = showPartiallyFillable ? LABELS : [...LABELS].reverse() const onSelect = (label: string) => setOverride(label === LABELS[0]) - const disabled = !featurePartialFillsEnabled return ( {({ isExpanded }: { isExpanded: boolean }) => ( - + {labelText} - {!disabled && ( - - )} + diff --git a/apps/cowswap-frontend/src/modules/limitOrders/pure/OrderType/styled.tsx b/apps/cowswap-frontend/src/modules/limitOrders/pure/OrderType/styled.tsx index 7bc48d569f..1360ee5f78 100644 --- a/apps/cowswap-frontend/src/modules/limitOrders/pure/OrderType/styled.tsx +++ b/apps/cowswap-frontend/src/modules/limitOrders/pure/OrderType/styled.tsx @@ -3,12 +3,14 @@ import { transparentize } from 'polished' import SVG from 'react-inlinesvg' import styled from 'styled-components/macro' +import { UI } from 'common/constants/theme' + export const Wrapper = styled.div` position: relative; ` export const LabelText = styled.span` - color: ${({ theme }) => theme.text1}; + color: var(${UI.COLOR_TEXT1}); transition: color 0.15s ease-in-out; ` @@ -19,7 +21,7 @@ export const StyledSVG = styled(SVG)` height: var(--size); > path { - fill: ${({ theme }) => theme.text1}; + fill: var(${UI.COLOR_TEXT1}); transition: fill 0.15s ease-in-out; } @@ -54,7 +56,7 @@ export const StyledMenuButton = styled(MenuButton)` export const StyledMenuList = styled(MenuList)` box-shadow: 0 4px 8px 0 ${({ theme }) => transparentize(0.95, theme.shadow1)}; - background: ${({ theme }) => theme.bg1}; + background: var(${UI.COLOR_CONTAINER_BG_01}); border-radius: 8px; z-index: 2; min-width: 100%; @@ -67,7 +69,7 @@ export const StyledMenuList = styled(MenuList)` export const StyledMenuItem = styled(MenuItem)` padding: 6px 12px; - color: ${({ theme }) => theme.text1}; + color: var(${UI.COLOR_TEXT1}); font-size: 13px; cursor: pointer; border-radius: 8px; diff --git a/apps/cowswap-frontend/src/modules/limitOrders/pure/RateImpactIndicator/index.cosmos.tsx b/apps/cowswap-frontend/src/modules/limitOrders/pure/RateImpactIndicator/index.cosmos.tsx index b37a7bb897..1a960c2370 100644 --- a/apps/cowswap-frontend/src/modules/limitOrders/pure/RateImpactIndicator/index.cosmos.tsx +++ b/apps/cowswap-frontend/src/modules/limitOrders/pure/RateImpactIndicator/index.cosmos.tsx @@ -1,4 +1,4 @@ -import { GNO_GNOSIS_CHAIN } from 'legacy/utils/gnosis_chain/constants' +import { GNO_GNOSIS_CHAIN } from '@cowprotocol/common-const' import { RateImpactIndicator } from './index' diff --git a/apps/cowswap-frontend/src/modules/limitOrders/pure/RateImpactIndicator/index.tsx b/apps/cowswap-frontend/src/modules/limitOrders/pure/RateImpactIndicator/index.tsx index c6eef7184d..b91dec12ad 100644 --- a/apps/cowswap-frontend/src/modules/limitOrders/pure/RateImpactIndicator/index.tsx +++ b/apps/cowswap-frontend/src/modules/limitOrders/pure/RateImpactIndicator/index.tsx @@ -1,13 +1,13 @@ +import { TokenSymbol } from '@cowprotocol/ui' +import { MouseoverTooltipContent } from '@cowprotocol/ui' import { Currency } from '@uniswap/sdk-core' import { AlertTriangle } from 'react-feather' import styled from 'styled-components/macro' -import { MouseoverTooltipContent } from 'legacy/components/Tooltip' - import { LOW_RATE_THRESHOLD_PERCENT } from 'modules/limitOrders/const/trade' -import { TokenSymbol } from 'common/pure/TokenSymbol' +import { UI } from 'common/constants/theme' interface RateImpactProps { rateImpact: number @@ -21,8 +21,8 @@ const PercentBox = styled.span<{ isPositive: boolean; isTooLowRate: boolean }>` display: inline-flex; align-items: center; gap: 2px; - color: ${({ isPositive, isTooLowRate, theme }) => - isPositive ? theme.success : isTooLowRate ? theme.danger : theme.text1}; + color: ${({ isPositive, isTooLowRate }) => + isPositive ? `var(${UI.COLOR_SUCCESS})` : isTooLowRate ? `var(${UI.COLOR_DANGER})` : `var(${UI.COLOR_TEXT1})`}; ` const ImpactTooltip = styled.span` display: block; diff --git a/apps/cowswap-frontend/src/modules/limitOrders/pure/RateImpactWarning/index.cosmos.tsx b/apps/cowswap-frontend/src/modules/limitOrders/pure/RateImpactWarning/index.cosmos.tsx index 2f8500fc93..234e81092a 100644 --- a/apps/cowswap-frontend/src/modules/limitOrders/pure/RateImpactWarning/index.cosmos.tsx +++ b/apps/cowswap-frontend/src/modules/limitOrders/pure/RateImpactWarning/index.cosmos.tsx @@ -1,7 +1,6 @@ +import { COW } from '@cowprotocol/common-const' import { SupportedChainId } from '@cowprotocol/cow-sdk' -import { COW } from 'legacy/constants/tokens' - import { RateImpactWarning } from './index' const Fixtures = { diff --git a/apps/cowswap-frontend/src/modules/limitOrders/pure/RateImpactWarning/index.tsx b/apps/cowswap-frontend/src/modules/limitOrders/pure/RateImpactWarning/index.tsx index 3a831ed7fc..0b62777663 100644 --- a/apps/cowswap-frontend/src/modules/limitOrders/pure/RateImpactWarning/index.tsx +++ b/apps/cowswap-frontend/src/modules/limitOrders/pure/RateImpactWarning/index.tsx @@ -1,3 +1,4 @@ +import { TokenSymbol } from '@cowprotocol/ui' import { Currency } from '@uniswap/sdk-core' import { transparentize, lighten, darken } from 'polished' @@ -6,7 +7,7 @@ import styled from 'styled-components/macro' import { LOW_RATE_THRESHOLD_PERCENT } from 'modules/limitOrders/const/trade' -import { TokenSymbol } from 'common/pure/TokenSymbol' +import { UI } from 'common/constants/theme' interface RateImpactAcknowledge { withAcknowledge: boolean @@ -41,7 +42,7 @@ const ReadMoreLink = styled.a` text-decoration: underline; &:hover { - color: ${({ theme }) => theme.text1}; + color: var(${UI.COLOR_TEXT1}); } ` diff --git a/apps/cowswap-frontend/src/modules/limitOrders/pure/Settings/index.cosmos.tsx b/apps/cowswap-frontend/src/modules/limitOrders/pure/Settings/index.cosmos.tsx index 99857c61ee..df49f8cc0c 100644 --- a/apps/cowswap-frontend/src/modules/limitOrders/pure/Settings/index.cosmos.tsx +++ b/apps/cowswap-frontend/src/modules/limitOrders/pure/Settings/index.cosmos.tsx @@ -8,7 +8,6 @@ const defaultProps: SettingsProps = { deadlineMilliseconds: 200_000, customDeadlineTimestamp: null, }, - featurePartialFillsEnabled: true, onStateChanged(state) { console.log('Settings state changed: ', state) }, diff --git a/apps/cowswap-frontend/src/modules/limitOrders/pure/Settings/index.tsx b/apps/cowswap-frontend/src/modules/limitOrders/pure/Settings/index.tsx index 4fcbca9924..6f5dbe5f3c 100644 --- a/apps/cowswap-frontend/src/modules/limitOrders/pure/Settings/index.tsx +++ b/apps/cowswap-frontend/src/modules/limitOrders/pure/Settings/index.tsx @@ -4,11 +4,10 @@ import { LimitOrdersSettingsState } from '../../state/limitOrdersSettingsAtom' export interface SettingsProps { state: LimitOrdersSettingsState - featurePartialFillsEnabled: boolean onStateChanged: (state: Partial) => void } -export function Settings({ state, featurePartialFillsEnabled, onStateChanged }: SettingsProps) { +export function Settings({ state, onStateChanged }: SettingsProps) { const { expertMode, showRecipient, partialFillsEnabled } = state return ( @@ -41,8 +40,7 @@ export function Settings({ state, featurePartialFillsEnabled, onStateChanged }: amount. } - disabled={!featurePartialFillsEnabled} - value={featurePartialFillsEnabled && partialFillsEnabled} + value={partialFillsEnabled} toggle={() => onStateChanged({ partialFillsEnabled: !partialFillsEnabled })} /> diff --git a/apps/cowswap-frontend/src/modules/limitOrders/pure/Settings/styled.ts b/apps/cowswap-frontend/src/modules/limitOrders/pure/Settings/styled.ts deleted file mode 100644 index aea0048814..0000000000 --- a/apps/cowswap-frontend/src/modules/limitOrders/pure/Settings/styled.ts +++ /dev/null @@ -1,42 +0,0 @@ -import { transparentize } from 'polished' -import styled from 'styled-components/macro' - -export const SettingsTitle = styled.h3` - font-weight: 600; - font-size: 14px; - color: ${({ theme }) => theme.text1}; - margin: 0 0 12px 0; -` - -export const SettingsContainer = styled.div` - margin: 12px 0 0; - padding: 16px; - border-radius: 12px; - box-shadow: ${({ theme }) => theme.boxShadow2}; - border: 1px solid ${({ theme }) => transparentize(0.95, theme.white)}; - background: ${({ theme }) => theme.bg1}; - color: ${({ theme }) => theme.text1}; -` - -export const SettingsBox = styled.div<{ disabled: boolean }>` - display: flex; - justify-content: space-between; - margin-bottom: 10px; - - :last-child { - margin-bottom: 0; - } - - opacity: ${({ disabled }) => (disabled ? '0.7' : '1')}; - pointer-events: ${({ disabled }) => (disabled ? 'none' : '')}; -` - -export const SettingsBoxTitle = styled.div` - display: flex; - align-items: center; - font-weight: 400; - color: ${({ theme }) => theme.text1}; - font-size: 14px; - opacity: 0.85; - margin-right: 2rem; -` diff --git a/apps/cowswap-frontend/src/modules/limitOrders/services/tradeFlow/index.ts b/apps/cowswap-frontend/src/modules/limitOrders/services/tradeFlow/index.ts index fcd22122d1..e6c7baf500 100644 --- a/apps/cowswap-frontend/src/modules/limitOrders/services/tradeFlow/index.ts +++ b/apps/cowswap-frontend/src/modules/limitOrders/services/tradeFlow/index.ts @@ -9,10 +9,10 @@ import { LOW_RATE_THRESHOLD_PERCENT } from 'modules/limitOrders/const/trade' import { PriceImpactDeclineError, TradeFlowContext } from 'modules/limitOrders/services/types' import { LimitOrdersSettingsState } from 'modules/limitOrders/state/limitOrdersSettingsAtom' import { calculateLimitOrdersDeadline } from 'modules/limitOrders/utils/calculateLimitOrdersDeadline' +import { handlePermit } from 'modules/permit' import { presignOrderStep } from 'modules/swap/services/swapFlow/steps/presignOrderStep' import { addPendingOrderStep } from 'modules/trade/utils/addPendingOrderStep' -import { tradeFlowAnalytics } from 'modules/trade/utils/analytics' -import { SwapFlowAnalyticsContext } from 'modules/trade/utils/analytics' +import { SwapFlowAnalyticsContext, tradeFlowAnalytics } from 'modules/trade/utils/analytics' import { logTradeFlow } from 'modules/trade/utils/logger' import { getSwapErrorMessage } from 'modules/trade/utils/swapErrorHelper' @@ -21,9 +21,22 @@ export async function tradeFlow( priceImpact: PriceImpact, settingsState: LimitOrdersSettingsState, confirmPriceImpactWithoutFee: (priceImpact: Percent) => Promise, - beforeTrade?: () => void + beforePermit: () => void, + beforeTrade: () => void ): Promise { - const { account, recipientAddressOrName, sellToken, buyToken } = params.postOrderParams + const { + postOrderParams, + rateImpact, + permitInfo, + provider, + chainId, + allowsOffchainSigning, + settlementContract, + dispatch, + isGnosisSafeWallet, + generatePermitHook, + } = params + const { account, recipientAddressOrName, sellToken, buyToken, appData } = postOrderParams const marketLabel = [sellToken.symbol, buyToken.symbol].join(',') const swapFlowAnalyticsContext: SwapFlowAnalyticsContext = { account, @@ -34,64 +47,76 @@ export async function tradeFlow( } logTradeFlow('LIMIT ORDER FLOW', 'STEP 1: confirm price impact') - const isTooLowRate = params.rateImpact < LOW_RATE_THRESHOLD_PERCENT + const isTooLowRate = rateImpact < LOW_RATE_THRESHOLD_PERCENT if (!isTooLowRate && priceImpact.priceImpact && !(await confirmPriceImpactWithoutFee(priceImpact.priceImpact))) { throw new PriceImpactDeclineError() } - logTradeFlow('LIMIT ORDER FLOW', 'STEP 2: send transaction') - tradeFlowAnalytics.trade(swapFlowAnalyticsContext) - beforeTrade?.() - const validTo = calculateLimitOrdersDeadline(settingsState) try { - logTradeFlow('LIMIT ORDER FLOW', 'STEP 3: sign and post order') + logTradeFlow('LIMIT ORDER FLOW', 'STEP 2: handle permit') + if (permitInfo) beforePermit() + + postOrderParams.appData = await handlePermit({ + permitInfo, + inputToken: sellToken, + account, + appData, + generatePermitHook, + }) + + logTradeFlow('LIMIT ORDER FLOW', 'STEP 3: send transaction') + tradeFlowAnalytics.trade(swapFlowAnalyticsContext) + + beforeTrade() + + logTradeFlow('LIMIT ORDER FLOW', 'STEP 4: sign and post order') const { id: orderId, order } = await signAndPostOrder({ - ...params.postOrderParams, - signer: params.provider.getSigner(), + ...postOrderParams, + signer: provider.getSigner(), validTo, }) - logTradeFlow('LIMIT ORDER FLOW', 'STEP 4: add pending order step') + logTradeFlow('LIMIT ORDER FLOW', 'STEP 5: add pending order step') addPendingOrderStep( { id: orderId, - chainId: params.chainId, + chainId: chainId, order: { ...order, - isHidden: !params.allowsOffchainSigning, + isHidden: !allowsOffchainSigning, }, }, - params.dispatch + dispatch ) - logTradeFlow('LIMIT ORDER FLOW', 'STEP 5: presign order (optional)') - const presignTx = await (params.allowsOffchainSigning + logTradeFlow('LIMIT ORDER FLOW', 'STEP 6: presign order (optional)') + const presignTx = await (allowsOffchainSigning ? Promise.resolve(null) - : presignOrderStep(orderId, params.settlementContract)) + : presignOrderStep(orderId, settlementContract)) - logTradeFlow('LIMIT ORDER FLOW', 'STEP 6: unhide SC order (optional)') + logTradeFlow('LIMIT ORDER FLOW', 'STEP 7: unhide SC order (optional)') if (presignTx) { partialOrderUpdate( { - chainId: params.chainId, + chainId, order: { id: order.id, - presignGnosisSafeTxHash: params.isGnosisSafeWallet ? presignTx.hash : undefined, + presignGnosisSafeTxHash: isGnosisSafeWallet ? presignTx.hash : undefined, isHidden: false, }, }, - params.dispatch + dispatch ) } - logTradeFlow('LIMIT ORDER FLOW', 'STEP 7: Sign order') + logTradeFlow('LIMIT ORDER FLOW', 'STEP 8: Sign order') tradeFlowAnalytics.sign(swapFlowAnalyticsContext) return orderId } catch (error: any) { - logTradeFlow('LIMIT ORDER FLOW', 'STEP 8: ERROR: ', error) + logTradeFlow('LIMIT ORDER FLOW', 'STEP 9: ERROR: ', error) const swapErrorMessage = getSwapErrorMessage(error) tradeFlowAnalytics.error(error, swapErrorMessage, swapFlowAnalyticsContext) diff --git a/apps/cowswap-frontend/src/modules/limitOrders/services/types.ts b/apps/cowswap-frontend/src/modules/limitOrders/services/types.ts index 709933594a..71d0f022e0 100644 --- a/apps/cowswap-frontend/src/modules/limitOrders/services/types.ts +++ b/apps/cowswap-frontend/src/modules/limitOrders/services/types.ts @@ -1,12 +1,12 @@ +import { Erc20, GPv2Settlement } from '@cowprotocol/abis' import { SupportedChainId } from '@cowprotocol/cow-sdk' -import { Erc20, GPv2Settlement } from '@cowswap/abis' import { Web3Provider } from '@ethersproject/providers' import SafeAppsSDK from '@safe-global/safe-apps-sdk' import { AppDispatch } from 'legacy/state' import { PostOrderParams } from 'legacy/utils/trade' -import { AppDataInfo } from 'modules/appData' +import { GeneratePermitHook, IsTokenPermittableResult } from 'modules/permit' export interface TradeFlowContext { // signer changes creates redundant re-renders @@ -16,10 +16,11 @@ export interface TradeFlowContext { chainId: SupportedChainId dispatch: AppDispatch rateImpact: number - appData: AppDataInfo provider: Web3Provider allowsOffchainSigning: boolean isGnosisSafeWallet: boolean + permitInfo: IsTokenPermittableResult + generatePermitHook: GeneratePermitHook } export interface SafeBundleFlowContext extends TradeFlowContext { diff --git a/apps/cowswap-frontend/src/modules/limitOrders/state/limitOrdersRawStateAtom.ts b/apps/cowswap-frontend/src/modules/limitOrders/state/limitOrdersRawStateAtom.ts index fbec1895e0..c0d8afc079 100644 --- a/apps/cowswap-frontend/src/modules/limitOrders/state/limitOrdersRawStateAtom.ts +++ b/apps/cowswap-frontend/src/modules/limitOrders/state/limitOrdersRawStateAtom.ts @@ -1,10 +1,9 @@ import { atom } from 'jotai' import { atomWithStorage } from 'jotai/utils' +import { getJotaiIsolatedStorage } from '@cowprotocol/core' import { OrderKind, SupportedChainId } from '@cowprotocol/cow-sdk' -import { getJotaiIsolatedStorage } from 'jotaiStore' - import { DEFAULT_TRADE_DERIVED_STATE, TradeDerivedState } from 'modules/trade/types/TradeDerivedState' import { ExtendedTradeRawState, getDefaultTradeRawState } from 'modules/trade/types/TradeRawState' diff --git a/apps/cowswap-frontend/src/modules/limitOrders/state/limitOrdersSettingsAtom.ts b/apps/cowswap-frontend/src/modules/limitOrders/state/limitOrdersSettingsAtom.ts index 634d9ebd86..5241831bd5 100644 --- a/apps/cowswap-frontend/src/modules/limitOrders/state/limitOrdersSettingsAtom.ts +++ b/apps/cowswap-frontend/src/modules/limitOrders/state/limitOrdersSettingsAtom.ts @@ -1,7 +1,8 @@ import { atom } from 'jotai' import { atomWithStorage } from 'jotai/utils' -import { getJotaiIsolatedStorage } from 'jotaiStore' +import { getJotaiIsolatedStorage } from '@cowprotocol/core' + import { Milliseconds, Timestamp } from 'types' import { defaultLimitOrderDeadline } from 'modules/limitOrders/pure/DeadlineSelector/deadlines' diff --git a/apps/cowswap-frontend/src/modules/limitOrders/state/limitRateAtom.ts b/apps/cowswap-frontend/src/modules/limitOrders/state/limitRateAtom.ts index 5887799588..66f79dd58c 100644 --- a/apps/cowswap-frontend/src/modules/limitOrders/state/limitRateAtom.ts +++ b/apps/cowswap-frontend/src/modules/limitOrders/state/limitRateAtom.ts @@ -1,9 +1,8 @@ import { atom } from 'jotai' +import { atomWithPartialUpdate } from '@cowprotocol/common-utils' import { Currency, CurrencyAmount, Fraction } from '@uniswap/sdk-core' -import { atomWithPartialUpdate } from 'utils/jotai/atomWithPartialUpdate' - export interface LimitRateState { readonly isLoading: boolean readonly isLoadingMarketRate: boolean diff --git a/apps/cowswap-frontend/src/modules/limitOrders/updaters/InitialPriceUpdater/index.tsx b/apps/cowswap-frontend/src/modules/limitOrders/updaters/InitialPriceUpdater/index.tsx index aa6161f7db..4a7f8d6480 100644 --- a/apps/cowswap-frontend/src/modules/limitOrders/updaters/InitialPriceUpdater/index.tsx +++ b/apps/cowswap-frontend/src/modules/limitOrders/updaters/InitialPriceUpdater/index.tsx @@ -1,9 +1,9 @@ import { useSetAtom } from 'jotai' import { useLayoutEffect, useState } from 'react' -import { Writeable } from 'types' +import { usePrevious } from '@cowprotocol/common-hooks' -import usePrevious from 'legacy/hooks/usePrevious' +import { Writeable } from 'types' import { useGetInitialPrice } from 'modules/limitOrders/hooks/useGetInitialPrice' import { useUpdateActiveRate } from 'modules/limitOrders/hooks/useUpdateActiveRate' diff --git a/apps/cowswap-frontend/src/modules/limitOrders/updaters/QuoteObserverUpdater/index.tsx b/apps/cowswap-frontend/src/modules/limitOrders/updaters/QuoteObserverUpdater/index.tsx index ecfba21327..75fcfa3997 100644 --- a/apps/cowswap-frontend/src/modules/limitOrders/updaters/QuoteObserverUpdater/index.tsx +++ b/apps/cowswap-frontend/src/modules/limitOrders/updaters/QuoteObserverUpdater/index.tsx @@ -1,14 +1,13 @@ import { useSetAtom } from 'jotai' import { useEffect } from 'react' +import { FractionUtils } from '@cowprotocol/common-utils' import { CurrencyAmount, Percent, Price } from '@uniswap/sdk-core' import { updateLimitRateAtom } from 'modules/limitOrders/state/limitRateAtom' import { useDerivedTradeState } from 'modules/trade/hooks/useDerivedTradeState' import { useTradeQuote } from 'modules/tradeQuote' -import { FractionUtils } from 'utils/fractionUtils' - export const LIMIT_ORDERS_PRICE_SLIPPAGE = new Percent(1, 10) // 0.1% export function QuoteObserverUpdater() { diff --git a/apps/cowswap-frontend/src/modules/limitOrders/utils/calculateLimitOrdersDeadline.ts b/apps/cowswap-frontend/src/modules/limitOrders/utils/calculateLimitOrdersDeadline.ts index 6e74aef9d2..d6a120a074 100644 --- a/apps/cowswap-frontend/src/modules/limitOrders/utils/calculateLimitOrdersDeadline.ts +++ b/apps/cowswap-frontend/src/modules/limitOrders/utils/calculateLimitOrdersDeadline.ts @@ -1,9 +1,9 @@ +import { calculateValidTo } from '@cowprotocol/common-utils' + import { Timestamp } from 'types' import { LimitOrdersSettingsState } from 'modules/limitOrders/state/limitOrdersSettingsAtom' -import { calculateValidTo } from 'utils/time' - export function calculateLimitOrdersDeadline(settingsState: LimitOrdersSettingsState): Timestamp { return settingsState.customDeadlineTimestamp ? settingsState.customDeadlineTimestamp diff --git a/apps/cowswap-frontend/src/modules/limitOrders/utils/parsePrice.ts b/apps/cowswap-frontend/src/modules/limitOrders/utils/parsePrice.ts index 1e38742387..75ba2cafc5 100644 --- a/apps/cowswap-frontend/src/modules/limitOrders/utils/parsePrice.ts +++ b/apps/cowswap-frontend/src/modules/limitOrders/utils/parsePrice.ts @@ -1,7 +1,6 @@ +import { DEFAULT_DECIMALS } from '@cowprotocol/common-const' import { Currency } from '@uniswap/sdk-core' -import { DEFAULT_DECIMALS } from 'legacy/constants' - /** * @deprecated use rawToTokenAmount */ diff --git a/apps/cowswap-frontend/src/modules/mainMenu/constants/mainMenu.tsx b/apps/cowswap-frontend/src/modules/mainMenu/constants/mainMenu.tsx index abf730ceb5..d7f223602f 100644 --- a/apps/cowswap-frontend/src/modules/mainMenu/constants/mainMenu.tsx +++ b/apps/cowswap-frontend/src/modules/mainMenu/constants/mainMenu.tsx @@ -1,21 +1,26 @@ -import { Globe } from 'react-feather' - -import IMAGE_CODE from 'legacy/assets/cow-swap/code.svg' -import IMAGE_COOKIE_POLICY from 'legacy/assets/cow-swap/cookie-policy.svg' -import IMAGE_DISCORD from 'legacy/assets/cow-swap/discord.svg' -import IMAGE_DOCS from 'legacy/assets/cow-swap/doc.svg' -import IMAGE_GAME from 'legacy/assets/cow-swap/game.gif' -import IMAGE_INFO from 'legacy/assets/cow-swap/info.svg' -import IMAGE_SLICER from 'legacy/assets/cow-swap/ninja-cow.png' -import IMAGE_PIE from 'legacy/assets/cow-swap/pie.svg' -import IMAGE_PRIVACY_POLICY from 'legacy/assets/cow-swap/privacy-policy.svg' -import IMAGE_TERMS_AND_CONDITIONS from 'legacy/assets/cow-swap/terms-and-conditions.svg' -import IMAGE_TWITTER from 'legacy/assets/cow-swap/twitter.svg' -import { CONTRACTS_CODE_LINK, DISCORD_LINK, DOCS_LINK, DUNE_DASHBOARD_LINK, TWITTER_LINK } from 'legacy/constants' -import { ExternalLink } from 'legacy/theme' -import { getExplorerBaseUrl } from 'legacy/utils/explorer' +import IMAGE_CODE from '@cowprotocol/assets/cow-swap/code.svg' +import IMAGE_COOKIE_POLICY from '@cowprotocol/assets/cow-swap/cookie-policy.svg' +import IMAGE_DISCORD from '@cowprotocol/assets/cow-swap/discord.svg' +import IMAGE_DOCS from '@cowprotocol/assets/cow-swap/doc.svg' +import IMAGE_GAME from '@cowprotocol/assets/cow-swap/game.gif' +import IMAGE_INFO from '@cowprotocol/assets/cow-swap/info.svg' +import IMAGE_SLICER from '@cowprotocol/assets/cow-swap/ninja-cow.png' +import IMAGE_PIE from '@cowprotocol/assets/cow-swap/pie.svg' +import IMAGE_PRIVACY_POLICY from '@cowprotocol/assets/cow-swap/privacy-policy.svg' +import IMAGE_TERMS_AND_CONDITIONS from '@cowprotocol/assets/cow-swap/terms-and-conditions.svg' +import IMAGE_TWITTER from '@cowprotocol/assets/cow-swap/twitter.svg' +import { + CONTRACTS_CODE_LINK, + DISCORD_LINK, + DOCS_LINK, + DUNE_DASHBOARD_LINK, + TWITTER_LINK, +} from '@cowprotocol/common-const' +import { getExplorerBaseUrl } from '@cowprotocol/common-utils' +import { ExternalLink } from '@cowprotocol/ui' +import { useWalletInfo } from '@cowprotocol/wallet' -import { useWalletInfo } from 'modules/wallet' +import { Globe } from 'react-feather' import { Routes } from 'common/constants/routes' @@ -60,6 +65,12 @@ export const MAIN_MENU: MenuTreeItem[] = [ title: 'Limit orders', url: Routes.LIMIT_ORDER, }, + { + id: MainMenuItemId.ADVANCED_ORDERS, + kind: MenuItemKind.PARAMETRIZED_LINK, + title: 'TWAP orders', + url: Routes.ADVANCED_ORDERS, + }, ], }, ], diff --git a/apps/cowswap-frontend/src/modules/mainMenu/hooks.ts b/apps/cowswap-frontend/src/modules/mainMenu/hooks.ts deleted file mode 100644 index 7612906103..0000000000 --- a/apps/cowswap-frontend/src/modules/mainMenu/hooks.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { useMemo } from 'react' - -import { useIsAdvancedOrdersEnabled } from 'common/hooks/useIsAdvancedOrdersEnabled' - -import { MenuTreeItem } from './types' -import { buildMainMenuTreeItems } from './utils' - -export function useMenuItems(): MenuTreeItem[] { - const isAdvancedOrdersEnabled = !!useIsAdvancedOrdersEnabled() - - return useMemo(() => buildMainMenuTreeItems({ isAdvancedOrdersEnabled }), [isAdvancedOrdersEnabled]) -} diff --git a/apps/cowswap-frontend/src/modules/mainMenu/index.ts b/apps/cowswap-frontend/src/modules/mainMenu/index.ts index 52c64f81db..28508e16a2 100644 --- a/apps/cowswap-frontend/src/modules/mainMenu/index.ts +++ b/apps/cowswap-frontend/src/modules/mainMenu/index.ts @@ -1,4 +1,2 @@ export * from './constants/mainMenu' export * from './types' -export * from './utils' -export * from './hooks' diff --git a/apps/cowswap-frontend/src/modules/mainMenu/pure/MenuTree/index.tsx b/apps/cowswap-frontend/src/modules/mainMenu/pure/MenuTree/index.tsx index 04bf386858..b5ba054f26 100644 --- a/apps/cowswap-frontend/src/modules/mainMenu/pure/MenuTree/index.tsx +++ b/apps/cowswap-frontend/src/modules/mainMenu/pure/MenuTree/index.tsx @@ -1,27 +1,30 @@ +import IMAGE_MOON from '@cowprotocol/assets/cow-swap/moon.svg' +import IMAGE_SUN from '@cowprotocol/assets/cow-swap/sun.svg' +import { ExternalLink as ExternalLinkComponent } from '@cowprotocol/ui' + import SVG from 'react-inlinesvg' -import IMAGE_MOON from 'legacy/assets/cow-swap/moon.svg' -import IMAGE_SUN from 'legacy/assets/cow-swap/sun.svg' import { HeaderLinks as Wrapper, StyledNavLink } from 'legacy/components/Header/styled' import MenuDropdown from 'legacy/components/MenuDropdown' import { MenuSection, MenuTitle } from 'legacy/components/MenuDropdown/styled' -import { ExternalLink as ExternalLinkComponent } from 'legacy/theme/components' import { - DropDownItem, - ParametrizedLink, CustomItem, + DropDownItem, ExternalLink, InternalLink, MainMenuContext, MenuItemKind, MenuLink, MenuTreeItem, + ParametrizedLink, } from 'modules/mainMenu/types' import { parameterizeTradeRoute } from 'modules/trade/utils/parameterizeTradeRoute' import { RoutesValues } from 'common/constants/routes' +import { MAIN_MENU } from '../../constants/mainMenu' + // Assets // TODO: decompose the file @@ -164,12 +167,12 @@ function MenuItemWithDropDown(props: MenuItemWithDropDownProps) { } export interface MenuTreeProps { - items: MenuTreeItem[] + items?: MenuTreeItem[] context: MainMenuContext isMobileMenuOpen: boolean } -export function MenuTree({ items, isMobileMenuOpen, context }: MenuTreeProps) { +export function MenuTree({ items = MAIN_MENU, isMobileMenuOpen, context }: MenuTreeProps) { return ( {items.map((menuItem, index) => { diff --git a/apps/cowswap-frontend/src/modules/mainMenu/utils.ts b/apps/cowswap-frontend/src/modules/mainMenu/utils.ts deleted file mode 100644 index 4cb760db8b..0000000000 --- a/apps/cowswap-frontend/src/modules/mainMenu/utils.ts +++ /dev/null @@ -1,34 +0,0 @@ -import cloneDeep from 'clone-deep' - -import { Routes } from 'common/constants/routes' - -import { MAIN_MENU } from './constants/mainMenu' -import { DropDownItem, MainMenuItemId, MenuItemKind, MenuTreeItem } from './types' - -const ADVANCED_ORDERS_MENU_TITLE = 'TWAP orders' - -export type BuildMainMenuTreeItemsParams = { - isAdvancedOrdersEnabled: boolean -} - -export function buildMainMenuTreeItems({ isAdvancedOrdersEnabled }: BuildMainMenuTreeItemsParams): MenuTreeItem[] { - if (!isAdvancedOrdersEnabled) { - return MAIN_MENU - } - - // Make a deep copy to avoid mutating original - const mainMenuCopy = cloneDeep(MAIN_MENU) - - // Assume trade menu is at the first position - const [tradeMenu] = mainMenuCopy - - // Add to the bottom of the list - ;(tradeMenu as DropDownItem).items[0].links.push({ - id: MainMenuItemId.ADVANCED_ORDERS, - kind: MenuItemKind.PARAMETRIZED_LINK, - title: ADVANCED_ORDERS_MENU_TITLE, - url: Routes.ADVANCED_ORDERS, - }) - - return mainMenuCopy -} diff --git a/apps/cowswap-frontend/src/modules/operations/bundle/buildApproveTx.ts b/apps/cowswap-frontend/src/modules/operations/bundle/buildApproveTx.ts index 7a2e6ac24b..abd22db931 100644 --- a/apps/cowswap-frontend/src/modules/operations/bundle/buildApproveTx.ts +++ b/apps/cowswap-frontend/src/modules/operations/bundle/buildApproveTx.ts @@ -1,4 +1,4 @@ -import { Erc20 } from '@cowswap/abis' +import { Erc20 } from '@cowprotocol/abis' import { Currency, CurrencyAmount } from '@uniswap/sdk-core' import { estimateApprove } from 'common/hooks/useApproveCallback' diff --git a/apps/cowswap-frontend/src/modules/operations/bundle/buildPresignTx.ts b/apps/cowswap-frontend/src/modules/operations/bundle/buildPresignTx.ts index 49f9fcc256..d4157a7d5b 100644 --- a/apps/cowswap-frontend/src/modules/operations/bundle/buildPresignTx.ts +++ b/apps/cowswap-frontend/src/modules/operations/bundle/buildPresignTx.ts @@ -1,4 +1,4 @@ -import { GPv2Settlement } from '@cowswap/abis' +import { GPv2Settlement } from '@cowprotocol/abis' export type BuildPresignTxParams = { orderId: string diff --git a/apps/cowswap-frontend/src/modules/operations/bundle/buildWrapTx.ts b/apps/cowswap-frontend/src/modules/operations/bundle/buildWrapTx.ts index e0d9e9d577..0adeb8e0c2 100644 --- a/apps/cowswap-frontend/src/modules/operations/bundle/buildWrapTx.ts +++ b/apps/cowswap-frontend/src/modules/operations/bundle/buildWrapTx.ts @@ -1,4 +1,4 @@ -import { Weth } from '@cowswap/abis' +import { Weth } from '@cowprotocol/abis' export type BuildWrapTxParams = { wrappedNativeContract: Weth diff --git a/apps/cowswap-frontend/src/modules/orders/hooks/useSWROrdersRequest.ts b/apps/cowswap-frontend/src/modules/orders/hooks/useSWROrdersRequest.ts index 49f4fe2d97..d3fada025a 100644 --- a/apps/cowswap-frontend/src/modules/orders/hooks/useSWROrdersRequest.ts +++ b/apps/cowswap-frontend/src/modules/orders/hooks/useSWROrdersRequest.ts @@ -1,8 +1,7 @@ import { useMemo } from 'react' -import { AMOUNT_OF_ORDERS_TO_FETCH } from 'legacy/constants' - -import { useWalletInfo } from 'modules/wallet' +import { AMOUNT_OF_ORDERS_TO_FETCH } from '@cowprotocol/common-const' +import { useWalletInfo } from '@cowprotocol/wallet' export function useSWROrdersRequest(): { owner: string; limit: number } | null { const { account } = useWalletInfo() diff --git a/apps/cowswap-frontend/src/modules/orders/hooks/useSWRProdOrders.ts b/apps/cowswap-frontend/src/modules/orders/hooks/useSWRProdOrders.ts index da01743db6..0e438f14bf 100644 --- a/apps/cowswap-frontend/src/modules/orders/hooks/useSWRProdOrders.ts +++ b/apps/cowswap-frontend/src/modules/orders/hooks/useSWRProdOrders.ts @@ -1,14 +1,12 @@ import { useMemo } from 'react' +import { GP_ORDER_UPDATE_INTERVAL } from '@cowprotocol/common-const' +import { isBarnBackendEnv } from '@cowprotocol/common-utils' import { EnrichedOrder } from '@cowprotocol/cow-sdk' +import { useWalletInfo } from '@cowprotocol/wallet' import useSWR from 'swr' -import { GP_ORDER_UPDATE_INTERVAL } from 'legacy/constants' -import { isBarnBackendEnv } from 'legacy/utils/environments' - -import { useWalletInfo } from 'modules/wallet' - import { getOrders } from 'api/gnosisProtocol' import { useApiOrders } from './useApiOrders' diff --git a/apps/cowswap-frontend/src/modules/orders/hooks/useTokensForOrdersList.ts b/apps/cowswap-frontend/src/modules/orders/hooks/useTokensForOrdersList.ts index e3e42c175d..5d1174e575 100644 --- a/apps/cowswap-frontend/src/modules/orders/hooks/useTokensForOrdersList.ts +++ b/apps/cowswap-frontend/src/modules/orders/hooks/useTokensForOrdersList.ts @@ -1,12 +1,13 @@ import { useCallback, useRef } from 'react' +import { useWalletInfo } from '@cowprotocol/wallet' import { Token } from '@uniswap/sdk-core' import { useAllTokens } from 'legacy/hooks/Tokens' import { useTokenLazy } from 'legacy/hooks/useTokenLazy' -import { TokensByAddress, TokenWithLogo } from 'modules/tokensList/state/tokensListAtom' -import { useWalletInfo } from 'modules/wallet' +import { TokensByAddress } from 'modules/tokensList/state/tokensListAtom' +import { TokenWithLogo } from 'modules/tokensList/types' import { getTokenFromMapping } from 'utils/orderUtils/getTokenFromMapping' diff --git a/apps/cowswap-frontend/src/modules/ordersTable/containers/MultipleCancellationMenu/index.tsx b/apps/cowswap-frontend/src/modules/ordersTable/containers/MultipleCancellationMenu/index.tsx index cb738c2a21..760b94f5b9 100644 --- a/apps/cowswap-frontend/src/modules/ordersTable/containers/MultipleCancellationMenu/index.tsx +++ b/apps/cowswap-frontend/src/modules/ordersTable/containers/MultipleCancellationMenu/index.tsx @@ -1,12 +1,13 @@ import { useAtomValue, useSetAtom } from 'jotai' import { useCallback, useEffect } from 'react' +import { useWalletDetails } from '@cowprotocol/wallet' + import { transparentize } from 'polished' import { Trash2 } from 'react-feather' import styled from 'styled-components/macro' -import { useWalletDetails } from 'modules/wallet' - +import { UI } from 'common/constants/theme' import { useMultipleOrdersCancellation } from 'common/hooks/useMultipleOrdersCancellation' import { ordersToCancelAtom, updateOrdersToCancelAtom } from 'common/hooks/useMultipleOrdersCancellation/state' import { isOrderOffChainCancellable } from 'common/utils/isOrderOffChainCancellable' @@ -61,7 +62,7 @@ const ActionButton = styled.button` const TextButton = styled.button` display: inline-block; - color: ${({ theme }) => theme.text1}; + color: var(${UI.COLOR_TEXT1}); font-size: 13px; padding: 5px 10px; cursor: pointer; diff --git a/apps/cowswap-frontend/src/modules/ordersTable/containers/OrdersReceiptModal/index.tsx b/apps/cowswap-frontend/src/modules/ordersTable/containers/OrdersReceiptModal/index.tsx index e13b1738ed..4cc7b9f947 100644 --- a/apps/cowswap-frontend/src/modules/ordersTable/containers/OrdersReceiptModal/index.tsx +++ b/apps/cowswap-frontend/src/modules/ordersTable/containers/OrdersReceiptModal/index.tsx @@ -1,13 +1,12 @@ +import { useENS } from '@cowprotocol/ens' +import { useWalletInfo } from '@cowprotocol/wallet' import { CurrencyAmount } from '@uniswap/sdk-core' import JSBI from 'jsbi' -import useENS from 'legacy/hooks/useENS' - import { PendingOrdersPrices } from 'modules/orders/state/pendingOrdersPricesAtom' import { ReceiptModal } from 'modules/ordersTable/pure/ReceiptModal' import { useTwapOrderById, useTwapOrderByChildId } from 'modules/twap' -import { useWalletInfo } from 'modules/wallet' import { calculatePrice } from 'utils/orderUtils/calculatePrice' diff --git a/apps/cowswap-frontend/src/modules/ordersTable/containers/OrdersTableWidget/hooks/useGetOrdersToCheckPendingPermit.ts b/apps/cowswap-frontend/src/modules/ordersTable/containers/OrdersTableWidget/hooks/useGetOrdersToCheckPendingPermit.ts new file mode 100644 index 0000000000..444c72662b --- /dev/null +++ b/apps/cowswap-frontend/src/modules/ordersTable/containers/OrdersTableWidget/hooks/useGetOrdersToCheckPendingPermit.ts @@ -0,0 +1,34 @@ +import { useMemo } from 'react' + +import { SupportedChainId } from '@cowprotocol/cow-sdk' + +import { BalancesAndAllowances } from 'modules/tokens' + +import { ParsedOrder } from 'utils/orderUtils/parseOrder' + +import { OrdersTableList } from './useOrdersTableList' + +import { getOrderParams } from '../../../pure/OrdersTableContainer/utils/getOrderParams' +import { isParsedOrder } from '../../../utils/orderTableGroupUtils' + +export function useGetOrdersToCheckPendingPermit( + ordersList: OrdersTableList, + chainId: SupportedChainId, + balancesAndAllowances: BalancesAndAllowances +) { + return useMemo(() => { + // Pick only the pending orders + return ordersList.pending.reduce((acc: ParsedOrder[], item) => { + // Only do it for regular orders (not TWAP) + if (isParsedOrder(item)) { + const { hasEnoughAllowance } = getOrderParams(chainId, balancesAndAllowances, item) + + // Only if the order has not enough allowance + if (hasEnoughAllowance === false) { + acc.push(item) + } + } + return acc + }, []) + }, [balancesAndAllowances, chainId, ordersList.pending]) +} diff --git a/apps/cowswap-frontend/src/modules/ordersTable/containers/OrdersTableWidget/hooks/useOrdersTableList.ts b/apps/cowswap-frontend/src/modules/ordersTable/containers/OrdersTableWidget/hooks/useOrdersTableList.ts index d42302c4f1..186e89fe5e 100644 --- a/apps/cowswap-frontend/src/modules/ordersTable/containers/OrdersTableWidget/hooks/useOrdersTableList.ts +++ b/apps/cowswap-frontend/src/modules/ordersTable/containers/OrdersTableWidget/hooks/useOrdersTableList.ts @@ -3,7 +3,7 @@ import { useMemo } from 'react' import { Order, PENDING_STATES } from 'legacy/state/orders/actions' import { groupOrdersTable } from '../../../utils/groupOrdersTable' -import { getParsedOrderFromItem, isParsedOrder, OrderTableItem } from '../../../utils/orderTableGroupUtils' +import { getParsedOrderFromTableItem, isParsedOrder, OrderTableItem } from '../../../utils/orderTableGroupUtils' export interface OrdersTableList { pending: OrderTableItem[] @@ -11,8 +11,8 @@ export interface OrdersTableList { } const ordersSorter = (a: OrderTableItem, b: OrderTableItem) => { - const aCreationTime = getParsedOrderFromItem(a).creationTime - const bCreationTime = getParsedOrderFromItem(b).creationTime + const aCreationTime = getParsedOrderFromTableItem(a).creationTime + const bCreationTime = getParsedOrderFromTableItem(b).creationTime return bCreationTime.getTime() - aCreationTime.getTime() } diff --git a/apps/cowswap-frontend/src/modules/ordersTable/containers/OrdersTableWidget/hooks/useOrdersTableTokenApprove.test.ts b/apps/cowswap-frontend/src/modules/ordersTable/containers/OrdersTableWidget/hooks/useOrdersTableTokenApprove.test.ts index bb3b468d14..c93d059593 100644 --- a/apps/cowswap-frontend/src/modules/ordersTable/containers/OrdersTableWidget/hooks/useOrdersTableTokenApprove.test.ts +++ b/apps/cowswap-frontend/src/modules/ordersTable/containers/OrdersTableWidget/hooks/useOrdersTableTokenApprove.test.ts @@ -1,8 +1,8 @@ import { useEffect } from 'react' -import { renderHook } from '@testing-library/react-hooks' +import { WETH_GOERLI } from '@cowprotocol/common-const' -import { WETH_GOERLI } from 'legacy/utils/goerli/constants' +import { renderHook } from '@testing-library/react-hooks' import { useTradeApproveCallback } from 'common/containers/TradeApprove' diff --git a/apps/cowswap-frontend/src/modules/ordersTable/containers/OrdersTableWidget/index.tsx b/apps/cowswap-frontend/src/modules/ordersTable/containers/OrdersTableWidget/index.tsx index 2c196c3808..d98cc04619 100644 --- a/apps/cowswap-frontend/src/modules/ordersTable/containers/OrdersTableWidget/index.tsx +++ b/apps/cowswap-frontend/src/modules/ordersTable/containers/OrdersTableWidget/index.tsx @@ -1,10 +1,12 @@ import { useAtomValue, useSetAtom } from 'jotai' import { useCallback, useEffect, useMemo } from 'react' +import { GP_VAULT_RELAYER } from '@cowprotocol/common-const' +import { useIsSafeViaWc, useWalletDetails, useWalletInfo } from '@cowprotocol/wallet' + import { useLocation, useNavigate } from 'react-router-dom' import styled from 'styled-components/macro' -import { GP_VAULT_RELAYER } from 'legacy/constants' import { Order } from 'legacy/state/orders/actions' import { pendingOrdersPricesAtom } from 'modules/orders/state/pendingOrdersPricesAtom' @@ -15,20 +17,22 @@ import { OrdersReceiptModal } from 'modules/ordersTable/containers/OrdersReceipt import { useSelectReceiptOrder } from 'modules/ordersTable/containers/OrdersReceiptModal/hooks' import { OrderActions } from 'modules/ordersTable/pure/OrdersTableContainer/types' import { buildOrdersTableUrl, parseOrdersTableUrl } from 'modules/ordersTable/utils/buildOrdersTableUrl' +import { PendingPermitUpdater, useGetOrdersPermitStatus } from 'modules/permit' import { useBalancesAndAllowances } from 'modules/tokens' -import { useIsSafeViaWc, useWalletDetails, useWalletInfo } from 'modules/wallet' import { useCancelOrder } from 'common/hooks/useCancelOrder' +import { useCategorizeRecentActivity } from 'common/hooks/useCategorizeRecentActivity' import { ordersToCancelAtom, updateOrdersToCancelAtom } from 'common/hooks/useMultipleOrdersCancellation/state' import { CancellableOrder } from 'common/utils/isOrderCancellable' import { ParsedOrder } from 'utils/orderUtils/parseOrder' +import { useGetOrdersToCheckPendingPermit } from './hooks/useGetOrdersToCheckPendingPermit' import { OrdersTableList, useOrdersTableList } from './hooks/useOrdersTableList' import { useOrdersTableTokenApprove } from './hooks/useOrdersTableTokenApprove' import { useValidatePageUrlParams } from './hooks/useValidatePageUrlParams' import { OrdersTableContainer, TabOrderTypes } from '../../pure/OrdersTableContainer' -import { getParsedOrderFromItem, OrderTableItem, tableItemsToOrders } from '../../utils/orderTableGroupUtils' +import { getParsedOrderFromTableItem, OrderTableItem, tableItemsToOrders } from '../../utils/orderTableGroupUtils' function getOrdersListByIndex(ordersList: OrdersTableList, id: string): OrderTableItem[] { return id === OPEN_TAB.id ? ordersList.pending : ordersList.history @@ -71,6 +75,7 @@ export function OrdersTableWidget({ const getSpotPrice = useGetSpotPrice() const selectReceiptOrder = useSelectReceiptOrder() const isSafeViaWc = useIsSafeViaWc() + const ordersPermitStatus = useGetOrdersPermitStatus() const spender = useMemo(() => (chainId ? GP_VAULT_RELAYER[chainId] : undefined), [chainId]) @@ -99,11 +104,12 @@ export function OrdersTableWidget({ const tokens = useMemo(() => { const pendingOrders = isOpenOrdersTab ? ordersList.pending : [] - return pendingOrders.map((item) => getParsedOrderFromItem(item).inputToken) + return pendingOrders.map((item) => getParsedOrderFromTableItem(item).inputToken) }, [isOpenOrdersTab, ordersList.pending]) // Get effective balance const balancesAndAllowances = useBalancesAndAllowances({ account, spender, tokens }) + const { pendingActivity } = useCategorizeRecentActivity() const toggleOrdersForCancellation = useCallback( (orders: ParsedOrder[]) => { @@ -145,8 +151,11 @@ export function OrdersTableWidget({ useValidatePageUrlParams(orders.length, currentTabId, currentPageNumber) + const ordersToCheckPendingPermit = useGetOrdersToCheckPendingPermit(ordersList, chainId, balancesAndAllowances) + return ( <> + {isOpenOrdersTab && orders.length && } diff --git a/apps/cowswap-frontend/src/modules/ordersTable/pure/OrdersTableContainer/OrderRow/EstimatedExecutionPrice.tsx b/apps/cowswap-frontend/src/modules/ordersTable/pure/OrdersTableContainer/OrderRow/EstimatedExecutionPrice.tsx index 01d725a782..a1e9a5ab86 100644 --- a/apps/cowswap-frontend/src/modules/ordersTable/pure/OrdersTableContainer/OrderRow/EstimatedExecutionPrice.tsx +++ b/apps/cowswap-frontend/src/modules/ordersTable/pure/OrdersTableContainer/OrderRow/EstimatedExecutionPrice.tsx @@ -1,18 +1,17 @@ import { useContext } from 'react' +import AlertTriangle from '@cowprotocol/assets/cow-swap/alert.svg' +import { ZERO_FRACTION } from '@cowprotocol/common-const' +import { SymbolElement, TokenAmount, TokenAmountProps } from '@cowprotocol/ui' +import { MouseoverTooltipContent } from '@cowprotocol/ui' import { Currency, CurrencyAmount, Fraction, Percent } from '@uniswap/sdk-core' import { darken, transparentize } from 'polished' import SVG from 'react-inlinesvg' import styled, { ThemeContext } from 'styled-components/macro' -import AlertTriangle from 'legacy/assets/cow-swap/alert.svg' -import { MouseoverTooltipContent } from 'legacy/components/Tooltip' -import { ZERO_FRACTION } from 'legacy/constants' - import { HIGH_FEE_WARNING_PERCENTAGE } from 'common/constants/common' import { calculateOrderExecutionStatus, ExecuteIndicator } from 'common/pure/OrderExecutionStatusList' -import { SymbolElement, TokenAmount, TokenAmountProps } from 'common/pure/TokenAmount' import * as styledEl from './styled' diff --git a/apps/cowswap-frontend/src/modules/ordersTable/pure/OrdersTableContainer/OrderRow/OrderContextMenu.tsx b/apps/cowswap-frontend/src/modules/ordersTable/pure/OrdersTableContainer/OrderRow/OrderContextMenu.tsx index 08f2b3c49d..2ebd2ab942 100644 --- a/apps/cowswap-frontend/src/modules/ordersTable/pure/OrdersTableContainer/OrderRow/OrderContextMenu.tsx +++ b/apps/cowswap-frontend/src/modules/ordersTable/pure/OrdersTableContainer/OrderRow/OrderContextMenu.tsx @@ -5,6 +5,8 @@ import { transparentize } from 'polished' import { FileText, Link2, MoreVertical, Trash2 } from 'react-feather' import styled, { ThemeContext } from 'styled-components/macro' +import { UI } from 'common/constants/theme' + export const ContextMenuButton = styled(MenuButton)` background: none; border: 0; @@ -26,7 +28,7 @@ export const ContextMenuButton = styled(MenuButton)` } ` export const ContextMenuList = styled(MenuList)` - background: ${({ theme }) => theme.bg1}; + background: var(${UI.COLOR_CONTAINER_BG_01}); border-radius: 12px; overflow: hidden; position: relative; @@ -47,7 +49,7 @@ export const ContextMenuItem = styled(MenuItem)<{ $red?: boolean }>` align-items: center; font-size: 15px; font-weight: 500; - color: ${({ theme, $red }) => ($red ? theme.danger : theme.text1)}; + color: ${({ theme, $red }) => ($red ? `var(${UI.COLOR_DANGER})` : theme.text1)}; &:hover { background: ${({ theme }) => transparentize(0.8, theme.text3)}; diff --git a/apps/cowswap-frontend/src/modules/ordersTable/pure/OrdersTableContainer/OrderRow/index.tsx b/apps/cowswap-frontend/src/modules/ordersTable/pure/OrdersTableContainer/OrderRow/index.tsx index e02fd5057d..e71f7ff25d 100644 --- a/apps/cowswap-frontend/src/modules/ordersTable/pure/OrdersTableContainer/OrderRow/index.tsx +++ b/apps/cowswap-frontend/src/modules/ordersTable/pure/OrdersTableContainer/OrderRow/index.tsx @@ -1,17 +1,17 @@ import React, { useCallback, useContext, useEffect, useState } from 'react' +import AlertTriangle from '@cowprotocol/assets/cow-swap/alert.svg' +import { ZERO_FRACTION } from '@cowprotocol/common-const' +import { useTimeAgo } from '@cowprotocol/common-hooks' +import { getAddress, getEtherscanLink } from '@cowprotocol/common-utils' import { OrderClass, SupportedChainId } from '@cowprotocol/cow-sdk' +import { Loader, TokenAmount, TokenSymbol } from '@cowprotocol/ui' import { Currency, CurrencyAmount, Percent, Price } from '@uniswap/sdk-core' import SVG from 'react-inlinesvg' import { ThemeContext } from 'styled-components/macro' -import AlertTriangle from 'legacy/assets/cow-swap/alert.svg' -import Loader from 'legacy/components/Loader' -import { ZERO_FRACTION } from 'legacy/constants' -import useTimeAgo from 'legacy/hooks/useTimeAgo' import { CREATING_STATES, OrderStatus } from 'legacy/state/orders/actions' -import { getEtherscanLink } from 'legacy/utils' import { PendingOrderPrices } from 'modules/orders/state/pendingOrdersPricesAtom' import { EstimatedExecutionPrice } from 'modules/ordersTable/pure/OrdersTableContainer/OrderRow/EstimatedExecutionPrice' @@ -30,11 +30,8 @@ import { useSafeMemo } from 'common/hooks/useSafeMemo' import { ButtonSecondary } from 'common/pure/ButtonSecondary' import { CurrencyLogo } from 'common/pure/CurrencyLogo' import { RateInfo } from 'common/pure/RateInfo' -import { TokenAmount } from 'common/pure/TokenAmount' -import { TokenSymbol } from 'common/pure/TokenSymbol' import { getQuoteCurrency } from 'common/services/getQuoteCurrency' import { isOrderCancellable } from 'common/utils/isOrderCancellable' -import { getAddress } from 'utils/getAddress' import { calculatePercentageInRelationToReference } from 'utils/orderUtils/calculatePercentageInRelationToReference' import { calculatePriceDifference, PriceDifference } from 'utils/orderUtils/calculatePriceDifference' import { getIsComposableCowParentOrder } from 'utils/orderUtils/getIsComposableCowParentOrder' @@ -151,6 +148,7 @@ export interface OrderRowProps { orderParams: OrderParams onClick: () => void orderActions: OrderActions + hasValidPendingPermit?: boolean | undefined children?: JSX.Element } @@ -167,6 +165,7 @@ export function OrderRow({ prices, spotPrice, children, + hasValidPendingPermit, }: OrderRowProps) { const { buyAmount, rateInfoParams, hasEnoughAllowance, hasEnoughBalance, chainId } = orderParams const { creationTime, expirationTime, status } = order @@ -177,7 +176,7 @@ export function OrderRow({ const showCancellationModal = orderActions.getShowCancellationModal(order) const withWarning = - (hasEnoughBalance === false || hasEnoughAllowance === false) && + (hasEnoughBalance === false || (hasEnoughAllowance === false && hasValidPendingPermit === false)) && // show the warning only for pending and scheduled orders (status === OrderStatus.PENDING || status === OrderStatus.SCHEDULED) const theme = useContext(ThemeContext) @@ -360,7 +359,7 @@ export function OrderRow({ {hasEnoughBalance === false && ( )} - {hasEnoughAllowance === false && ( + {hasEnoughAllowance === false && hasValidPendingPermit === false && ( orderActions.approveOrderToken(order.inputToken)} symbol={inputTokenSymbol} diff --git a/apps/cowswap-frontend/src/modules/ordersTable/pure/OrdersTableContainer/OrderRow/styled.tsx b/apps/cowswap-frontend/src/modules/ordersTable/pure/OrdersTableContainer/OrderRow/styled.tsx index 2c566846b8..a335e391df 100644 --- a/apps/cowswap-frontend/src/modules/ordersTable/pure/OrdersTableContainer/OrderRow/styled.tsx +++ b/apps/cowswap-frontend/src/modules/ordersTable/pure/OrdersTableContainer/OrderRow/styled.tsx @@ -3,6 +3,7 @@ import styled from 'styled-components/macro' import QuestionHelper from 'legacy/components/QuestionHelper' +import { UI } from 'common/constants/theme' import { RateWrapper } from 'common/pure/RateInfo' export const WarningIndicator = styled.button<{ hasBackground?: boolean }>` @@ -297,7 +298,7 @@ export const ToggleExpandButton = styled.div<{ isCollapsed?: boolean }>` margin: 0 0 0 6px; cursor: pointer; outline: none; - color: ${({ theme }) => theme.text1}; + color: var(${UI.COLOR_TEXT1}); transition: color 0.2s ease-out; position: relative; height: var(--height); diff --git a/apps/cowswap-frontend/src/modules/ordersTable/pure/OrdersTableContainer/OrdersTable.tsx b/apps/cowswap-frontend/src/modules/ordersTable/pure/OrdersTableContainer/OrdersTable.tsx index 4e34e84f23..b9d87eadb5 100644 --- a/apps/cowswap-frontend/src/modules/ordersTable/pure/OrdersTableContainer/OrdersTable.tsx +++ b/apps/cowswap-frontend/src/modules/ordersTable/pure/OrdersTableContainer/OrdersTable.tsx @@ -1,5 +1,6 @@ -import React, { useCallback, useState, useEffect, useMemo, useRef } from 'react' +import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react' +import iconOrderExecution from '@cowprotocol/assets/cow-swap/orderExecution.svg' import { SupportedChainId } from '@cowprotocol/cow-sdk' import { Currency, Price } from '@uniswap/sdk-core' @@ -10,23 +11,23 @@ import SVG from 'react-inlinesvg' import { useLocation } from 'react-router-dom' import styled from 'styled-components/macro' -import iconOrderExecution from 'legacy/assets/cow-swap/orderExecution.svg' -import { QuestionWrapper } from 'legacy/components/QuestionHelper' -import QuestionHelper from 'legacy/components/QuestionHelper' +import QuestionHelper, { QuestionWrapper } from 'legacy/components/QuestionHelper' import { PendingOrdersPrices } from 'modules/orders/state/pendingOrdersPricesAtom' import { SpotPricesKeyParams } from 'modules/orders/state/spotPricesAtom' import { ORDERS_TABLE_PAGE_SIZE } from 'modules/ordersTable/const/tabs' import { + CheckboxCheckmark, TableHeader, TableRowCheckbox, TableRowCheckboxWrapper, - CheckboxCheckmark, } from 'modules/ordersTable/pure/OrdersTableContainer/styled' import { OrderActions } from 'modules/ordersTable/pure/OrdersTableContainer/types' +import { OrdersPermitStatus } from 'modules/permit' import { BalancesAndAllowances } from 'modules/tokens' import { ordersTableFeatures } from 'common/constants/featureFlags' +import { UI } from 'common/constants/theme' import { OrderExecutionStatusList, RateTooltipHeader } from 'common/pure/OrderExecutionStatusList' import { InvertRateControl } from 'common/pure/RateInfo' import { CancellableOrder } from 'common/utils/isOrderCancellable' @@ -39,7 +40,7 @@ import { getOrderParams } from './utils/getOrderParams' import { buildOrdersTableUrl } from '../../utils/buildOrdersTableUrl' import { - getParsedOrderFromItem, + getParsedOrderFromTableItem, isParsedOrder, OrderTableItem, tableItemsToOrders, @@ -150,7 +151,7 @@ const StyledCloseIcon = styled(X)` } > line { - stroke: ${({ theme }) => theme.text1}; + stroke: var(${UI.COLOR_TEXT1}); } ` @@ -205,6 +206,7 @@ export interface OrdersTableProps { balancesAndAllowances: BalancesAndAllowances getSpotPrice: (params: SpotPricesKeyParams) => Price | null orderActions: OrderActions + ordersPermitStatus: OrdersPermitStatus } export function OrdersTable({ @@ -218,6 +220,7 @@ export function OrdersTable({ getSpotPrice, orderActions, currentPageNumber, + ordersPermitStatus, }: OrdersTableProps) { const location = useLocation() const [isRateInverted, setIsRateInverted] = useState(false) @@ -260,14 +263,14 @@ export function OrdersTable({ }, [showOrdersExplainerBanner]) const cancellableOrders = useMemo( - () => ordersPage.filter((item) => isOrderOffChainCancellable(getParsedOrderFromItem(item))), + () => ordersPage.filter((item) => isOrderOffChainCancellable(getParsedOrderFromTableItem(item))), [ordersPage] ) const allOrdersSelected = useMemo(() => { if (!cancellableOrders.length) return false - return cancellableOrders.every((item) => selectedOrdersMap[getParsedOrderFromItem(item).id]) + return cancellableOrders.every((item) => selectedOrdersMap[getParsedOrderFromTableItem(item).id]) }, [cancellableOrders, selectedOrdersMap]) const getPageUrl = useCallback((index: number) => buildOrdersTableUrl(location, { pageNumber: index }), [location]) @@ -399,7 +402,7 @@ export function OrdersTable({ {ordersPage.map((item) => { - const { inputToken, outputToken } = getParsedOrderFromItem(item) + const { inputToken, outputToken } = getParsedOrderFromTableItem(item) const spotPrice = getSpotPrice({ chainId: chainId as SupportedChainId, sellTokenAddress: inputToken.address, @@ -409,6 +412,10 @@ export function OrdersTable({ if (isParsedOrder(item)) { const order = item + const orderParams = getOrderParams(chainId, balancesAndAllowances, order) + + const hasValidPendingPermit = ordersPermitStatus[order.id] + return ( orderActions.selectReceiptOrder(order)} + hasValidPendingPermit={hasValidPendingPermit} /> ) } else { diff --git a/apps/cowswap-frontend/src/modules/ordersTable/pure/OrdersTableContainer/OrdersTablePagination.tsx b/apps/cowswap-frontend/src/modules/ordersTable/pure/OrdersTableContainer/OrdersTablePagination.tsx index e4519ba642..e5e7519a93 100644 --- a/apps/cowswap-frontend/src/modules/ordersTable/pure/OrdersTableContainer/OrdersTablePagination.tsx +++ b/apps/cowswap-frontend/src/modules/ordersTable/pure/OrdersTableContainer/OrdersTablePagination.tsx @@ -2,6 +2,8 @@ import { transparentize } from 'polished' import { Link } from 'react-router-dom' import styled, { css } from 'styled-components/macro' +import { UI } from 'common/constants/theme' + export interface OrdersTablePaginationProps { getPageUrl?(index: number): Partial<{ pathname: string; search: string }> onPageChange?(index: number): void @@ -28,7 +30,7 @@ const PaginationBox = styled.div` const pageButtonStyles = css<{ $active?: boolean }>` background: ${({ theme, $active }) => ($active ? transparentize(0.9, theme.text3) : 'transparent')}; - color: ${({ theme, $active }) => ($active ? theme.text1 : transparentize(0.2, theme.text1))}; + color: ${({ theme, $active }) => ($active ? `var(${UI.COLOR_TEXT1})` : transparentize(0.2, theme.text1))}; border: 0; outline: 0; padding: 5px 10px; @@ -39,8 +41,8 @@ const pageButtonStyles = css<{ $active?: boolean }>` text-decoration: none; &:hover { - background: ${({ theme }) => theme.bg1}; - color: ${({ theme }) => theme.text1}; + background: var(${UI.COLOR_CONTAINER_BG_01}); + color: var(${UI.COLOR_TEXT1}); } ` diff --git a/apps/cowswap-frontend/src/modules/ordersTable/pure/OrdersTableContainer/OrdersTabs.tsx b/apps/cowswap-frontend/src/modules/ordersTable/pure/OrdersTableContainer/OrdersTabs.tsx index 0b228fe113..b12867c0bf 100644 --- a/apps/cowswap-frontend/src/modules/ordersTable/pure/OrdersTableContainer/OrdersTabs.tsx +++ b/apps/cowswap-frontend/src/modules/ordersTable/pure/OrdersTableContainer/OrdersTabs.tsx @@ -5,6 +5,8 @@ import styled from 'styled-components/macro' import { buildOrdersTableUrl } from 'modules/ordersTable/utils/buildOrdersTableUrl' +import { UI } from 'common/constants/theme' + import { OrderTab } from '../../const/tabs' const Tabs = styled.div` @@ -24,7 +26,7 @@ const Tabs = styled.div` const TabButton = styled(Link)<{ active: string }>` display: inline-block; background: ${({ theme, active }) => (active === 'true' ? transparentize(0.88, theme.text3) : 'transparent')}; - color: ${({ theme, active }) => (active === 'true' ? theme.text1 : transparentize(0.2, theme.text1))}; + color: ${({ theme, active }) => (active === 'true' ? `var(${UI.COLOR_TEXT1})` : transparentize(0.2, theme.text1))}; font-weight: ${({ active }) => (active === 'true' ? '600' : '400')}; text-decoration: none; font-size: 13px; @@ -39,8 +41,8 @@ const TabButton = styled(Link)<{ active: string }>` `}; &:hover { - background: ${({ theme }) => theme.bg1}; - color: ${({ theme }) => theme.text1}; + background: var(${UI.COLOR_CONTAINER_BG_01}); + color: var(${UI.COLOR_TEXT1}); } ` diff --git a/apps/cowswap-frontend/src/modules/ordersTable/pure/OrdersTableContainer/index.cosmos.tsx b/apps/cowswap-frontend/src/modules/ordersTable/pure/OrdersTableContainer/index.cosmos.tsx index a35075a79b..0288e07a25 100644 --- a/apps/cowswap-frontend/src/modules/ordersTable/pure/OrdersTableContainer/index.cosmos.tsx +++ b/apps/cowswap-frontend/src/modules/ordersTable/pure/OrdersTableContainer/index.cosmos.tsx @@ -53,6 +53,7 @@ const orderActions: OrderActions = { export default ( null} orderActions={orderActions} orderType={TabOrderTypes.LIMIT} + ordersPermitStatus={{}} /> ) diff --git a/apps/cowswap-frontend/src/modules/ordersTable/pure/OrdersTableContainer/index.tsx b/apps/cowswap-frontend/src/modules/ordersTable/pure/OrdersTableContainer/index.tsx index 5370596d2c..dcde2ae431 100644 --- a/apps/cowswap-frontend/src/modules/ordersTable/pure/OrdersTableContainer/index.tsx +++ b/apps/cowswap-frontend/src/modules/ordersTable/pure/OrdersTableContainer/index.tsx @@ -1,16 +1,15 @@ import { ReactNode } from 'react' +import cowMeditatingV2 from '@cowprotocol/assets/cow-swap/meditating-cow-v2.svg' +import imageConnectWallet from '@cowprotocol/assets/cow-swap/wallet-plus.svg' +import { ExternalLink } from '@cowprotocol/ui' + import { Trans } from '@lingui/macro' import { transparentize } from 'polished' import SVG from 'react-inlinesvg' import styled from 'styled-components/macro' -import cowMeditatingV2 from 'legacy/assets/cow-swap/meditating-cow-v2.svg' -import imageConnectWallet from 'legacy/assets/cow-swap/wallet-plus.svg' -import { ExternalLink } from 'legacy/theme' - -import { Wrapper as Web3StatusWrapper } from 'modules/wallet/api/pure/Web3StatusInner/styled' -import { Web3Status } from 'modules/wallet/web3-react/containers/Web3Status' +import { Web3Status } from 'modules/wallet/containers/Web3Status' import { CowSwapSafeAppLink } from 'common/pure/CowSwapSafeAppLink' @@ -85,10 +84,6 @@ const Content = styled.div` text-align: center; color: ${({ theme }) => transparentize(0.3, theme.text1)}; } - - ${Web3StatusWrapper} { - margin: 0 auto; - } ` const Header = styled.div` @@ -144,6 +139,7 @@ export interface OrdersProps extends OrdersTabsProps, OrdersTableProps { isOpenOrdersTab: boolean isSafeViaWc: boolean displayOrdersOnlyForSafeApp: boolean + pendingActivities: string[] children?: ReactNode orderType: TabOrderTypes } @@ -170,6 +166,8 @@ export function OrdersTableContainer({ getSpotPrice, children, orderType, + pendingActivities, + ordersPermitStatus, }: OrdersProps) { const content = () => { if (!isWalletConnected) { @@ -188,7 +186,7 @@ export function OrdersTableContainer({

- + ) } @@ -236,6 +234,7 @@ export function OrdersTableContainer({ balancesAndAllowances={balancesAndAllowances} getSpotPrice={getSpotPrice} orderActions={orderActions} + ordersPermitStatus={ordersPermitStatus} /> ) } diff --git a/apps/cowswap-frontend/src/modules/ordersTable/pure/OrdersTableContainer/orders.mock.ts b/apps/cowswap-frontend/src/modules/ordersTable/pure/OrdersTableContainer/orders.mock.ts index 89c9e45e14..742785a504 100644 --- a/apps/cowswap-frontend/src/modules/ordersTable/pure/OrdersTableContainer/orders.mock.ts +++ b/apps/cowswap-frontend/src/modules/ordersTable/pure/OrdersTableContainer/orders.mock.ts @@ -1,8 +1,8 @@ +import { COW, DAI, GNO, USDC } from '@cowprotocol/common-const' +import { WETH_GOERLI } from '@cowprotocol/common-const' import { OrderKind, OrderClass } from '@cowprotocol/cow-sdk' -import { COW, DAI, GNO, USDC } from 'legacy/constants/tokens' import { OrderStatus } from 'legacy/state/orders/actions' -import { WETH_GOERLI } from 'legacy/utils/goerli/constants' import { ParsedOrder, parseOrder } from 'utils/orderUtils/parseOrder' diff --git a/apps/cowswap-frontend/src/modules/ordersTable/pure/OrdersTableContainer/styled.tsx b/apps/cowswap-frontend/src/modules/ordersTable/pure/OrdersTableContainer/styled.tsx index bfa9c7de84..bc97fc4c2a 100644 --- a/apps/cowswap-frontend/src/modules/ordersTable/pure/OrdersTableContainer/styled.tsx +++ b/apps/cowswap-frontend/src/modules/ordersTable/pure/OrdersTableContainer/styled.tsx @@ -1,6 +1,7 @@ import { transparentize } from 'polished' import styled from 'styled-components/macro' +import { UI } from 'common/constants/theme' import { RateWrapper } from 'common/pure/RateInfo' export const TableHeader = styled.div<{ isOpenOrdersTab: boolean; isRowSelectable: boolean }>` @@ -118,7 +119,7 @@ export const TableRowCheckbox = styled.input` outline: 0; &:checked { - background-color: ${({ theme }) => theme.text1}; + background-color: var(${UI.COLOR_TEXT1}); } &:checked + ${CheckboxCheckmark}::after { @@ -126,7 +127,7 @@ export const TableRowCheckbox = styled.input` } &:indeterminate { - border-color: ${({ theme }) => theme.text1}; + border-color: var(${UI.COLOR_TEXT1}); } &:indeterminate + ${CheckboxCheckmark}::after { diff --git a/apps/cowswap-frontend/src/modules/ordersTable/pure/OrdersTableContainer/utils/getOrderParams.ts b/apps/cowswap-frontend/src/modules/ordersTable/pure/OrdersTableContainer/utils/getOrderParams.ts index 8968e26a34..afda0bf5fd 100644 --- a/apps/cowswap-frontend/src/modules/ordersTable/pure/OrdersTableContainer/utils/getOrderParams.ts +++ b/apps/cowswap-frontend/src/modules/ordersTable/pure/OrdersTableContainer/utils/getOrderParams.ts @@ -1,10 +1,10 @@ +import { isEnoughAmount } from '@cowprotocol/common-utils' import { SupportedChainId } from '@cowprotocol/cow-sdk' import { Currency, CurrencyAmount, Percent, Token } from '@uniswap/sdk-core' import { BalancesAndAllowances } from 'modules/tokens' import { RateInfoParams } from 'common/pure/RateInfo' -import { isEnoughAmount } from 'utils/isEnoughAmount' import { ParsedOrder } from 'utils/orderUtils/parseOrder' export interface OrderParams { @@ -23,8 +23,8 @@ export function getOrderParams( balancesAndAllowances: BalancesAndAllowances, order: ParsedOrder ): OrderParams { - const sellAmount = CurrencyAmount.fromRawAmount(order.inputToken, order.sellAmount.toString()) - const buyAmount = CurrencyAmount.fromRawAmount(order.outputToken, order.buyAmount.toString()) + const sellAmount = CurrencyAmount.fromRawAmount(order.inputToken, order.sellAmount) + const buyAmount = CurrencyAmount.fromRawAmount(order.outputToken, order.buyAmount) const rateInfoParams: RateInfoParams = { chainId, diff --git a/apps/cowswap-frontend/src/modules/ordersTable/pure/ReceiptModal/CurrencyField.tsx b/apps/cowswap-frontend/src/modules/ordersTable/pure/ReceiptModal/CurrencyField.tsx index 05b1f2a7b5..ddb834a39e 100644 --- a/apps/cowswap-frontend/src/modules/ordersTable/pure/ReceiptModal/CurrencyField.tsx +++ b/apps/cowswap-frontend/src/modules/ordersTable/pure/ReceiptModal/CurrencyField.tsx @@ -1,7 +1,7 @@ +import { TokenAmount } from '@cowprotocol/ui' import { CurrencyAmount, Token } from '@uniswap/sdk-core' import { CurrencySelectButton } from 'common/pure/CurrencySelectButton' -import { TokenAmount } from 'common/pure/TokenAmount' import * as styledEl from './styled' diff --git a/apps/cowswap-frontend/src/modules/ordersTable/pure/ReceiptModal/DateField.tsx b/apps/cowswap-frontend/src/modules/ordersTable/pure/ReceiptModal/DateField.tsx index 38642583fe..63ae1693af 100644 --- a/apps/cowswap-frontend/src/modules/ordersTable/pure/ReceiptModal/DateField.tsx +++ b/apps/cowswap-frontend/src/modules/ordersTable/pure/ReceiptModal/DateField.tsx @@ -1,6 +1,6 @@ -import { format } from 'date-fns' +import { useTimeAgo } from '@cowprotocol/common-hooks' -import useTimeAgo from 'legacy/hooks/useTimeAgo' +import { format } from 'date-fns' import * as styledEl from './styled' diff --git a/apps/cowswap-frontend/src/modules/ordersTable/pure/ReceiptModal/FeeField.tsx b/apps/cowswap-frontend/src/modules/ordersTable/pure/ReceiptModal/FeeField.tsx index 7786024f61..eed9c96389 100644 --- a/apps/cowswap-frontend/src/modules/ordersTable/pure/ReceiptModal/FeeField.tsx +++ b/apps/cowswap-frontend/src/modules/ordersTable/pure/ReceiptModal/FeeField.tsx @@ -1,6 +1,6 @@ +import { TokenAmount } from '@cowprotocol/ui' import { CurrencyAmount } from '@uniswap/sdk-core' -import { TokenAmount } from 'common/pure/TokenAmount' import { ParsedOrder } from 'utils/orderUtils/parseOrder' import * as styledEl from './styled' diff --git a/apps/cowswap-frontend/src/modules/ordersTable/pure/ReceiptModal/FilledField.tsx b/apps/cowswap-frontend/src/modules/ordersTable/pure/ReceiptModal/FilledField.tsx index 5c2752ac09..866e6c7e93 100644 --- a/apps/cowswap-frontend/src/modules/ordersTable/pure/ReceiptModal/FilledField.tsx +++ b/apps/cowswap-frontend/src/modules/ordersTable/pure/ReceiptModal/FilledField.tsx @@ -1,8 +1,9 @@ // Code based on https://github.com/cowprotocol/explorer/blob/develop/src/components/orders/FilledProgress/index.tsx +import { TokenAmount } from '@cowprotocol/ui' + import { ProgressBarWrapper, ProgressBar } from 'modules/ordersTable/pure/OrdersTableContainer/OrderRow/styled' -import { TokenAmount } from 'common/pure/TokenAmount' import { getFilledAmounts } from 'utils/orderUtils/getFilledAmounts' import { ParsedOrder } from 'utils/orderUtils/parseOrder' diff --git a/apps/cowswap-frontend/src/modules/ordersTable/pure/ReceiptModal/IdField.tsx b/apps/cowswap-frontend/src/modules/ordersTable/pure/ReceiptModal/IdField.tsx index 73eef077b1..4947ceeda0 100644 --- a/apps/cowswap-frontend/src/modules/ordersTable/pure/ReceiptModal/IdField.tsx +++ b/apps/cowswap-frontend/src/modules/ordersTable/pure/ReceiptModal/IdField.tsx @@ -1,7 +1,6 @@ +import { getEtherscanLink } from '@cowprotocol/common-utils' import { SupportedChainId } from '@cowprotocol/cow-sdk' - -import { ExternalLink } from 'legacy/theme' -import { getEtherscanLink } from 'legacy/utils' +import { ExternalLink } from '@cowprotocol/ui' import * as styledEl from './styled' diff --git a/apps/cowswap-frontend/src/modules/ordersTable/pure/ReceiptModal/PriceField.tsx b/apps/cowswap-frontend/src/modules/ordersTable/pure/ReceiptModal/PriceField.tsx index 9a6b7a469d..9e53548174 100644 --- a/apps/cowswap-frontend/src/modules/ordersTable/pure/ReceiptModal/PriceField.tsx +++ b/apps/cowswap-frontend/src/modules/ordersTable/pure/ReceiptModal/PriceField.tsx @@ -1,7 +1,7 @@ +import { TokenAmount } from '@cowprotocol/ui' +import { TokenSymbol } from '@cowprotocol/ui' import { Fraction } from '@uniswap/sdk-core' -import { TokenAmount } from 'common/pure/TokenAmount' -import { TokenSymbol } from 'common/pure/TokenSymbol' import { ParsedOrder } from 'utils/orderUtils/parseOrder' import * as styledEl from './styled' diff --git a/apps/cowswap-frontend/src/modules/ordersTable/pure/ReceiptModal/SurplusField.tsx b/apps/cowswap-frontend/src/modules/ordersTable/pure/ReceiptModal/SurplusField.tsx index 7cd1495a1b..235ec3282c 100644 --- a/apps/cowswap-frontend/src/modules/ordersTable/pure/ReceiptModal/SurplusField.tsx +++ b/apps/cowswap-frontend/src/modules/ordersTable/pure/ReceiptModal/SurplusField.tsx @@ -1,7 +1,7 @@ import { OrderKind } from '@cowprotocol/cow-sdk' +import { TokenAmount } from '@cowprotocol/ui' import { CurrencyAmount } from '@uniswap/sdk-core' -import { TokenAmount } from 'common/pure/TokenAmount' import { ParsedOrder } from 'utils/orderUtils/parseOrder' import * as styledEl from './styled' diff --git a/apps/cowswap-frontend/src/modules/ordersTable/pure/ReceiptModal/fields/SafeTxFields.tsx b/apps/cowswap-frontend/src/modules/ordersTable/pure/ReceiptModal/fields/SafeTxFields.tsx index 93a75c77f2..00eea420be 100644 --- a/apps/cowswap-frontend/src/modules/ordersTable/pure/ReceiptModal/fields/SafeTxFields.tsx +++ b/apps/cowswap-frontend/src/modules/ordersTable/pure/ReceiptModal/fields/SafeTxFields.tsx @@ -1,9 +1,8 @@ +import safeLogo from '@cowprotocol/assets/cow-swap/safe-logo.svg' import { SupportedChainId } from '@cowprotocol/cow-sdk' import styled from 'styled-components/macro' -import safeLogo from 'modules/wallet/api/assets/safe-logo.svg' - import { SafeWalletLink } from 'common/pure/SafeWalletLink' import { FieldLabel } from '../FieldLabel' diff --git a/apps/cowswap-frontend/src/modules/ordersTable/pure/ReceiptModal/index.tsx b/apps/cowswap-frontend/src/modules/ordersTable/pure/ReceiptModal/index.tsx index 512aae78c7..609ac01159 100644 --- a/apps/cowswap-frontend/src/modules/ordersTable/pure/ReceiptModal/index.tsx +++ b/apps/cowswap-frontend/src/modules/ordersTable/pure/ReceiptModal/index.tsx @@ -1,15 +1,23 @@ +import { ExplorerDataType, getExplorerLink, shortenAddress } from '@cowprotocol/common-utils' import { OrderKind, SupportedChainId } from '@cowprotocol/cow-sdk' +import { ExternalLink } from '@cowprotocol/ui' import { CurrencyAmount, Fraction, Token } from '@uniswap/sdk-core' import { OrderStatus } from 'legacy/state/orders/actions' -import { CloseIcon, ExternalLink } from 'legacy/theme' -import { shortenAddress } from 'legacy/utils' -import { ExplorerDataType, getExplorerLink } from 'legacy/utils/getExplorerLink' +import { CloseIcon } from 'legacy/theme' import { TwapOrderItem } from 'modules/twap/types' +import { UI } from 'common/constants/theme' +import { isPending } from 'common/hooks/useCategorizeRecentActivity' +import { Icon, IconType } from 'common/pure/Icon' import { InlineBanner } from 'common/pure/InlineBanner' +import { BannerOrientation, CustomRecipientWarningBanner } from 'common/pure/InlineBanner/banners' import { CowModal } from 'common/pure/Modal' +import { + useHideReceiverWalletBanner, + useIsReceiverWalletBannerHidden, +} from 'common/state/receiverWalletBannerVisibility' import { getSellAmountWithFee } from 'utils/orderUtils/getSellAmountWithFee' import { ParsedOrder } from 'utils/orderUtils/parseOrder' @@ -88,6 +96,14 @@ export function ReceiptModal({ estimatedExecutionPrice, receiverEnsName, }: ReceiptProps) { + // Check if Custom Recipient Warning Banner should be visible + const isCustomRecipientWarningBannerVisible = !useIsReceiverWalletBannerHidden(order.id) + const hideCustomRecipientWarning = useHideReceiverWalletBanner() + + const isCustomRecipient = Boolean(order.receiver && order.owner !== order.receiver) + + const showCustomRecipientBanner = isCustomRecipient && isCustomRecipientWarningBannerVisible && isPending(order) + if (!order || !chainId) { return null } @@ -108,7 +124,7 @@ export function ReceiptModal({ {twapOrder && ( - +

{isTwapPartOrder ? `Part of a ${twapOrder.order.n}-part TWAP order split` @@ -123,6 +139,15 @@ export function ReceiptModal({ + {/* If custom recipient show warning banner */} + {showCustomRecipientBanner && ( + hideCustomRecipientWarning(order.id)} + /> + )} + @@ -132,8 +157,11 @@ export function ReceiptModal({

+ {showCustomRecipientBanner && ( + + )} - {receiverEnsName || shortenAddress(order.receiver)} + {receiverEnsName || shortenAddress(order.receiver)} ↗
diff --git a/apps/cowswap-frontend/src/modules/ordersTable/pure/ReceiptModal/styled.ts b/apps/cowswap-frontend/src/modules/ordersTable/pure/ReceiptModal/styled.ts index 836c5be695..0c829b2b09 100644 --- a/apps/cowswap-frontend/src/modules/ordersTable/pure/ReceiptModal/styled.ts +++ b/apps/cowswap-frontend/src/modules/ordersTable/pure/ReceiptModal/styled.ts @@ -1,9 +1,11 @@ +import { AutoRow } from '@cowprotocol/ui' + import styled from 'styled-components/macro' -import { AutoRow } from 'legacy/components/Row' +import { UI } from 'common/constants/theme' export const Wrapper = styled.div` - background: ${({ theme }) => theme.bg1}; + background: var(${UI.COLOR_CONTAINER_BG_01}); width: 100%; margin: 0 0 14px; overflow-y: auto; @@ -24,7 +26,7 @@ export const Header = styled.div` justify-content: space-between; align-items: center; padding: 0 16px 16px; - background: ${({ theme }) => theme.bg1}; + background: var(${UI.COLOR_CONTAINER_BG_01}); position: sticky; top: 0; left: 0; @@ -69,7 +71,7 @@ export const Field = styled.div` justify-content: space-between; align-items: center; padding: 12px 16px; - background: ${({ theme }) => theme.grey1}; + background: var(${UI.COLOR_GREY}); width: 100%; font-size: 13px; @@ -80,6 +82,10 @@ export const Field = styled.div` &:last-child { border-radius: 0 0 16px 16px; } + + > div { + display: flex; + } ` export const CurrencyField = styled.div` @@ -88,7 +94,7 @@ export const CurrencyField = styled.div` flex-direction: column; align-items: flex-start; padding: 16px; - background: ${({ theme }) => theme.grey1}; + background: var(${UI.COLOR_GREY}); width: 100%; border-radius: 16px; margin: 0 0 10px; diff --git a/apps/cowswap-frontend/src/modules/ordersTable/utils/orderTableGroupUtils.ts b/apps/cowswap-frontend/src/modules/ordersTable/utils/orderTableGroupUtils.ts index 621ed72dd2..2f4db047ae 100644 --- a/apps/cowswap-frontend/src/modules/ordersTable/utils/orderTableGroupUtils.ts +++ b/apps/cowswap-frontend/src/modules/ordersTable/utils/orderTableGroupUtils.ts @@ -7,10 +7,11 @@ export interface OrderTableGroup { export type OrderTableItem = OrderTableGroup | ParsedOrder -export const isParsedOrder = (item: OrderTableItem): item is ParsedOrder => item.hasOwnProperty('creationTime') +export const isParsedOrder = (item: OrderTableItem): item is ParsedOrder => !('children' in item) -export const getParsedOrderFromItem = (item: OrderTableItem): ParsedOrder => (isParsedOrder(item) ? item : item.parent) +export const getParsedOrderFromTableItem = (item: OrderTableItem): ParsedOrder => + isParsedOrder(item) ? item : item.parent export function tableItemsToOrders(items: OrderTableItem[]): ParsedOrder[] { - return items.map(getParsedOrderFromItem) + return items.map(getParsedOrderFromTableItem) } diff --git a/apps/cowswap-frontend/src/modules/permit/const.ts b/apps/cowswap-frontend/src/modules/permit/const.ts new file mode 100644 index 0000000000..516059f1f3 --- /dev/null +++ b/apps/cowswap-frontend/src/modules/permit/const.ts @@ -0,0 +1,33 @@ +import { SupportedChainId } from '@cowprotocol/cow-sdk' +import { MaxUint256 } from '@ethersproject/constants' +import { Wallet } from '@ethersproject/wallet' + +import ms from 'ms.macro' + +import { TradeType } from '../trade' + +// PK used only for signing permit requests for quoting and identifying token 'permittability' +// Do not use or try to send funds to it. Or do. It'll be your funds 🤷 +const PERMIT_PK = '0xc58a2a421ca71ca57ae698f1c32feeb0b0ccb434da0b8089d88d80fb918f3f9d' // address: 0xFf65D1DfCF256cf4A8D5F2fb8e70F936606B7474 + +export const PERMIT_SIGNER = new Wallet(PERMIT_PK) + +export const PERMIT_GAS_LIMIT_MIN: Record = { + 1: 55_000, + 100: 55_000, + 5: 36_000, +} + +export const DEFAULT_PERMIT_GAS_LIMIT = '80000' + +export const DEFAULT_PERMIT_VALUE = MaxUint256.toString() + +export const DEFAULT_PERMIT_DURATION = ms`5 years` + +export const ORDER_TYPE_SUPPORTS_PERMIT: Record = { + [TradeType.SWAP]: true, + [TradeType.LIMIT_ORDER]: true, + [TradeType.ADVANCED_ORDERS]: false, +} + +export const PENDING_ORDER_PERMIT_CHECK_INTERVAL = ms`1min` diff --git a/apps/cowswap-frontend/src/modules/permit/hooks/useAccountAgnosticPermitHookData.ts b/apps/cowswap-frontend/src/modules/permit/hooks/useAccountAgnosticPermitHookData.ts new file mode 100644 index 0000000000..458cbe3e21 --- /dev/null +++ b/apps/cowswap-frontend/src/modules/permit/hooks/useAccountAgnosticPermitHookData.ts @@ -0,0 +1,54 @@ +import { useEffect, useState } from 'react' + +import { Token } from '@uniswap/sdk-core' + +import { useDerivedTradeState } from 'modules/trade' + +import { useSafeMemo } from 'common/hooks/useSafeMemo' + +import { useGeneratePermitHook } from './useGeneratePermitHook' +import { useIsTokenPermittable } from './useIsTokenPermittable' + +import { GeneratePermitHookParams, PermitHookData } from '../types' + +/** + * Returns PermitHookData using an account agnostic signer if inputCurrency is permittable + * + * Internally checks whether the token is permittable + * + * If not permittable or not able to tell, returns undefined + */ +export function useAccountAgnosticPermitHookData(): PermitHookData | undefined { + const params = useGeneratePermitHookParams() + const generatePermitHook = useGeneratePermitHook() + + const [data, setData] = useState(undefined) + + useEffect(() => { + if (!params) { + setData(undefined) + + return + } + + generatePermitHook(params).then(setData) + }, [generatePermitHook, params]) + + return data +} + +function useGeneratePermitHookParams(): GeneratePermitHookParams | undefined { + const { state } = useDerivedTradeState() + const { inputCurrency, tradeType } = state || {} + + const permitInfo = useIsTokenPermittable(inputCurrency, tradeType) + + return useSafeMemo(() => { + if (!inputCurrency || !permitInfo) return undefined + + return { + inputToken: inputCurrency as Token, + permitInfo, + } + }, [inputCurrency, permitInfo]) +} diff --git a/apps/cowswap-frontend/src/modules/permit/hooks/useCheckHasValidPendingPermit.ts b/apps/cowswap-frontend/src/modules/permit/hooks/useCheckHasValidPendingPermit.ts new file mode 100644 index 0000000000..6197865e15 --- /dev/null +++ b/apps/cowswap-frontend/src/modules/permit/hooks/useCheckHasValidPendingPermit.ts @@ -0,0 +1,121 @@ +import { useCallback } from 'react' + +import { SupportedChainId } from '@cowprotocol/cow-sdk' +import { useWalletInfo } from '@cowprotocol/wallet' +import { Web3Provider } from '@ethersproject/providers' +import { useWeb3React } from '@web3-react/core' + +import { DAI_PERMIT_SELECTOR, Eip2612PermitUtils, EIP_2612_PERMIT_SELECTOR } from '@1inch/permit-signed-approvals-utils' + +import { getAppDataHooks } from 'modules/appData' + +import { ParsedOrder } from 'utils/orderUtils/parseOrder' + +import { CheckHasValidPendingPermit } from '../types' +import { getPermitUtilsInstance } from '../utils/getPermitUtilsInstance' + +export function useCheckHasValidPendingPermit(): CheckHasValidPendingPermit { + const { chainId } = useWalletInfo() + const { provider } = useWeb3React() + + return useCallback( + async (order: ParsedOrder): Promise => { + if (!provider) { + // Missing required params, we can't tell + return undefined + } + + return checkHasValidPendingPermit(order, provider, chainId) + }, + [chainId, provider] + ) +} + +async function checkHasValidPendingPermit( + order: ParsedOrder, + provider: Web3Provider, + chainId: SupportedChainId +): Promise { + const { fullAppData, partiallyFillable, executionData } = order + const preHooks = getAppDataHooks(fullAppData)?.pre + + if ( + // No hooks === no permit + !preHooks || + // Permit is only executed for partially fillable orders in the first execution + // Thus, if there is any amount executed, partiallyFillable permit is no longer valid + (partiallyFillable && executionData.filledAmount.gt('0')) + ) { + // These cases we know for sure permit isn't valid or there is no permit + return false + } + + const eip2162Utils = getPermitUtilsInstance(chainId, provider, order.owner) + + const tokenAddress = order.inputToken.address + const tokenName = order.inputToken.name || tokenAddress + + const checkedHooks = await Promise.all( + preHooks.map(({ callData }) => + checkIsSingleCallDataAValidPermit(order, chainId, eip2162Utils, tokenAddress, tokenName, callData) + ) + ) + + const validPermits = checkedHooks.filter((v) => v !== undefined) + + if (!validPermits.length) { + // No permits means no preHook permits, we can say that there is no valid permit + return false + } + + // Only when all permits are valid, then the order permits are still valid + return validPermits.every(Boolean) +} + +async function checkIsSingleCallDataAValidPermit( + order: ParsedOrder, + chainId: SupportedChainId, + eip2162Utils: Eip2612PermitUtils, + tokenAddress: string, + tokenName: string, + callData: string +): Promise { + const params = { chainId, tokenName, tokenAddress, callData } + + let recoverPermitOwnerPromise: Promise | undefined = undefined + + // If pre-hook doesn't start with either selector, it's not a permit + if (callData.startsWith(EIP_2612_PERMIT_SELECTOR)) { + recoverPermitOwnerPromise = eip2162Utils.recoverPermitOwnerFromCallData({ + ...params, + // I don't know why this was removed, ok? + // We added it back on buildPermitCallData.ts + // But it looks like this is needed 🤷 + // Check the test for this method https://github.com/1inch/permit-signed-approvals-utils/blob/master/src/eip-2612-permit.test.ts#L85-L106 + callData: callData.replace(EIP_2612_PERMIT_SELECTOR, '0x'), + }) + } else if (callData.startsWith(DAI_PERMIT_SELECTOR)) { + recoverPermitOwnerPromise = eip2162Utils.recoverDaiLikePermitOwnerFromCallData({ + ...params, + callData: callData.replace(DAI_PERMIT_SELECTOR, '0x'), + }) + } + + if (!recoverPermitOwnerPromise) { + // The callData doesn't match any known permit type + return undefined + } + + try { + const recoveredOwner = await recoverPermitOwnerPromise + + // Permit is valid when recovered owner matches order owner + return recoveredOwner.toLowerCase() === order.owner.toLowerCase() + } catch (e) { + console.debug( + `[checkHasValidPendingPermit] Failed to check permit validity for order ${order.id} with callData ${callData}`, + e + ) + return false + } +} diff --git a/apps/cowswap-frontend/src/modules/permit/hooks/useGeneratePermitHook.ts b/apps/cowswap-frontend/src/modules/permit/hooks/useGeneratePermitHook.ts new file mode 100644 index 0000000000..82edb237c0 --- /dev/null +++ b/apps/cowswap-frontend/src/modules/permit/hooks/useGeneratePermitHook.ts @@ -0,0 +1,73 @@ +import { useAtomValue, useSetAtom } from 'jotai' +import { useCallback } from 'react' + +import { useWalletInfo } from '@cowprotocol/wallet' +import { useWeb3React } from '@web3-react/core' + +import { + getPermitCacheAtom, + staticPermitCacheAtom, + storePermitCacheAtom, + userPermitCacheAtom, +} from '../state/permitCacheAtom' +import { GeneratePermitHook, GeneratePermitHookParams, PermitHookData } from '../types' +import { generatePermitHook } from '../utils/generatePermitHook' +import { getPermitUtilsInstance } from '../utils/getPermitUtilsInstance' + +/** + * Hook that returns callback to generate permit hook data + */ +export function useGeneratePermitHook(): GeneratePermitHook { + const getCachedPermit = useSetAtom(getPermitCacheAtom) + const storePermit = useSetAtom(storePermitCacheAtom) + + // Warming up stored atoms + // + // For some reason, atoms start always in the default state (`{}`) on load, + // even if localStorage contains data, wiping previously saved data. + // Here we force an individual read of each atom, which does populate them properly + useAtomValue(staticPermitCacheAtom) + useAtomValue(userPermitCacheAtom) + + const { chainId } = useWalletInfo() + const { provider } = useWeb3React() + + return useCallback( + async (params: GeneratePermitHookParams): Promise => { + const { inputToken, account, permitInfo } = params + + if (!provider) { + return + } + + const eip2162Utils = getPermitUtilsInstance(chainId, provider, account) + + // Always get the nonce for the real account, to know whether the cache should be invalidated + // Static account should never need to pre-check the nonce as it'll never change once cached + const nonce = account ? await eip2162Utils.getTokenNonce(inputToken.address, account) : undefined + + const permitParams = { chainId, tokenAddress: inputToken.address, account, nonce } + + const cachedPermit = getCachedPermit(permitParams) + + if (cachedPermit) { + return cachedPermit + } + + const hookData = await generatePermitHook({ + chainId, + inputToken, + provider, + permitInfo, + eip2162Utils, + account, + nonce, + }) + + storePermit({ ...permitParams, hookData }) + + return hookData + }, + [storePermit, chainId, getCachedPermit, provider] + ) +} diff --git a/apps/cowswap-frontend/src/modules/permit/hooks/useIsTokenPermittable.ts b/apps/cowswap-frontend/src/modules/permit/hooks/useIsTokenPermittable.ts new file mode 100644 index 0000000000..b804d3aaf5 --- /dev/null +++ b/apps/cowswap-frontend/src/modules/permit/hooks/useIsTokenPermittable.ts @@ -0,0 +1,97 @@ +import { useAtomValue, useSetAtom } from 'jotai' +import { useEffect, useMemo } from 'react' + +import { SupportedChainId } from '@cowprotocol/cow-sdk' +import { useWalletInfo } from '@cowprotocol/wallet' +import { Currency } from '@uniswap/sdk-core' +import { useWeb3React } from '@web3-react/core' + +import { Nullish } from 'types' + +import { TradeType } from 'modules/trade' + +import { useIsPermitEnabled } from 'common/hooks/featureFlags/useIsPermitEnabled' + +import { ORDER_TYPE_SUPPORTS_PERMIT } from '../const' +import { addPermitInfoForTokenAtom, permittableTokensAtom } from '../state/permittableTokensAtom' +import { IsTokenPermittableResult } from '../types' +import { checkIsTokenPermittable } from '../utils/checkIsTokenPermittable' + +/** + * Checks whether the token is permittable, and caches the result on localStorage + * + * When it is, returned type is `{type: 'dai'|'permit', gasLimit: number} + * When it is not, returned type is `false` + * When it is unknown, returned type is `undefined` + * + */ +export function useIsTokenPermittable( + token: Nullish, + tradeType: Nullish +): IsTokenPermittableResult { + const { chainId } = useWalletInfo() + const { provider } = useWeb3React() + + const lowerCaseAddress = token?.wrapped?.address?.toLowerCase() + const isNative = token?.isNative + const tokenName = token?.name || lowerCaseAddress || '' + + // Avoid building permit info in the first place if order type is not supported + const isPermitSupported = !!tradeType && ORDER_TYPE_SUPPORTS_PERMIT[tradeType] + + const isPermitEnabled = useIsPermitEnabled(chainId) && isPermitSupported + + const addPermitInfo = useAddPermitInfo() + const permitInfo = usePermitInfo(chainId, isPermitEnabled ? lowerCaseAddress : undefined) + + useEffect(() => { + if (!chainId || !isPermitEnabled || !lowerCaseAddress || !provider || permitInfo !== undefined || isNative) { + return + } + + checkIsTokenPermittable({ tokenAddress: lowerCaseAddress, tokenName, chainId, provider }).then((result) => { + if (!result) { + // When falsy, we know it doesn't support permit. Cache it. + addPermitInfo({ chainId, tokenAddress: lowerCaseAddress, permitInfo: false }) + } else if ('error' in result) { + // When error, we don't know. Log and don't cache. + console.debug( + `useIsTokenPermittable: failed to check whether token ${lowerCaseAddress} is permittable: ${result.error}` + ) + } else { + // Otherwise, we know it is permittable. Cache it. + addPermitInfo({ chainId, tokenAddress: lowerCaseAddress, permitInfo: result }) + } + }) + }, [addPermitInfo, chainId, isNative, isPermitEnabled, lowerCaseAddress, permitInfo, provider, tokenName]) + + if (isNative) { + return false + } + // TODO: add an updater for this + return permitInfo +} + +/** + * Returns a callback for adding PermitInfo for a given token + */ +function useAddPermitInfo() { + return useSetAtom(addPermitInfoForTokenAtom) +} + +/** + * Returns whether a token is permittable. + * + * When it is, returned type is `{type: 'dai'|'permit', gasLimit: number}` + * When it is not, returned type is `false` + * When it is unknown, returned type is `undefined` + */ +function usePermitInfo(chainId: SupportedChainId, tokenAddress: string | undefined): IsTokenPermittableResult { + const permittableTokens = useAtomValue(permittableTokensAtom) + + return useMemo(() => { + if (!tokenAddress) return undefined + + return permittableTokens[chainId][tokenAddress.toLowerCase()] + }, [chainId, permittableTokens, tokenAddress]) +} diff --git a/apps/cowswap-frontend/src/modules/permit/hooks/useOrdersPermitStatus.ts b/apps/cowswap-frontend/src/modules/permit/hooks/useOrdersPermitStatus.ts new file mode 100644 index 0000000000..b61aba3797 --- /dev/null +++ b/apps/cowswap-frontend/src/modules/permit/hooks/useOrdersPermitStatus.ts @@ -0,0 +1,7 @@ +import { useAtomValue } from 'jotai' + +import { ordersPermitStatusAtom } from '../state/ordersPermitStatusAtom' + +export function useGetOrdersPermitStatus() { + return useAtomValue(ordersPermitStatusAtom) +} diff --git a/apps/cowswap-frontend/src/modules/permit/index.ts b/apps/cowswap-frontend/src/modules/permit/index.ts new file mode 100644 index 0000000000..9de2b7724e --- /dev/null +++ b/apps/cowswap-frontend/src/modules/permit/index.ts @@ -0,0 +1,7 @@ +export * from './hooks/useAccountAgnosticPermitHookData' +export * from './hooks/useGeneratePermitHook' +export * from './hooks/useIsTokenPermittable' +export * from './hooks/useOrdersPermitStatus' +export * from './types' +export * from './updaters/PendingPermitUpdater' +export * from './utils/handlePermit' diff --git a/apps/cowswap-frontend/src/modules/permit/state/ordersPermitStatusAtom.ts b/apps/cowswap-frontend/src/modules/permit/state/ordersPermitStatusAtom.ts new file mode 100644 index 0000000000..cf132cefc3 --- /dev/null +++ b/apps/cowswap-frontend/src/modules/permit/state/ordersPermitStatusAtom.ts @@ -0,0 +1,9 @@ +import { atom } from 'jotai' + +import { atomWithPartialUpdate } from '@cowprotocol/common-utils' + +import { OrdersPermitStatus } from '../types' + +export const { atom: ordersPermitStatusAtom, updateAtom: updateOrdersPermitStatusAtom } = atomWithPartialUpdate( + atom({}) +) diff --git a/apps/cowswap-frontend/src/modules/permit/state/permitCacheAtom.ts b/apps/cowswap-frontend/src/modules/permit/state/permitCacheAtom.ts new file mode 100644 index 0000000000..aac142e2a1 --- /dev/null +++ b/apps/cowswap-frontend/src/modules/permit/state/permitCacheAtom.ts @@ -0,0 +1,106 @@ +import { atom } from 'jotai' +import { atomWithStorage } from 'jotai/utils' + +import { + CachedPermitData, + GetPermitCacheParams, + PermitCache, + PermitCacheKeyParams, + StorePermitCacheParams, +} from '../types' + +/** + * Atom that stores permit data for static permit requests. + * Should never change once it has been created. + * Used exclusively for quote requests + */ +export const staticPermitCacheAtom = atomWithStorage('staticPermitCache:v0', {}) + +/** + * Atom that stores permit data for user permit requests. + * Should be updated whenever the permit nonce is updated. + * Used exclusively for order requests + */ +export const userPermitCacheAtom = atomWithStorage('userPermitCache:v0', {}) + +/** + * Atom to add/update permit cache data + * + * Input depends on the target type of cache: static or user + */ +export const storePermitCacheAtom = atom(null, (get, set, params: StorePermitCacheParams) => { + const atomToUpdate = params.account ? userPermitCacheAtom : staticPermitCacheAtom + + const key = buildKey(params) + + const dataToCache: CachedPermitData = { + hookData: params.hookData, + nonce: params.nonce, + } + + set(atomToUpdate, (permitCache) => ({ ...permitCache, [key]: JSON.stringify(dataToCache) })) +}) + +/** + * Atom to get the cached permit data. + * + * Returns either undefined when no cache or cache is outdated, or the cached permit hook data. + * + * When cache is outdated, it will remove the cache key from the target cache. + * For this reason it's a writable atom. + */ +export const getPermitCacheAtom = atom(null, (get, set, params: GetPermitCacheParams) => { + const atomToUpdate = params.account ? userPermitCacheAtom : staticPermitCacheAtom + + const permitCache = get(atomToUpdate) + const key = buildKey(params) + const cachedData = permitCache[key] + + if (!cachedData) { + return undefined + } + + try { + const { hookData, nonce: storedNonce }: CachedPermitData = JSON.parse(cachedData) + + if (params.account !== undefined) { + // User type permit cache, check the nonce + + const inputNonce = params.nonce + + if (storedNonce !== undefined && inputNonce !== undefined && storedNonce < inputNonce) { + // When both nonces exist and storedNonce < inputNonce, data is outdated + + // Remove cache key + set(atomToUpdate, removePermitCacheBuilder(key)) + + return undefined + } + } + + // Cache hit for both static and user permit types + return hookData + } catch (e) { + // Failed to parse stored data, clear cache and return nothing + + set(atomToUpdate, removePermitCacheBuilder(key)) + + console.info(`[getPermitCacheAtom] failed to parse stored data`, cachedData, e) + + return undefined + } +}) + +function buildKey({ chainId, tokenAddress, account }: PermitCacheKeyParams) { + const base = `${chainId}-${tokenAddress.toLowerCase()}` + + return account ? `${base}-${account.toLowerCase()}` : base +} + +const removePermitCacheBuilder = (key: string) => (permitCache: PermitCache) => { + const newPermitCache = { ...permitCache } + + delete newPermitCache[key] + + return newPermitCache +} diff --git a/apps/cowswap-frontend/src/modules/permit/state/permittableTokensAtom.ts b/apps/cowswap-frontend/src/modules/permit/state/permittableTokensAtom.ts new file mode 100644 index 0000000000..daf8a9de07 --- /dev/null +++ b/apps/cowswap-frontend/src/modules/permit/state/permittableTokensAtom.ts @@ -0,0 +1,33 @@ +import { atom } from 'jotai' +import { atomWithStorage } from 'jotai/utils' + +import { SupportedChainId } from '@cowprotocol/cow-sdk' + +import { AddPermitTokenParams, PermittableTokens } from '../types' + +/** + * Atom that stores the permittable tokens info for each chain on localStorage. + * It's meant to be shared across different tabs, thus no special storage handling. + * + * Contains either the permit info with `type` and `gasLimit` when supported or + * `false` when not supported + */ +export const permittableTokensAtom = atomWithStorage('permittableTokens:v0', { + [SupportedChainId.MAINNET]: {}, + [SupportedChainId.GOERLI]: {}, + [SupportedChainId.GNOSIS_CHAIN]: {}, +}) + +/** + * Helper derived atom to add a permit info for a token for a given chain + */ +export const addPermitInfoForTokenAtom = atom( + null, + (get, set, { chainId, tokenAddress, permitInfo }: AddPermitTokenParams) => { + const permittableTokens = { ...get(permittableTokensAtom) } + + permittableTokens[chainId][tokenAddress.toLowerCase()] = permitInfo + + set(permittableTokensAtom, permittableTokens) + } +) diff --git a/apps/cowswap-frontend/src/modules/permit/types.ts b/apps/cowswap-frontend/src/modules/permit/types.ts new file mode 100644 index 0000000000..d1cc15571f --- /dev/null +++ b/apps/cowswap-frontend/src/modules/permit/types.ts @@ -0,0 +1,100 @@ +import { latest } from '@cowprotocol/app-data' +import { SupportedChainId } from '@cowprotocol/cow-sdk' +import { Web3Provider } from '@ethersproject/providers' +import { Token } from '@uniswap/sdk-core' + +import { Eip2612PermitUtils } from '@1inch/permit-signed-approvals-utils' + +import { AppDataInfo } from 'modules/appData' + +import { ParsedOrder } from 'utils/orderUtils/parseOrder' + +export type PermitType = 'dai-like' | 'eip-2612' + +export type SupportedPermitInfo = { + type: PermitType + gasLimit: number +} +type UnsupportedPermitInfo = false +export type PermitInfo = SupportedPermitInfo | UnsupportedPermitInfo + +export type PermittableTokens = Record> + +export type IsTokenPermittableResult = PermitInfo | undefined + +export type AddPermitTokenParams = { + chainId: SupportedChainId + tokenAddress: string + permitInfo: PermitInfo +} + +export type PermitHookParams = { + inputToken: Token + chainId: SupportedChainId + permitInfo: SupportedPermitInfo + provider: Web3Provider + eip2162Utils: Eip2612PermitUtils + account?: string | undefined + nonce?: number | undefined +} + +export type GeneratePermitHookParams = Pick + +export type GeneratePermitHook = (params: GeneratePermitHookParams) => Promise + +export type HandlePermitParams = Omit & { + permitInfo: IsTokenPermittableResult + appData: AppDataInfo + generatePermitHook: GeneratePermitHook +} + +export type PermitHookData = latest.CoWHook + +type FailedToIdentify = { error: string } + +export type EstimatePermitResult = + // When it's a permittable token: + | SupportedPermitInfo + // When something failed: + | FailedToIdentify + // When it's not permittable: + | UnsupportedPermitInfo + +type BasePermitCallDataParams = { + eip2162Utils: Eip2612PermitUtils +} +export type BuildEip2162PermitCallDataParams = BasePermitCallDataParams & { + callDataParams: Parameters +} +export type BuildDaiLikePermitCallDataParams = BasePermitCallDataParams & { + callDataParams: Parameters +} + +export type CheckIsTokenPermittableParams = { + tokenAddress: string + tokenName: string + chainId: SupportedChainId + provider: Web3Provider +} + +export type PermitCache = Record + +export type CachedPermitData = { + hookData: PermitHookData + nonce: number | undefined +} + +export type PermitCacheKeyParams = { + chainId: SupportedChainId + tokenAddress: string + account: string | undefined + nonce: number | undefined +} + +export type StorePermitCacheParams = PermitCacheKeyParams & { hookData: PermitHookData } + +export type GetPermitCacheParams = PermitCacheKeyParams + +export type CheckHasValidPendingPermit = (order: ParsedOrder) => Promise + +export type OrdersPermitStatus = Record diff --git a/apps/cowswap-frontend/src/modules/permit/updaters/PendingPermitUpdater.ts b/apps/cowswap-frontend/src/modules/permit/updaters/PendingPermitUpdater.ts new file mode 100644 index 0000000000..b286652ed9 --- /dev/null +++ b/apps/cowswap-frontend/src/modules/permit/updaters/PendingPermitUpdater.ts @@ -0,0 +1,39 @@ +import { useSetAtom } from 'jotai' +import { useEffect, useRef } from 'react' + +import { ParsedOrder } from 'utils/orderUtils/parseOrder' + +import { PENDING_ORDER_PERMIT_CHECK_INTERVAL } from '../const' +import { useCheckHasValidPendingPermit } from '../hooks/useCheckHasValidPendingPermit' +import { updateOrdersPermitStatusAtom } from '../state/ordersPermitStatusAtom' + +export type PendingPermitUpdaterProps = { + orders: ParsedOrder[] +} + +export function PendingPermitUpdater({ orders }: PendingPermitUpdaterProps): null { + const ordersRef = useRef(orders) + ordersRef.current = orders + + const checkHasValidPendingPermit = useCheckHasValidPendingPermit() + const updateOrdersPermitStatus = useSetAtom(updateOrdersPermitStatusAtom) + + useEffect(() => { + const checkOrders = () => { + console.debug(`UpdatePendingPermit: checking orders`, ordersRef.current.length) + ordersRef.current.forEach((order) => { + checkHasValidPendingPermit(order).then((status) => { + console.debug(`UpdatePendingPermit: checked order ${order.id} with status ${status}`) + updateOrdersPermitStatus({ [order.id]: status }) + }) + }) + } + + checkOrders() + const interval = setInterval(checkOrders, PENDING_ORDER_PERMIT_CHECK_INTERVAL) + + return () => clearInterval(interval) + }, [checkHasValidPendingPermit, updateOrdersPermitStatus]) + + return null +} diff --git a/apps/cowswap-frontend/src/modules/permit/utils/buildPermitCallData.ts b/apps/cowswap-frontend/src/modules/permit/utils/buildPermitCallData.ts new file mode 100644 index 0000000000..67d5ddcca0 --- /dev/null +++ b/apps/cowswap-frontend/src/modules/permit/utils/buildPermitCallData.ts @@ -0,0 +1,26 @@ +import { DAI_PERMIT_SELECTOR, EIP_2612_PERMIT_SELECTOR } from '@1inch/permit-signed-approvals-utils' + +import { BuildDaiLikePermitCallDataParams, BuildEip2162PermitCallDataParams } from '../types' + +export async function buildEip2162PermitCallData({ + eip2162Utils, + callDataParams, +}: BuildEip2162PermitCallDataParams): Promise { + const callData = await eip2162Utils.buildPermitCallData(...callDataParams) + + // For some reason, the method above removes the permit selector prefix + // https://github.com/1inch/permit-signed-approvals-utils/blob/master/src/eip-2612-permit.utils.ts#L92 + // Adding it back + return callData.replace('0x', EIP_2612_PERMIT_SELECTOR) +} + +export async function buildDaiLikePermitCallData({ + eip2162Utils, + callDataParams, +}: BuildDaiLikePermitCallDataParams): Promise { + const callData = await eip2162Utils.buildDaiLikePermitCallData(...callDataParams) + + // Same as above, but for dai like + // https://github.com/1inch/permit-signed-approvals-utils/blob/master/src/eip-2612-permit.utils.ts#L140 + return callData.replace('0x', DAI_PERMIT_SELECTOR) +} diff --git a/apps/cowswap-frontend/src/modules/permit/utils/checkIsTokenPermittable.ts b/apps/cowswap-frontend/src/modules/permit/utils/checkIsTokenPermittable.ts new file mode 100644 index 0000000000..8093044c24 --- /dev/null +++ b/apps/cowswap-frontend/src/modules/permit/utils/checkIsTokenPermittable.ts @@ -0,0 +1,186 @@ +import { GP_VAULT_RELAYER, NATIVE_CURRENCY_BUY_ADDRESS } from '@cowprotocol/common-const' +import { SupportedChainId } from '@cowprotocol/cow-sdk' +import type { Web3Provider } from '@ethersproject/providers' + +import { DAI_LIKE_PERMIT_TYPEHASH, Eip2612PermitUtils } from '@1inch/permit-signed-approvals-utils' + +import { buildDaiLikePermitCallData, buildEip2162PermitCallData } from './buildPermitCallData' +import { getPermitDeadline } from './getPermitDeadline' +import { getPermitUtilsInstance } from './getPermitUtilsInstance' + +import { DEFAULT_PERMIT_VALUE, PERMIT_GAS_LIMIT_MIN, PERMIT_SIGNER } from '../const' +import { CheckIsTokenPermittableParams, EstimatePermitResult, PermitType } from '../types' + +const EIP_2162_PERMIT_PARAMS = { + value: DEFAULT_PERMIT_VALUE, + nonce: 0, + deadline: getPermitDeadline(), +} + +const DAI_LIKE_PERMIT_PARAMS = { + allowed: true, + nonce: 0, + expiry: getPermitDeadline(), +} + +const REQUESTS_CACHE: Record> = {} + +export async function checkIsTokenPermittable(params: CheckIsTokenPermittableParams): Promise { + const { tokenAddress, chainId } = params + if (NATIVE_CURRENCY_BUY_ADDRESS.toLowerCase() === tokenAddress.toLowerCase()) { + // We shouldn't call this for the native token, but just in case + return false + } + + const key = `${chainId}-${tokenAddress.toLowerCase()}` + + const cached = REQUESTS_CACHE[key] + + if (cached) { + return cached + } + + const request = actuallyCheckTokenIsPermittable(params) + + REQUESTS_CACHE[key] = request + + return request +} + +async function actuallyCheckTokenIsPermittable(params: CheckIsTokenPermittableParams): Promise { + const { tokenAddress, tokenName, chainId, provider } = params + + const spender = GP_VAULT_RELAYER[chainId] + + const eip2612PermitUtils = getPermitUtilsInstance(chainId, provider) + + const owner = PERMIT_SIGNER.address + + let nonce: number + + try { + nonce = await eip2612PermitUtils.getTokenNonce(tokenAddress, owner) + } catch (e) { + if (e === 'nonce not supported' || e.message === 'nonce is NaN') { + console.debug(`[checkTokenIsPermittable] Not a permittable token ${tokenAddress}`, e?.message || e) + // Here we know it's not supported, return false + // See https://github.com/1inch/permit-signed-approvals-utils/blob/b190197a45c3289867ee4e6da93f10dea51ef276/src/eip-2612-permit.utils.ts#L309 + // and https://github.com/1inch/permit-signed-approvals-utils/blob/b190197a45c3289867ee4e6da93f10dea51ef276/src/eip-2612-permit.utils.ts#L325 + return false + } + console.debug(`[checkTokenIsPermittable] Failed to get nonce for ${tokenAddress}`, e) + + // Otherwise, it might have been a network issue or another temporary failure, return error + return { error: e.message || e.toString() } + } + + const baseParams: BaseParams = { + chainId, + eip2612PermitUtils, + nonce, + spender, + tokenAddress, + tokenName, + walletAddress: owner, + } + + try { + // Try to estimate with eip-2612 first + return await estimateTokenPermit({ ...baseParams, type: 'eip-2612', provider }) + } catch (e) { + // Not eip-2612, try dai-like + console.debug(`[checkTokenIsPermittable] Failed to estimate eip-2612 permit for ${tokenAddress}`, e) + try { + return await estimateTokenPermit({ ...baseParams, type: 'dai-like', provider }) + } catch (e) { + // Not dai-like either, return error + console.debug(`[checkTokenIsPermittable] Failed to estimate dai-like permit for ${tokenAddress}`, e) + return { error: e.message || e.toString() } + } + } +} + +type BaseParams = { + tokenAddress: string + tokenName: string + chainId: SupportedChainId + walletAddress: string + spender: string + eip2612PermitUtils: Eip2612PermitUtils + nonce: number +} + +type EstimateParams = BaseParams & { + type: PermitType + provider: Web3Provider +} + +async function estimateTokenPermit(params: EstimateParams): Promise { + const { provider, chainId, walletAddress, tokenAddress, type } = params + + const getCallDataFn = type === 'eip-2612' ? getEip2612CallData : getDaiLikeCallData + + const data = await getCallDataFn(params) + + if (!data) { + return false + } + + const estimatedGas = await provider.estimateGas({ + data, + from: walletAddress, + to: tokenAddress, + }) + + const gasLimit = estimatedGas.toNumber() + + return gasLimit > PERMIT_GAS_LIMIT_MIN[chainId] + ? { + gasLimit, + type, + } + : false +} + +async function getEip2612CallData(params: BaseParams): Promise { + const { eip2612PermitUtils, walletAddress, spender, nonce, chainId, tokenName, tokenAddress } = params + return buildEip2162PermitCallData({ + eip2162Utils: eip2612PermitUtils, + callDataParams: [ + { + ...EIP_2162_PERMIT_PARAMS, + owner: walletAddress, + spender, + nonce, + }, + +chainId, + tokenName, + tokenAddress, + ], + }) +} + +async function getDaiLikeCallData(params: BaseParams): Promise { + const { eip2612PermitUtils, tokenAddress, walletAddress, spender, nonce, chainId, tokenName } = params + + const permitTypeHash = await eip2612PermitUtils.getPermitTypeHash(tokenAddress) + + if (permitTypeHash === DAI_LIKE_PERMIT_TYPEHASH) { + return buildDaiLikePermitCallData({ + eip2162Utils: eip2612PermitUtils, + callDataParams: [ + { + ...DAI_LIKE_PERMIT_PARAMS, + holder: walletAddress, + spender, + nonce, + }, + chainId as number, + tokenName, + tokenAddress, + ], + }) + } + + return false +} diff --git a/apps/cowswap-frontend/src/modules/permit/utils/generatePermitHook.ts b/apps/cowswap-frontend/src/modules/permit/utils/generatePermitHook.ts new file mode 100644 index 0000000000..7d781342aa --- /dev/null +++ b/apps/cowswap-frontend/src/modules/permit/utils/generatePermitHook.ts @@ -0,0 +1,124 @@ +import { GP_VAULT_RELAYER } from '@cowprotocol/common-const' +import { Web3Provider } from '@ethersproject/providers' + +import { buildDaiLikePermitCallData, buildEip2162PermitCallData } from './buildPermitCallData' +import { getPermitDeadline } from './getPermitDeadline' + +import { DEFAULT_PERMIT_GAS_LIMIT, DEFAULT_PERMIT_VALUE, PERMIT_SIGNER } from '../const' +import { PermitHookData, PermitHookParams } from '../types' + +const REQUESTS_CACHE: { [permitKey: string]: Promise } = {} + +export async function generatePermitHook(params: PermitHookParams): Promise { + const permitKey = getCacheKey(params) + + const cachedRequest = REQUESTS_CACHE[permitKey] + + if (cachedRequest) { + try { + return await cachedRequest + } catch (e) { + console.debug(`[generatePermitHookWith] cached request failed`, e) + delete REQUESTS_CACHE[permitKey] + } + } + + const request = generatePermitHookRaw(params).then((permitHookData) => { + // Remove consumed request to avoid stale data + delete REQUESTS_CACHE[permitKey] + + return permitHookData + }) + + REQUESTS_CACHE[permitKey] = request + + return request +} + +async function generatePermitHookRaw(params: PermitHookParams): Promise { + const { inputToken, chainId, permitInfo, provider, account, eip2162Utils, nonce: preFetchedNonce } = params + const tokenAddress = inputToken.address + const tokenName = inputToken.name || tokenAddress + + const owner = account || PERMIT_SIGNER.address + + // Only fetch the nonce in case it wasn't pre-fetched before + // That's the case for static account + const nonce = preFetchedNonce === undefined ? await eip2162Utils.getTokenNonce(tokenAddress, owner) : preFetchedNonce + + const spender = GP_VAULT_RELAYER[chainId] + const deadline = getPermitDeadline() + const value = DEFAULT_PERMIT_VALUE + + const callData = + permitInfo.type === 'eip-2612' + ? await buildEip2162PermitCallData({ + eip2162Utils, + callDataParams: [ + { + owner, + spender, + value, + nonce, + deadline, + }, + chainId as number, + tokenName, + tokenAddress, + ], + }) + : await buildDaiLikePermitCallData({ + eip2162Utils, + callDataParams: [ + { + holder: owner, + spender, + allowed: true, + value, + nonce, + expiry: deadline, + }, + chainId as number, + tokenName, + tokenAddress, + ], + }) + + const gasLimit = await calculateGasLimit(callData, owner, tokenAddress, provider, !!account) + + return { + target: tokenAddress, + callData, + gasLimit, + } +} + +async function calculateGasLimit( + data: string, + from: string, + to: string, + provider: Web3Provider, + isUserAccount: boolean +): Promise { + try { + // Query the actual gas estimate + const actual = await provider.estimateGas({ data, from, to }) + + // Add 10% to actual value to account for minor differences with real account + // Do not add it if this is the real user's account + const gasLimit = !isUserAccount ? actual.add(actual.div(10)) : actual + + // Pick the biggest between estimated and default + return gasLimit.gt(DEFAULT_PERMIT_GAS_LIMIT) ? gasLimit.toString() : DEFAULT_PERMIT_GAS_LIMIT + } catch (e) { + console.debug(`[calculatePermitGasLimit] Failed to estimateGas, using default`, e) + + return DEFAULT_PERMIT_GAS_LIMIT + } +} + +function getCacheKey(params: PermitHookParams): string { + const { inputToken, chainId, account } = params + + return `${inputToken.address.toLowerCase()}-${chainId}${account ? `-${account.toLowerCase()}` : ''}` +} diff --git a/apps/cowswap-frontend/src/modules/permit/utils/getPermitDeadline.ts b/apps/cowswap-frontend/src/modules/permit/utils/getPermitDeadline.ts new file mode 100644 index 0000000000..3c05ad4eeb --- /dev/null +++ b/apps/cowswap-frontend/src/modules/permit/utils/getPermitDeadline.ts @@ -0,0 +1,5 @@ +import { DEFAULT_PERMIT_DURATION } from '../const' + +export function getPermitDeadline() { + return Math.ceil((Date.now() + DEFAULT_PERMIT_DURATION) / 1000) +} diff --git a/apps/cowswap-frontend/src/modules/permit/utils/getPermitUtilsInstance.ts b/apps/cowswap-frontend/src/modules/permit/utils/getPermitUtilsInstance.ts new file mode 100644 index 0000000000..daeba06d33 --- /dev/null +++ b/apps/cowswap-frontend/src/modules/permit/utils/getPermitUtilsInstance.ts @@ -0,0 +1,51 @@ +import { SupportedChainId } from '@cowprotocol/cow-sdk' +import type { Web3Provider } from '@ethersproject/providers' + +import { Eip2612PermitUtils } from '@1inch/permit-signed-approvals-utils' + +import { PermitProviderConnector } from 'modules/wallet/utils/PermitProviderConnector' + +import { PERMIT_SIGNER } from '../const' + +/** + * Cache by network. Here we don't care about the provider as a static account will be used for the signature + */ +const CHAIN_UTILS_CACHE = new Map() +/** + * Cache by provider. Here we cache per provider as each account should have its own instance + */ +const PROVIDER_UTILS_CACHE = new Map() + +export function getPermitUtilsInstance( + chainId: SupportedChainId, + provider: Web3Provider, + account?: string | undefined +): Eip2612PermitUtils { + const chainCache = CHAIN_UTILS_CACHE.get(chainId) + + if (!account && chainCache) { + return chainCache + } + const providerCacheKey = `${chainId}-${account}` + const providerCache = PROVIDER_UTILS_CACHE.get(providerCacheKey) + + if (providerCache) { + return providerCache + } + + const web3ProviderConnector = new PermitProviderConnector(provider, account ? undefined : PERMIT_SIGNER) + const eip2612PermitUtils = new Eip2612PermitUtils(web3ProviderConnector) + + if (!account) { + console.log(`[getPermitUtilsInstance] Set cached chain utils for chain ${chainId}`, eip2612PermitUtils) + CHAIN_UTILS_CACHE.set(chainId, eip2612PermitUtils) + } else { + console.log( + `[getPermitUtilsInstance] Set cached provider utils for chain ${chainId}-${account}`, + eip2612PermitUtils + ) + PROVIDER_UTILS_CACHE.set(providerCacheKey, eip2612PermitUtils) + } + + return eip2612PermitUtils +} diff --git a/apps/cowswap-frontend/src/modules/permit/utils/handlePermit.ts b/apps/cowswap-frontend/src/modules/permit/utils/handlePermit.ts new file mode 100644 index 0000000000..38bc18b9c3 --- /dev/null +++ b/apps/cowswap-frontend/src/modules/permit/utils/handlePermit.ts @@ -0,0 +1,38 @@ +import { AppDataInfo, buildAppDataHooks, updateHooksOnAppData } from 'modules/appData' + +import { HandlePermitParams } from '../types' + +/** + * Handle token permit + * + * Will request user signature if needed + * Can use cached permit if available + * + * If not needed, will remove any permit info from appData + * + * Returns the updated appData + */ +export async function handlePermit(params: HandlePermitParams): Promise { + const { permitInfo, inputToken, account, appData, generatePermitHook } = params + + if (permitInfo) { + // permitInfo will only be set if there's NOT enough allowance + + const permitData = await generatePermitHook({ + inputToken, + account, + permitInfo, + }) + + if (!permitData) { + throw new Error(`Unable to generate permit data`) + } + + const hooks = buildAppDataHooks([permitData]) + + return updateHooksOnAppData(appData, hooks) + } else { + // Otherwise, remove hooks (if any) from appData to avoid stale data + return updateHooksOnAppData(appData, undefined) + } +} diff --git a/apps/cowswap-frontend/src/modules/swap/containers/EthFlow/hooks/useEthFlowActions.ts b/apps/cowswap-frontend/src/modules/swap/containers/EthFlow/hooks/useEthFlowActions.ts index 557a19e047..0bea93ab97 100644 --- a/apps/cowswap-frontend/src/modules/swap/containers/EthFlow/hooks/useEthFlowActions.ts +++ b/apps/cowswap-frontend/src/modules/swap/containers/EthFlow/hooks/useEthFlowActions.ts @@ -2,17 +2,18 @@ import { useSetAtom } from 'jotai' import { useAtomValue } from 'jotai' import { useMemo } from 'react' -import { WRAPPED_NATIVE_CURRENCY } from 'legacy/constants/tokens' +import { WRAPPED_NATIVE_CURRENCY } from '@cowprotocol/common-const' +import { useWalletInfo } from '@cowprotocol/wallet' + import { WrapUnwrapCallback } from 'legacy/hooks/useWrapCallback' -import { Field } from 'legacy/state/swap/actions' -import { useDerivedSwapInfo, useSwapActionHandlers } from 'legacy/state/swap/hooks' +import { Field } from 'legacy/state/types' import { useSwapConfirmManager } from 'modules/swap/hooks/useSwapConfirmManager' import { HandleSwapCallback } from 'modules/swap/pure/SwapButtons' -import { useWalletInfo } from 'modules/wallet' import { TradeApproveCallback } from 'common/containers/TradeApprove/useTradeApproveCallback' +import { useDerivedSwapInfo, useSwapActionHandlers } from '../../../hooks/useSwapState' import { ethFlowContextAtom, updateEthFlowContextAtom } from '../../../state/EthFlow/ethFlowContextAtom' export interface EthFlowActionCallbacks { diff --git a/apps/cowswap-frontend/src/modules/swap/containers/EthFlow/hooks/useRemainingNativeTxsAndCosts.ts b/apps/cowswap-frontend/src/modules/swap/containers/EthFlow/hooks/useRemainingNativeTxsAndCosts.ts index 489f2f2408..58376d2694 100644 --- a/apps/cowswap-frontend/src/modules/swap/containers/EthFlow/hooks/useRemainingNativeTxsAndCosts.ts +++ b/apps/cowswap-frontend/src/modules/swap/containers/EthFlow/hooks/useRemainingNativeTxsAndCosts.ts @@ -1,15 +1,14 @@ import { useMemo } from 'react' +import { AVG_APPROVE_COST_GWEI } from '@cowprotocol/common-const' +import { useWalletInfo } from '@cowprotocol/wallet' import { BigNumber } from '@ethersproject/bignumber' import { CurrencyAmount, Currency } from '@uniswap/sdk-core' import { parseUnits } from 'ethers/lib/utils' -import { AVG_APPROVE_COST_GWEI } from 'legacy/constants' import { useGasPrices } from 'legacy/state/gas/hooks' -import { useWalletInfo } from 'modules/wallet' - import { BalanceChecks } from '../../../pure/EthFlow/EthFlowModalContent/EthFlowModalTopContent' export const MINIMUM_TXS = '10' diff --git a/apps/cowswap-frontend/src/modules/swap/containers/EthFlow/hooks/useSetupEthFlow.ts b/apps/cowswap-frontend/src/modules/swap/containers/EthFlow/hooks/useSetupEthFlow.ts index 72b41992d7..88c2d2e034 100644 --- a/apps/cowswap-frontend/src/modules/swap/containers/EthFlow/hooks/useSetupEthFlow.ts +++ b/apps/cowswap-frontend/src/modules/swap/containers/EthFlow/hooks/useSetupEthFlow.ts @@ -1,9 +1,10 @@ import { useAtomValue, useSetAtom } from 'jotai' import { useEffect, useState } from 'react' +import { delay } from '@cowprotocol/common-utils' + import { ApprovalState } from 'legacy/hooks/useApproveCallback/useApproveCallbackMod' import { ActivityDescriptors, ActivityStatus } from 'legacy/hooks/useRecentActivity' -import { delay } from 'legacy/utils/misc' import { EthFlowActions } from './useEthFlowActions' diff --git a/apps/cowswap-frontend/src/modules/swap/containers/EthFlow/index.tsx b/apps/cowswap-frontend/src/modules/swap/containers/EthFlow/index.tsx index ab11eed1bf..09af53c8e8 100644 --- a/apps/cowswap-frontend/src/modules/swap/containers/EthFlow/index.tsx +++ b/apps/cowswap-frontend/src/modules/swap/containers/EthFlow/index.tsx @@ -1,6 +1,7 @@ import { useAtomValue } from 'jotai' import { useMemo } from 'react' +import { useWalletInfo } from '@cowprotocol/wallet' import { Currency, CurrencyAmount } from '@uniswap/sdk-core' import { useSingleActivityDescriptor } from 'legacy/hooks/useRecentActivity' @@ -14,7 +15,6 @@ import { HandleSwapCallback } from 'modules/swap/pure/SwapButtons' import { ethFlowContextAtom } from 'modules/swap/state/EthFlow/ethFlowContextAtom' import { useCurrencyBalances } from 'modules/tokens/hooks/useCurrencyBalance' import { useWrappedToken } from 'modules/trade/hooks/useWrappedToken' -import { useWalletInfo } from 'modules/wallet' import { useTradeApproveCallback, useTradeApproveState } from 'common/containers/TradeApprove' import { CowModal } from 'common/pure/Modal' diff --git a/apps/cowswap-frontend/src/modules/swap/containers/EthFlowStepper/index.tsx b/apps/cowswap-frontend/src/modules/swap/containers/EthFlowStepper/index.tsx index e685f0d5a9..46b09bfcb2 100644 --- a/apps/cowswap-frontend/src/modules/swap/containers/EthFlowStepper/index.tsx +++ b/apps/cowswap-frontend/src/modules/swap/containers/EthFlowStepper/index.tsx @@ -1,4 +1,6 @@ -import { NATIVE_CURRENCY_BUY_ADDRESS } from 'legacy/constants' +import { NATIVE_CURRENCY_BUY_ADDRESS } from '@cowprotocol/common-const' +import { formatSymbol } from '@cowprotocol/common-utils' + import { useAllTransactions } from 'legacy/state/enhancedTransactions/hooks' import { EnhancedTransactionDetails } from 'legacy/state/enhancedTransactions/reducer' import { Order, OrderStatus } from 'legacy/state/orders/actions' @@ -11,7 +13,6 @@ import { } from 'modules/swap/pure/EthFlow/EthFlowStepper' import useNativeCurrency from 'lib/hooks/useNativeCurrency' -import { formatSymbol } from 'utils/format' type EthFlowStepperProps = { order: Order | undefined diff --git a/apps/cowswap-frontend/src/modules/swap/containers/FeesDiscount/index.tsx b/apps/cowswap-frontend/src/modules/swap/containers/FeesDiscount/index.tsx index 603d9a73f7..b25922ad7f 100644 --- a/apps/cowswap-frontend/src/modules/swap/containers/FeesDiscount/index.tsx +++ b/apps/cowswap-frontend/src/modules/swap/containers/FeesDiscount/index.tsx @@ -1,24 +1,27 @@ +import { AutoRow } from '@cowprotocol/ui' +import { MouseoverTooltipContent } from '@cowprotocol/ui' + import { Trans } from '@lingui/macro' import { BoxProps, Text } from 'rebass' import styled, { DefaultTheme } from 'styled-components/macro' import { SUBSIDY_INFO_MESSAGE } from 'legacy/components/CowSubsidyModal/constants' -import { AutoRow } from 'legacy/components/Row' -import { MouseoverTooltipContent } from 'legacy/components/Tooltip' import useCowBalanceAndSubsidy from 'legacy/hooks/useCowBalanceAndSubsidy' import { StyledInfoIcon } from 'modules/swap/pure/styled' import { LowerSectionWrapper } from 'modules/swap/pure/styled' +import { UI } from 'common/constants/theme' + interface FeesDiscountProps extends BoxProps { theme: DefaultTheme } const DarkSpan = styled.span` padding: 2px 8px; - background: ${({ theme }) => theme.grey1}; + background: var(${UI.COLOR_GREY}); border-radius: 5px; - color: ${({ theme }) => theme.text1}; + color: var(${UI.COLOR_TEXT1}); transition: background 0.2s ease-in-out, color 0.2s ease-in-out; &:hover { diff --git a/apps/cowswap-frontend/src/modules/swap/containers/Row/RowFee/index.tsx b/apps/cowswap-frontend/src/modules/swap/containers/Row/RowFee/index.tsx index 59b641ddeb..52e7136694 100644 --- a/apps/cowswap-frontend/src/modules/swap/containers/Row/RowFee/index.tsx +++ b/apps/cowswap-frontend/src/modules/swap/containers/Row/RowFee/index.tsx @@ -1,5 +1,8 @@ import { useMemo } from 'react' +import { formatFiatAmount, formatTokenAmount } from '@cowprotocol/common-utils' +import { FractionUtils } from '@cowprotocol/common-utils' +import { formatSymbol } from '@cowprotocol/common-utils' import { Currency, CurrencyAmount, Token, TradeType } from '@uniswap/sdk-core' import TradeGp from 'legacy/state/swap/TradeGp' @@ -9,9 +12,6 @@ import { RowFeeContent } from 'modules/swap/pure/Row/RowFeeContent' import { RowWithShowHelpersProps } from 'modules/swap/pure/Row/types' import useNativeCurrency from 'lib/hooks/useNativeCurrency' -import { formatFiatAmount, formatTokenAmount } from 'utils/amountFormat' -import { formatSymbol } from 'utils/format' -import { FractionUtils } from 'utils/fractionUtils' export const GASLESS_FEE_TOOLTIP_MSG = 'On CoW Swap you sign your order (hence no gas costs!). The fees are covering your gas costs already.' diff --git a/apps/cowswap-frontend/src/modules/swap/containers/Row/RowReceivedAfterSlippage/index.tsx b/apps/cowswap-frontend/src/modules/swap/containers/Row/RowReceivedAfterSlippage/index.tsx index 046ff8937c..f81ee43f1b 100644 --- a/apps/cowswap-frontend/src/modules/swap/containers/Row/RowReceivedAfterSlippage/index.tsx +++ b/apps/cowswap-frontend/src/modules/swap/containers/Row/RowReceivedAfterSlippage/index.tsx @@ -2,8 +2,8 @@ import { useMemo } from 'react' import { Percent, TradeType } from '@uniswap/sdk-core' -import { Field } from 'legacy/state/swap/actions' import TradeGp from 'legacy/state/swap/TradeGp' +import { Field } from 'legacy/state/types' import { computeSlippageAdjustedAmounts } from 'legacy/utils/prices' import { RowReceivedAfterSlippageContent } from 'modules/swap/pure/Row/RowReceivedAfterSlippageContent' diff --git a/apps/cowswap-frontend/src/modules/swap/containers/Row/RowSlippage/index.tsx b/apps/cowswap-frontend/src/modules/swap/containers/Row/RowSlippage/index.tsx index ffe552649a..e5f9dbcfc9 100644 --- a/apps/cowswap-frontend/src/modules/swap/containers/Row/RowSlippage/index.tsx +++ b/apps/cowswap-frontend/src/modules/swap/containers/Row/RowSlippage/index.tsx @@ -1,5 +1,6 @@ import { useMemo } from 'react' +import { formatPercent } from '@cowprotocol/common-utils' import { Percent } from '@uniswap/sdk-core' import { useToggleSettingsMenu } from 'legacy/state/application/hooks' @@ -8,7 +9,6 @@ import { useIsEoaEthFlow } from 'modules/swap/hooks/useIsEoaEthFlow' import { RowSlippageContent } from 'modules/swap/pure/Row/RowSlippageContent' import useNativeCurrency from 'lib/hooks/useNativeCurrency' -import { formatPercent } from 'utils/amountFormat' export interface RowSlippageProps { allowedSlippage: Percent diff --git a/apps/cowswap-frontend/src/modules/swap/containers/SetRecipient/index.tsx b/apps/cowswap-frontend/src/modules/swap/containers/SetRecipient/index.tsx index 1583782fa0..55b110aa4b 100644 --- a/apps/cowswap-frontend/src/modules/swap/containers/SetRecipient/index.tsx +++ b/apps/cowswap-frontend/src/modules/swap/containers/SetRecipient/index.tsx @@ -1,10 +1,11 @@ import { useContext } from 'react' +import { AutoRow } from '@cowprotocol/ui' + import { ArrowDown } from 'react-feather' import { ThemeContext } from 'styled-components/macro' import { AddressInputPanel } from 'legacy/components/AddressInputPanel' -import { AutoRow } from 'legacy/components/Row' import { ArrowWrapper } from 'legacy/components/swap/styleds' export interface SetRecipientProps { diff --git a/apps/cowswap-frontend/src/modules/swap/containers/SurplusModalSetup/index.tsx b/apps/cowswap-frontend/src/modules/swap/containers/SurplusModalSetup/index.tsx index cad0a44151..65f41ef968 100644 --- a/apps/cowswap-frontend/src/modules/swap/containers/SurplusModalSetup/index.tsx +++ b/apps/cowswap-frontend/src/modules/swap/containers/SurplusModalSetup/index.tsx @@ -1,8 +1,8 @@ import { useCallback, useEffect } from 'react' -import { useOrder } from 'legacy/state/orders/hooks' +import { useWalletInfo } from '@cowprotocol/wallet' -import { useWalletInfo } from 'modules/wallet' +import { useOrder } from 'legacy/state/orders/hooks' import { useGetSurplusData } from 'common/hooks/useGetSurplusFiatValue' import { CowModal } from 'common/pure/Modal' diff --git a/apps/cowswap-frontend/src/modules/swap/containers/SwapModals/index.tsx b/apps/cowswap-frontend/src/modules/swap/containers/SwapModals/index.tsx index bfb450a0b3..420510807f 100644 --- a/apps/cowswap-frontend/src/modules/swap/containers/SwapModals/index.tsx +++ b/apps/cowswap-frontend/src/modules/swap/containers/SwapModals/index.tsx @@ -1,10 +1,10 @@ import React from 'react' +import { genericPropsChecker } from '@cowprotocol/common-utils' + import { ConfirmSwapModalSetup, ConfirmSwapModalSetupProps } from 'modules/swap/containers/ConfirmSwapModalSetup' import { EthFlowModal, EthFlowProps } from 'modules/swap/containers/EthFlow' -import { genericPropsChecker } from 'utils/genericPropsChecker' - import { SurplusModalSetup } from '../SurplusModalSetup' export interface SwapModalsProps { diff --git a/apps/cowswap-frontend/src/modules/swap/containers/SwapWidget/index.tsx b/apps/cowswap-frontend/src/modules/swap/containers/SwapWidget/index.tsx index c3e1bf2ce2..07a12bff92 100644 --- a/apps/cowswap-frontend/src/modules/swap/containers/SwapWidget/index.tsx +++ b/apps/cowswap-frontend/src/modules/swap/containers/SwapWidget/index.tsx @@ -1,20 +1,15 @@ import React, { useMemo, useState } from 'react' +import { isFractionFalsy } from '@cowprotocol/common-utils' +import { useIsSafeViaWc, useWalletDetails, useWalletInfo } from '@cowprotocol/wallet' + import { NetworkAlert } from 'legacy/components/NetworkAlert/NetworkAlert' import SettingsTab from 'legacy/components/Settings' import useCowBalanceAndSubsidy from 'legacy/hooks/useCowBalanceAndSubsidy' import { useModalIsOpen } from 'legacy/state/application/hooks' import { ApplicationModal } from 'legacy/state/application/reducer' import { useIsTradeUnsupported } from 'legacy/state/lists/hooks' -import { Field } from 'legacy/state/swap/actions' -import { - useDerivedSwapInfo, - useHighFeeWarning, - useIsFeeGreaterThanInput, - useSwapActionHandlers, - useSwapState, - useUnknownImpactWarning, -} from 'legacy/state/swap/hooks' +import { Field } from 'legacy/state/types' import { useExpertModeManager, useUserSlippageTolerance } from 'legacy/state/user/hooks' import { ConfirmSwapModalSetupProps } from 'modules/swap/containers/ConfirmSwapModalSetup' @@ -40,15 +35,21 @@ import { TradeWidget, TradeWidgetContainer, useTradePriceImpact } from 'modules/ import { useTradeRouteContext } from 'modules/trade/hooks/useTradeRouteContext' import { useWrappedToken } from 'modules/trade/hooks/useWrappedToken' import { useTradeUsdAmounts } from 'modules/usdAmount' -import { useIsSafeViaWc, useWalletDetails, useWalletInfo } from 'modules/wallet' import { useRateInfoParams } from 'common/hooks/useRateInfoParams' import { useShouldZeroApprove } from 'common/hooks/useShouldZeroApprove' import { CurrencyInfo } from 'common/pure/CurrencyInputPanel/types' import useNativeCurrency from 'lib/hooks/useNativeCurrency' -import { isFractionFalsy } from 'utils/isFractionFalsy' import { useIsSwapEth } from '../../hooks/useIsSwapEth' +import { + useDerivedSwapInfo, + useHighFeeWarning, + useIsFeeGreaterThanInput, + useSwapActionHandlers, + useSwapState, + useUnknownImpactWarning, +} from '../../hooks/useSwapState' const BUTTON_STATES_TO_SHOW_BUNDLE_APPROVAL_BANNER = [ SwapButtonState.ApproveAndSwap, diff --git a/apps/cowswap-frontend/src/modules/swap/containers/SwapWidget/propsChecker.ts b/apps/cowswap-frontend/src/modules/swap/containers/SwapWidget/propsChecker.ts index ff7ed8ff2b..9b292674e1 100644 --- a/apps/cowswap-frontend/src/modules/swap/containers/SwapWidget/propsChecker.ts +++ b/apps/cowswap-frontend/src/modules/swap/containers/SwapWidget/propsChecker.ts @@ -1,11 +1,12 @@ +import { genericPropsChecker } from '@cowprotocol/common-utils' +import { areFractionsEqual } from '@cowprotocol/common-utils' + import { PriceImpact } from 'legacy/hooks/usePriceImpact' import { SwapFormProps } from 'modules/swap/containers/SwapWidget/types' import { ReceiveAmountInfo } from 'modules/swap/helpers/tradeReceiveAmount' import { CurrencyInfo } from 'common/pure/CurrencyInputPanel/types' -import { areFractionsEqual } from 'utils/areFractionsEqual' -import { genericPropsChecker } from 'utils/genericPropsChecker' function isReceiveAmountInfoEqual(prev: ReceiveAmountInfo | null, next: ReceiveAmountInfo | null): boolean { if (!prev || !next) { diff --git a/apps/cowswap-frontend/src/modules/swap/containers/SwapWidget/types.ts b/apps/cowswap-frontend/src/modules/swap/containers/SwapWidget/types.ts index 059cfabd08..b610f65bd1 100644 --- a/apps/cowswap-frontend/src/modules/swap/containers/SwapWidget/types.ts +++ b/apps/cowswap-frontend/src/modules/swap/containers/SwapWidget/types.ts @@ -2,10 +2,11 @@ import { Currency, CurrencyAmount, Percent } from '@uniswap/sdk-core' import { BalanceAndSubsidy } from 'legacy/hooks/useCowBalanceAndSubsidy' import { PriceImpact } from 'legacy/hooks/usePriceImpact' -import { SwapActions } from 'legacy/state/swap/hooks' import { CurrencyInfo } from 'common/pure/CurrencyInputPanel/types' +import { SwapActions } from '../../hooks/useSwapState' + export interface SwapFormProps { chainId: number | undefined recipient: string | null diff --git a/apps/cowswap-frontend/src/modules/swap/containers/TradeBasicDetails/index.tsx b/apps/cowswap-frontend/src/modules/swap/containers/TradeBasicDetails/index.tsx index 9d7893925b..7904ad0440 100644 --- a/apps/cowswap-frontend/src/modules/swap/containers/TradeBasicDetails/index.tsx +++ b/apps/cowswap-frontend/src/modules/swap/containers/TradeBasicDetails/index.tsx @@ -1,8 +1,8 @@ +import { INITIAL_ALLOWED_SLIPPAGE_PERCENT } from '@cowprotocol/common-const' import { Currency, CurrencyAmount, Percent } from '@uniswap/sdk-core' import { BoxProps } from 'rebass' -import { INITIAL_ALLOWED_SLIPPAGE_PERCENT } from 'legacy/constants' import TradeGp from 'legacy/state/swap/TradeGp' import { RowFee } from 'modules/swap/containers/Row/RowFee' diff --git a/apps/cowswap-frontend/src/modules/swap/containers/TradeSummary/index.tsx b/apps/cowswap-frontend/src/modules/swap/containers/TradeSummary/index.tsx index 376e8041a2..b8bb423882 100644 --- a/apps/cowswap-frontend/src/modules/swap/containers/TradeSummary/index.tsx +++ b/apps/cowswap-frontend/src/modules/swap/containers/TradeSummary/index.tsx @@ -1,10 +1,10 @@ +import { useWalletDetails } from '@cowprotocol/wallet' import { Percent } from '@uniswap/sdk-core' import TradeGp from 'legacy/state/swap/TradeGp' import { TradeSummaryContent } from 'modules/swap/pure/TradeSummary' import { useUsdAmount } from 'modules/usdAmount' -import { useWalletDetails } from 'modules/wallet' // Sub-components diff --git a/apps/cowswap-frontend/src/modules/swap/helpers/getSwapButtonState.ts b/apps/cowswap-frontend/src/modules/swap/helpers/getSwapButtonState.ts index 7f5b8eb78f..fe2112b2f2 100644 --- a/apps/cowswap-frontend/src/modules/swap/helpers/getSwapButtonState.ts +++ b/apps/cowswap-frontend/src/modules/swap/helpers/getSwapButtonState.ts @@ -40,8 +40,7 @@ export interface SwapButtonStateParams { isReadonlyGnosisSafeUser: boolean isExpertMode: boolean isSwapUnsupported: boolean - isTxBundlingEnabled: boolean - isEthFlowBundlingEnabled: boolean + isBundlingSupported: boolean quoteError: QuoteError | undefined | null inputError?: string approvalState: ApprovalState @@ -54,6 +53,7 @@ export interface SwapButtonStateParams { isSmartContractWallet: boolean isBestQuoteLoading: boolean wrappedToken: Token + isPermitSupported: boolean } const quoteErrorToSwapButtonState: { [key in QuoteError]: SwapButtonState | null } = { @@ -67,12 +67,14 @@ const quoteErrorToSwapButtonState: { [key in QuoteError]: SwapButtonState | null } export function getSwapButtonState(input: SwapButtonStateParams): SwapButtonState { - const { quoteError, approvalState } = input + const { quoteError, approvalState, isPermitSupported } = input // show approve flow when: no error on inputs, not approved or pending, or approved in current session // never show if price impact is above threshold in non expert mode const showApproveFlow = - !input.inputError && (approvalState === ApprovalState.NOT_APPROVED || approvalState === ApprovalState.PENDING) + !isPermitSupported && + !input.inputError && + (approvalState === ApprovalState.NOT_APPROVED || approvalState === ApprovalState.PENDING) const isValid = !input.inputError && input.feeWarningAccepted && input.impactWarningAccepted const swapBlankState = !input.inputError && !input.trade @@ -104,12 +106,8 @@ export function getSwapButtonState(input: SwapButtonStateParams): SwapButtonStat } if (!input.isNativeIn && showApproveFlow) { - if (input.isTxBundlingEnabled) { - // TODO: decide if this should be done re-using the current approval flow state or whether do it custom with bundling - if (input.isExpertMode) { - return SwapButtonState.ExpertApproveAndSwap - } - return SwapButtonState.ApproveAndSwap + if (input.isBundlingSupported) { + return input.isExpertMode ? SwapButtonState.ExpertApproveAndSwap : SwapButtonState.ApproveAndSwap } return SwapButtonState.NeedApprove } @@ -125,7 +123,7 @@ export function getSwapButtonState(input: SwapButtonStateParams): SwapButtonStat if (input.isNativeIn) { if (getEthFlowEnabled(input.isSmartContractWallet)) { return input.isExpertMode ? SwapButtonState.ExpertModeEthFlowSwap : SwapButtonState.RegularEthFlowSwap - } else if (input.isEthFlowBundlingEnabled) { + } else if (input.isBundlingSupported) { return input.isExpertMode ? SwapButtonState.ExpertWrapAndSwap : SwapButtonState.WrapAndSwap } else { return SwapButtonState.SwapWithWrappedToken diff --git a/apps/cowswap-frontend/src/modules/swap/helpers/tradeReceiveAmount.test.ts b/apps/cowswap-frontend/src/modules/swap/helpers/tradeReceiveAmount.test.ts index 2bd20f1c70..a1e1da4f79 100644 --- a/apps/cowswap-frontend/src/modules/swap/helpers/tradeReceiveAmount.test.ts +++ b/apps/cowswap-frontend/src/modules/swap/helpers/tradeReceiveAmount.test.ts @@ -1,9 +1,9 @@ import { ReactElement } from 'react' +import { COW, GNO } from '@cowprotocol/common-const' import { SupportedChainId } from '@cowprotocol/cow-sdk' import { CurrencyAmount, Price, Token, TradeType } from '@uniswap/sdk-core' -import { COW, GNO } from 'legacy/constants/tokens' import TradeGp from 'legacy/state/swap/TradeGp' import { getInputReceiveAmountInfo, getOutputReceiveAmountInfo } from './tradeReceiveAmount' diff --git a/apps/cowswap-frontend/src/modules/swap/helpers/tradeReceiveAmount.tsx b/apps/cowswap-frontend/src/modules/swap/helpers/tradeReceiveAmount.tsx index 2ea808af17..aa2627c132 100644 --- a/apps/cowswap-frontend/src/modules/swap/helpers/tradeReceiveAmount.tsx +++ b/apps/cowswap-frontend/src/modules/swap/helpers/tradeReceiveAmount.tsx @@ -1,11 +1,10 @@ import { ReactNode } from 'react' +import { TokenAmount, TokenAmountProps } from '@cowprotocol/ui' import { Currency, CurrencyAmount, TradeType } from '@uniswap/sdk-core' import TradeGp from 'legacy/state/swap/TradeGp' -import { TokenAmount, TokenAmountProps } from 'common/pure/TokenAmount' - export interface ReceiveAmountInfo { type: 'from' | 'to' amountBeforeFees: ReactNode diff --git a/apps/cowswap-frontend/src/modules/swap/hooks/useBaseSafeBundleFlowContext.ts b/apps/cowswap-frontend/src/modules/swap/hooks/useBaseSafeBundleFlowContext.ts index 45f6e06254..a1369547a6 100644 --- a/apps/cowswap-frontend/src/modules/swap/hooks/useBaseSafeBundleFlowContext.ts +++ b/apps/cowswap-frontend/src/modules/swap/hooks/useBaseSafeBundleFlowContext.ts @@ -1,12 +1,11 @@ +import { useGP2SettlementContract } from '@cowprotocol/common-hooks' import { OrderKind } from '@cowprotocol/cow-sdk' +import { useSafeAppsSdk } from '@cowprotocol/wallet' import { TradeType } from '@uniswap/sdk-core' import { useWeb3React } from '@web3-react/core' -import { useGP2SettlementContract } from 'legacy/hooks/useContract' - import { getFlowContext, useBaseFlowContextSetup } from 'modules/swap/hooks/useFlowContext' import { BaseSafeFlowContext } from 'modules/swap/services/types' -import { useSafeAppsSdk } from 'modules/wallet/web3-react/hooks/useSafeAppsSdk' import { useTradeSpenderAddress } from 'common/hooks/useTradeSpenderAddress' diff --git a/apps/cowswap-frontend/src/modules/swap/hooks/useCheckEthFlowOrderExists.ts b/apps/cowswap-frontend/src/modules/swap/hooks/useCheckEthFlowOrderExists.ts new file mode 100644 index 0000000000..088ad2711b --- /dev/null +++ b/apps/cowswap-frontend/src/modules/swap/hooks/useCheckEthFlowOrderExists.ts @@ -0,0 +1,39 @@ +import { useAtomValue } from 'jotai' +import { useCallback } from 'react' + +import { ZERO_ADDRESS } from '@cowprotocol/common-const' +import { useEthFlowContract } from '@cowprotocol/common-hooks' + +import { ethFlowInFlightOrderIdsAtom } from '../state/EthFlow/ethFlowInFlightOrderIdsAtom' + +export interface EthFlowOrderExistsCallback { + (orderId: string, orderDigest: string): Promise +} + +export function useCheckEthFlowOrderExists(): EthFlowOrderExistsCallback { + const ethFlowInFlightOrderIds = useAtomValue(ethFlowInFlightOrderIdsAtom) + const ethFlowContract = useEthFlowContract() + + return useCallback( + async (orderId: string, orderDigest: string) => { + if (ethFlowInFlightOrderIds.includes(orderId)) { + return true + } + + if (ethFlowContract) { + try { + const { owner } = await ethFlowContract.callStatic.orders(orderDigest) + + return owner.toLowerCase() !== ZERO_ADDRESS + } catch (e) { + console.error('Eth-flow order existing check error: ', e) + + return false + } + } + + return false + }, + [ethFlowInFlightOrderIds, ethFlowContract] + ) +} diff --git a/apps/cowswap-frontend/src/modules/swap/hooks/useEthFlowContext.ts b/apps/cowswap-frontend/src/modules/swap/hooks/useEthFlowContext.ts index 93adb7d077..7cd8122b69 100644 --- a/apps/cowswap-frontend/src/modules/swap/hooks/useEthFlowContext.ts +++ b/apps/cowswap-frontend/src/modules/swap/hooks/useEthFlowContext.ts @@ -1,31 +1,25 @@ -import { useAtomValue, useSetAtom } from 'jotai' -import { useCallback } from 'react' +import { useSetAtom } from 'jotai' +import { NATIVE_CURRENCY_BUY_TOKEN } from '@cowprotocol/common-const' +import { useEthFlowContract } from '@cowprotocol/common-hooks' import { OrderKind } from '@cowprotocol/cow-sdk' -import { NATIVE_CURRENCY_BUY_TOKEN } from 'legacy/constants' -import { useEthFlowContract } from 'legacy/hooks/useContract' import { useTransactionAdder } from 'legacy/state/enhancedTransactions/hooks' import { FlowType, getFlowContext, useBaseFlowContextSetup } from 'modules/swap/hooks/useFlowContext' import { EthFlowContext } from 'modules/swap/services/types' -import { - addInFlightOrderIdAtom, - ethFlowInFlightOrderIdsAtom, -} from 'modules/swap/state/EthFlow/ethFlowInFlightOrderIdsAtom' +import { addInFlightOrderIdAtom } from 'modules/swap/state/EthFlow/ethFlowInFlightOrderIdsAtom' + +import { useCheckEthFlowOrderExists } from './useCheckEthFlowOrderExists' export function useEthFlowContext(): EthFlowContext | null { const contract = useEthFlowContract() const baseProps = useBaseFlowContextSetup() const addTransaction = useTransactionAdder() - const ethFlowInFlightOrderIds = useAtomValue(ethFlowInFlightOrderIdsAtom) const addInFlightOrderId = useSetAtom(addInFlightOrderIdAtom) - const checkInFlightOrderIdExists = useCallback( - (orderId: string) => ethFlowInFlightOrderIds.includes(orderId), - [ethFlowInFlightOrderIds] - ) + const checkEthFlowOrderExists = useCheckEthFlowOrderExists() const baseContext = getFlowContext({ baseProps, @@ -39,7 +33,7 @@ export function useEthFlowContext(): EthFlowContext | null { ...baseContext, contract, addTransaction, - checkInFlightOrderIdExists, + checkEthFlowOrderExists, addInFlightOrderId, } } diff --git a/apps/cowswap-frontend/src/modules/swap/hooks/useFlowContext.ts b/apps/cowswap-frontend/src/modules/swap/hooks/useFlowContext.ts index 8e6b4f1af9..5b4f2fd8e0 100644 --- a/apps/cowswap-frontend/src/modules/swap/hooks/useFlowContext.ts +++ b/apps/cowswap-frontend/src/modules/swap/hooks/useFlowContext.ts @@ -1,5 +1,10 @@ +import { Erc20, Weth } from '@cowprotocol/abis' +import { GpEther as ETHER, NATIVE_CURRENCY_BUY_TOKEN } from '@cowprotocol/common-const' +import { useTokenContract, useWETHContract } from '@cowprotocol/common-hooks' +import { calculateValidTo, getAddress } from '@cowprotocol/common-utils' import { OrderClass, OrderKind } from '@cowprotocol/cow-sdk' -import { Weth } from '@cowswap/abis' +import { useENSAddress } from '@cowprotocol/ens' +import { useGnosisSafeInfo, useWalletDetails, useWalletInfo } from '@cowprotocol/wallet' import { Web3Provider } from '@ethersproject/providers' import { SafeInfoResponse } from '@safe-global/api-kit' import { Currency, CurrencyAmount, Token } from '@uniswap/sdk-core' @@ -7,14 +12,9 @@ import { useWeb3React } from '@web3-react/core' import { useDispatch } from 'react-redux' -import { NATIVE_CURRENCY_BUY_TOKEN } from 'legacy/constants' -import { GpEther as ETHER } from 'legacy/constants/tokens' -import { useWETHContract } from 'legacy/hooks/useContract' -import useENSAddress from 'legacy/hooks/useENSAddress' import { AppDispatch } from 'legacy/state' import { useCloseModals } from 'legacy/state/application/hooks' import { AddOrderCallback, useAddPendingOrder } from 'legacy/state/orders/hooks' -import { useDerivedSwapInfo, useSwapState } from 'legacy/state/swap/hooks' import TradeGp from 'legacy/state/swap/TradeGp' import { useUserTransactionTTL } from 'legacy/state/user/hooks' import { computeSlippageAdjustedAmounts } from 'legacy/utils/prices' @@ -27,11 +27,9 @@ import { useIsEoaEthFlow } from 'modules/swap/hooks/useIsEoaEthFlow' import { SwapConfirmManager, useSwapConfirmManager } from 'modules/swap/hooks/useSwapConfirmManager' import { BaseFlowContext } from 'modules/swap/services/types' import { SwapFlowAnalyticsContext } from 'modules/trade/utils/analytics' -import { useGnosisSafeInfo, useWalletDetails, useWalletInfo } from 'modules/wallet' - -import { calculateValidTo } from 'utils/time' import { useIsSafeEthFlow } from './useIsSafeEthFlow' +import { useDerivedSwapInfo, useSwapState } from './useSwapState' const _computeInputAmountForSignature = (params: { input: CurrencyAmount @@ -63,6 +61,7 @@ export enum FlowType { interface BaseFlowContextSetup { chainId: number | undefined account: string | undefined + sellTokenContract: Erc20 | null provider: Web3Provider | undefined trade: TradeGp | undefined appData: AppDataInfo | null @@ -109,6 +108,7 @@ export function useBaseFlowContextSetup(): BaseFlowContextSetup { trade, allowedSlippage ) + const sellTokenContract = useTokenContract(getAddress(inputAmountWithSlippage?.currency) || undefined, true) const isSafeBundle = useIsSafeApprovalBundle(inputAmountWithSlippage) const flowType = _getFlowType(isSafeBundle, isEoaEthFlow, isSafeEthFlow) @@ -116,6 +116,7 @@ export function useBaseFlowContextSetup(): BaseFlowContextSetup { return { chainId, account, + sellTokenContract, provider, trade, appData, @@ -179,6 +180,7 @@ export function getFlowContext({ baseProps, sellToken, kind }: BaseGetFlowContex uploadAppData, dispatch, flowType, + sellTokenContract, } = baseProps if ( @@ -263,5 +265,6 @@ export function getFlowContext({ baseProps, sellToken, kind }: BaseGetFlowContex swapConfirmManager, orderParams, appDataInfo: appData, + sellTokenContract, } } diff --git a/apps/cowswap-frontend/src/modules/swap/hooks/useHandleSwap.test.tsx b/apps/cowswap-frontend/src/modules/swap/hooks/useHandleSwap.test.tsx index cd751a26de..e8c23f5bfb 100644 --- a/apps/cowswap-frontend/src/modules/swap/hooks/useHandleSwap.test.tsx +++ b/apps/cowswap-frontend/src/modules/swap/hooks/useHandleSwap.test.tsx @@ -1,8 +1,7 @@ import { renderHook } from '@testing-library/react-hooks' import { PriceImpact } from 'legacy/hooks/usePriceImpact' -import { Field } from 'legacy/state/swap/actions' -import { useSwapActionHandlers } from 'legacy/state/swap/hooks' +import { Field } from 'legacy/state/types' import { useSafeBundleApprovalFlowContext } from 'modules/swap/hooks/useSafeBundleApprovalFlowContext' import { ethFlow } from 'modules/swap/services/ethFlow' @@ -15,17 +14,18 @@ import { useEthFlowContext } from './useEthFlowContext' import { useHandleSwap } from './useHandleSwap' import { useSafeBundleEthFlowContext } from './useSafeBundleEthFlowContext' import { useSwapFlowContext } from './useSwapFlowContext' +import { useSwapActionHandlers } from './useSwapState' +jest.mock('./useSwapState') jest.mock('./useSwapFlowContext') jest.mock('./useEthFlowContext') jest.mock('./useSafeBundleApprovalFlowContext') jest.mock('./useSafeBundleEthFlowContext') -jest.mock('legacy/state/swap/hooks') jest.mock('modules/swap/services/swapFlow') jest.mock('modules/swap/services/ethFlow') jest.mock('modules/swap/services/safeBundleFlow') jest.mock('modules/twap/state/twapOrdersListAtom', () => ({})) -jest.mock('legacy/components/analytics/hooks/useAnalyticsReporter.ts') +jest.mock('common/hooks/useAnalyticsReporter') const mockUseSwapActionHandlers = useSwapActionHandlers as jest.MockedFunction const mockSwapFlow = swapFlow as jest.MockedFunction diff --git a/apps/cowswap-frontend/src/modules/swap/hooks/useHandleSwap.ts b/apps/cowswap-frontend/src/modules/swap/hooks/useHandleSwap.ts index 7ecfe2c12e..20dc460162 100644 --- a/apps/cowswap-frontend/src/modules/swap/hooks/useHandleSwap.ts +++ b/apps/cowswap-frontend/src/modules/swap/hooks/useHandleSwap.ts @@ -1,8 +1,7 @@ import { useCallback } from 'react' import { PriceImpact } from 'legacy/hooks/usePriceImpact' -import { Field } from 'legacy/state/swap/actions' -import { useSwapActionHandlers } from 'legacy/state/swap/hooks' +import { Field } from 'legacy/state/types' import { useSafeBundleApprovalFlowContext } from 'modules/swap/hooks/useSafeBundleApprovalFlowContext' import { ethFlow } from 'modules/swap/services/ethFlow' @@ -15,6 +14,7 @@ import { useConfirmPriceImpactWithoutFee } from 'common/hooks/useConfirmPriceImp import { useEthFlowContext } from './useEthFlowContext' import { useSafeBundleEthFlowContext } from './useSafeBundleEthFlowContext' import { useSwapFlowContext } from './useSwapFlowContext' +import { useSwapActionHandlers } from './useSwapState' export function useHandleSwap(priceImpactParams: PriceImpact): () => Promise { const swapFlowContext = useSwapFlowContext() diff --git a/apps/cowswap-frontend/src/modules/swap/hooks/useIsEoaEthFlow.ts b/apps/cowswap-frontend/src/modules/swap/hooks/useIsEoaEthFlow.ts index 3ee54396d4..5d2a630fe7 100644 --- a/apps/cowswap-frontend/src/modules/swap/hooks/useIsEoaEthFlow.ts +++ b/apps/cowswap-frontend/src/modules/swap/hooks/useIsEoaEthFlow.ts @@ -1,6 +1,6 @@ -import { getEthFlowEnabled } from 'modules/swap/helpers/getEthFlowEnabled' +import { useIsSmartContractWallet } from '@cowprotocol/wallet' -import { useIsSmartContractWallet } from 'common/hooks/useIsSmartContractWallet' +import { getEthFlowEnabled } from 'modules/swap/helpers/getEthFlowEnabled' import { useIsSwapEth } from './useIsSwapEth' diff --git a/apps/cowswap-frontend/src/modules/swap/hooks/useIsSafeEthFlow.ts b/apps/cowswap-frontend/src/modules/swap/hooks/useIsSafeEthFlow.ts index a108950381..b1badd3a31 100644 --- a/apps/cowswap-frontend/src/modules/swap/hooks/useIsSafeEthFlow.ts +++ b/apps/cowswap-frontend/src/modules/swap/hooks/useIsSafeEthFlow.ts @@ -1,10 +1,10 @@ -import { useIsEthFlowBundlingEnabled } from 'common/hooks/featureFlags/useIsEthFlowBundlingEnabled' +import { useIsBundlingSupported } from '@cowprotocol/wallet' import { useIsSwapEth } from './useIsSwapEth' export function useIsSafeEthFlow(): boolean { const isSwapEth = useIsSwapEth() - const isEthFlowBundlingEnabled = useIsEthFlowBundlingEnabled() + const isBundlingSupported = useIsBundlingSupported() - return isEthFlowBundlingEnabled && isSwapEth + return isBundlingSupported && isSwapEth } diff --git a/apps/cowswap-frontend/src/modules/swap/hooks/useSafeBundleApprovalFlowContext.ts b/apps/cowswap-frontend/src/modules/swap/hooks/useSafeBundleApprovalFlowContext.ts index 5e6425be86..7fc8ee6a35 100644 --- a/apps/cowswap-frontend/src/modules/swap/hooks/useSafeBundleApprovalFlowContext.ts +++ b/apps/cowswap-frontend/src/modules/swap/hooks/useSafeBundleApprovalFlowContext.ts @@ -1,4 +1,4 @@ -import { useTokenContract } from 'legacy/hooks/useContract' +import { useTokenContract } from '@cowprotocol/common-hooks' import { FlowType } from 'modules/swap/hooks/useFlowContext' import { SafeBundleApprovalFlowContext } from 'modules/swap/services/types' diff --git a/apps/cowswap-frontend/src/modules/swap/hooks/useSafeBundleEthFlowContext.ts b/apps/cowswap-frontend/src/modules/swap/hooks/useSafeBundleEthFlowContext.ts index e946713168..65ac47fc2b 100644 --- a/apps/cowswap-frontend/src/modules/swap/hooks/useSafeBundleEthFlowContext.ts +++ b/apps/cowswap-frontend/src/modules/swap/hooks/useSafeBundleEthFlowContext.ts @@ -1,4 +1,4 @@ -import { useWETHContract } from 'legacy/hooks/useContract' +import { useWETHContract } from '@cowprotocol/common-hooks' import { FlowType } from 'modules/swap/hooks/useFlowContext' import { SafeBundleEthFlowContext } from 'modules/swap/services/types' diff --git a/apps/cowswap-frontend/src/modules/swap/hooks/useSetupSwapAmountsFromUrl.ts b/apps/cowswap-frontend/src/modules/swap/hooks/useSetupSwapAmountsFromUrl.ts index 6e2f09e5d7..a3cb22aa90 100644 --- a/apps/cowswap-frontend/src/modules/swap/hooks/useSetupSwapAmountsFromUrl.ts +++ b/apps/cowswap-frontend/src/modules/swap/hooks/useSetupSwapAmountsFromUrl.ts @@ -1,13 +1,14 @@ import { useCallback, useLayoutEffect, useMemo } from 'react' +import { getIntOrFloat } from '@cowprotocol/common-utils' + import { useLocation, useNavigate } from 'react-router-dom' -import { Field } from 'legacy/state/swap/actions' -import { useSwapActionHandlers } from 'legacy/state/swap/hooks' +import { Field } from 'legacy/state/types' import { TRADE_URL_BUY_AMOUNT_KEY, TRADE_URL_SELL_AMOUNT_KEY } from 'modules/trade/const/tradeUrl' -import { getIntOrFloat } from 'utils/getIntOrFloat' +import { useSwapActionHandlers } from './useSwapState' /** * Parse sell/buy amount from URL and apply to Swap widget diff --git a/apps/cowswap-frontend/src/modules/swap/hooks/useSwapButtonContext.ts b/apps/cowswap-frontend/src/modules/swap/hooks/useSwapButtonContext.ts index 4ac0493a34..e76de08d48 100644 --- a/apps/cowswap-frontend/src/modules/swap/hooks/useSwapButtonContext.ts +++ b/apps/cowswap-frontend/src/modules/swap/hooks/useSwapButtonContext.ts @@ -1,13 +1,20 @@ +import { + useGnosisSafeInfo, + useIsBundlingSupported, + useIsSmartContractWallet, + useWalletDetails, + useWalletInfo, +} from '@cowprotocol/wallet' import { Currency, CurrencyAmount } from '@uniswap/sdk-core' import { PriceImpact } from 'legacy/hooks/usePriceImpact' import { useToggleWalletModal } from 'legacy/state/application/hooks' import { useIsTradeUnsupported } from 'legacy/state/lists/hooks' import { useGetQuoteAndStatus, useIsBestQuoteLoading } from 'legacy/state/price/hooks' -import { Field } from 'legacy/state/swap/actions' -import { useDerivedSwapInfo, useSwapActionHandlers } from 'legacy/state/swap/hooks' +import { Field } from 'legacy/state/types' import { useExpertModeManager } from 'legacy/state/user/hooks' +import { useIsTokenPermittable } from 'modules/permit' import { getSwapButtonState } from 'modules/swap/helpers/getSwapButtonState' import { useEthFlowContext } from 'modules/swap/hooks/useEthFlowContext' import { useHandleSwap } from 'modules/swap/hooks/useHandleSwap' @@ -16,18 +23,15 @@ import { useSwapConfirmManager } from 'modules/swap/hooks/useSwapConfirmManager' import { useSwapFlowContext } from 'modules/swap/hooks/useSwapFlowContext' import { SwapButtonsContext } from 'modules/swap/pure/SwapButtons' import useCurrencyBalance from 'modules/tokens/hooks/useCurrencyBalance' -import { useWrapNativeFlow } from 'modules/trade' +import { TradeType, useWrapNativeFlow } from 'modules/trade' import { useIsNativeIn } from 'modules/trade/hooks/useIsNativeInOrOut' import { useIsWrappedOut } from 'modules/trade/hooks/useIsWrappedInOrOut' import { useWrappedToken } from 'modules/trade/hooks/useWrappedToken' -import { useGnosisSafeInfo, useWalletDetails, useWalletInfo } from 'modules/wallet' import { useTradeApproveState } from 'common/containers/TradeApprove/useTradeApproveState' -import { useIsEthFlowBundlingEnabled } from 'common/hooks/featureFlags/useIsEthFlowBundlingEnabled' -import { useIsTxBundlingEnabled } from 'common/hooks/featureFlags/useIsTxBundlingEnabled' -import { useIsSmartContractWallet } from 'common/hooks/useIsSmartContractWallet' import { useSafeBundleEthFlowContext } from './useSafeBundleEthFlowContext' +import { useDerivedSwapInfo, useSwapActionHandlers } from './useSwapState' export interface SwapButtonInput { feeWarningAccepted: boolean @@ -87,16 +91,15 @@ export function useSwapButtonContext(input: SwapButtonInput): SwapButtonsContext const isReadonlyGnosisSafeUser = gnosisSafeInfo?.isReadOnly || false const isSwapUnsupported = useIsTradeUnsupported(currencyIn, currencyOut) const isSmartContractWallet = useIsSmartContractWallet() - const isTxBundlingEnabled = useIsTxBundlingEnabled() - const isEthFlowBundlingEnabled = useIsEthFlowBundlingEnabled() + const isBundlingSupported = useIsBundlingSupported() + const isPermitSupported = !!useIsTokenPermittable(currencyIn, TradeType.SWAP) const swapButtonState = getSwapButtonState({ account, isSupportedWallet, isSmartContractWallet, isReadonlyGnosisSafeUser, - isTxBundlingEnabled, - isEthFlowBundlingEnabled, + isBundlingSupported, isExpertMode, isSwapUnsupported, isNativeIn: isNativeInSwap, @@ -110,6 +113,7 @@ export function useSwapButtonContext(input: SwapButtonInput): SwapButtonsContext swapCallbackError, trade, isBestQuoteLoading, + isPermitSupported, }) return { diff --git a/apps/cowswap-frontend/src/modules/swap/hooks/useSwapConfirmManager.ts b/apps/cowswap-frontend/src/modules/swap/hooks/useSwapConfirmManager.ts index d771262739..0ba4f9b23c 100644 --- a/apps/cowswap-frontend/src/modules/swap/hooks/useSwapConfirmManager.ts +++ b/apps/cowswap-frontend/src/modules/swap/hooks/useSwapConfirmManager.ts @@ -1,75 +1,113 @@ -import { useAtom } from 'jotai' +import { useSetAtom } from 'jotai' import { useMemo } from 'react' import TradeGp from 'legacy/state/swap/TradeGp' import { useExpertModeManager } from 'legacy/state/user/hooks' -import { swapConfirmAtom } from 'modules/swap/state/swapConfirmAtom' +import { swapConfirmAtom, SwapConfirmState } from 'modules/swap/state/swapConfirmAtom' export interface SwapConfirmManager { setSwapError(swapErrorMessage: string): void - openSwapConfirmModal(tradeToConfirm: TradeGp): void + openSwapConfirmModal(tradeToConfirm: TradeGp, needsPermitSignature?: boolean): void acceptRateUpdates(tradeToConfirm: TradeGp): void closeSwapConfirm(): void sendTransaction(tradeToConfirm: TradeGp): void transactionSent(txHash: string): void + requestPermitSignature(): void + permitSigned(): void } export function useSwapConfirmManager(): SwapConfirmManager { - const [swapConfirmState, setSwapConfirmState] = useAtom(swapConfirmAtom) + const setSwapConfirmState = useSetAtom(swapConfirmAtom) const [isExpertMode] = useExpertModeManager() return useMemo( () => ({ setSwapError(swapErrorMessage: string) { - const state = { ...swapConfirmState, swapErrorMessage } - console.debug('[Swap confirm state] setSwapError: ', state) - setSwapConfirmState(state) + setSwapConfirmState((prev) => { + const state = { ...prev, swapErrorMessage, attemptingTxn: false, permitSignatureState: undefined } + console.debug('[Swap confirm state] setSwapError: ', state) + return state + }) }, openSwapConfirmModal(tradeToConfirm: TradeGp) { - const state = { + const state: SwapConfirmState = { tradeToConfirm, attemptingTxn: false, swapErrorMessage: undefined, showConfirm: true, txHash: undefined, + permitSignatureState: undefined, } console.debug('[Swap confirm state] openSwapConfirmModal: ', state) setSwapConfirmState(state) }, acceptRateUpdates(tradeToConfirm: TradeGp) { - const state = { ...swapConfirmState, tradeToConfirm } - console.debug('[Swap confirm state] acceptRateUpdates: ', state) - setSwapConfirmState(state) + setSwapConfirmState((prev) => { + const state = { ...prev, tradeToConfirm } + console.debug('[Swap confirm state] acceptRateUpdates: ', state) + return state + }) + }, + requestPermitSignature() { + setSwapConfirmState((prev) => { + const state: SwapConfirmState = { ...prev, permitSignatureState: 'requested' } + console.debug('[Swap confirm state] requestPermitSignature: ', state) + return state + }) + }, + permitSigned() { + setSwapConfirmState((prev) => { + // Move to `signed` state only if previous state was `requested` - which means the order is using the permit + // Set to `undefined` otherwise + const permitSignatureState = prev.permitSignatureState === 'requested' ? 'signed' : undefined + + const state: SwapConfirmState = { + ...prev, + permitSignatureState, + } + + console.debug('[Swap confirm state] permitSigned: ', state) + + return state + }) }, closeSwapConfirm() { - const state = { ...swapConfirmState, showConfirm: false } - console.debug('[Swap confirm state] closeSwapConfirm: ', state) - setSwapConfirmState(state) + setSwapConfirmState((prev) => { + const state = { ...prev, showConfirm: false, permitSignatureState: undefined } + console.debug('[Swap confirm state] closeSwapConfirm: ', state) + return state + }) }, sendTransaction(tradeToConfirm: TradeGp) { - const state = { - tradeToConfirm, - attemptingTxn: true, - swapErrorMessage: undefined, - showConfirm: true, - txHash: undefined, - } - console.debug('[Swap confirm state] sendTransaction: ', state) - setSwapConfirmState(state) + setSwapConfirmState((prev) => { + const state = { + ...prev, + tradeToConfirm, + attemptingTxn: true, + swapErrorMessage: undefined, + showConfirm: true, + txHash: undefined, + } + console.debug('[Swap confirm state] sendTransaction: ', state) + return state + }) }, transactionSent(txHash: string) { - const state = { - ...swapConfirmState, - attemptingTxn: false, - swapErrorMessage: undefined, - showConfirm: !isExpertMode, - txHash, - } - console.debug('[Swap confirm state] transactionSent: ', state) - setSwapConfirmState(state) + setSwapConfirmState((prev) => { + const state = { + ...prev, + attemptingTxn: false, + swapErrorMessage: undefined, + showConfirm: !isExpertMode, + txHash, + permitSignatureState: undefined, + } + console.debug('[Swap confirm state] transactionSent: ', state) + return state + }) }, }), - [swapConfirmState, setSwapConfirmState, isExpertMode] + [setSwapConfirmState, isExpertMode] ) } diff --git a/apps/cowswap-frontend/src/modules/swap/hooks/useSwapCurrenciesAmounts.ts b/apps/cowswap-frontend/src/modules/swap/hooks/useSwapCurrenciesAmounts.ts index 60036372c1..9d0c1e51f3 100644 --- a/apps/cowswap-frontend/src/modules/swap/hooks/useSwapCurrenciesAmounts.ts +++ b/apps/cowswap-frontend/src/modules/swap/hooks/useSwapCurrenciesAmounts.ts @@ -1,12 +1,13 @@ import { useMemo } from 'react' import { ParsedAmounts } from 'legacy/hooks/usePriceImpact/types' -import { Field } from 'legacy/state/swap/actions' -import { useSwapState } from 'legacy/state/swap/hooks' -import { useDerivedSwapInfo } from 'legacy/state/swap/hooks' +import { Field } from 'legacy/state/types' import { useSafeMemoObject } from 'common/hooks/useSafeMemo' +import { useSwapState } from './useSwapState' +import { useDerivedSwapInfo } from './useSwapState' + export function useSwapCurrenciesAmounts(): ParsedAmounts { const { independentField } = useSwapState() const { v2Trade: trade, parsedAmount } = useDerivedSwapInfo() diff --git a/apps/cowswap-frontend/src/modules/swap/hooks/useSwapFlowContext.ts b/apps/cowswap-frontend/src/modules/swap/hooks/useSwapFlowContext.ts index f8adc0ea86..086e4329ba 100644 --- a/apps/cowswap-frontend/src/modules/swap/hooks/useSwapFlowContext.ts +++ b/apps/cowswap-frontend/src/modules/swap/hooks/useSwapFlowContext.ts @@ -1,21 +1,34 @@ -import { OrderKind } from '@cowprotocol/cow-sdk' -import { TradeType } from '@uniswap/sdk-core' - -import { useGP2SettlementContract } from 'legacy/hooks/useContract' +import { GP_VAULT_RELAYER } from '@cowprotocol/common-const' +import { useGP2SettlementContract } from '@cowprotocol/common-hooks' +import { OrderKind, SupportedChainId } from '@cowprotocol/cow-sdk' +import { TradeType as UniTradeType } from '@uniswap/sdk-core' +import { useGeneratePermitHook, useIsTokenPermittable } from 'modules/permit' import { FlowType, getFlowContext, useBaseFlowContextSetup } from 'modules/swap/hooks/useFlowContext' import { SwapFlowContext } from 'modules/swap/services/types' +import { useEnoughBalanceAndAllowance } from 'modules/tokens' +import { TradeType } from 'modules/trade' export function useSwapFlowContext(): SwapFlowContext | null { const contract = useGP2SettlementContract() const baseProps = useBaseFlowContextSetup() + const sellCurrency = baseProps.trade?.inputAmount?.currency + const permitInfo = useIsTokenPermittable(sellCurrency, TradeType.SWAP) + const generatePermitHook = useGeneratePermitHook() + + const checkAllowanceAddress = GP_VAULT_RELAYER[baseProps.chainId || SupportedChainId.MAINNET] + const { enoughAllowance } = useEnoughBalanceAndAllowance({ + account: baseProps.account, + amount: baseProps.inputAmountWithSlippage, + checkAllowanceAddress, + }) if (!baseProps.trade) return null const baseContext = getFlowContext({ baseProps, sellToken: baseProps.trade.inputAmount.currency.wrapped, - kind: baseProps.trade.tradeType === TradeType.EXACT_INPUT ? OrderKind.SELL : OrderKind.BUY, + kind: baseProps.trade.tradeType === UniTradeType.EXACT_INPUT ? OrderKind.SELL : OrderKind.BUY, }) if (!contract || !baseContext || baseProps.flowType !== FlowType.REGULAR) return null @@ -23,5 +36,7 @@ export function useSwapFlowContext(): SwapFlowContext | null { return { ...baseContext, contract, + permitInfo: !enoughAllowance ? permitInfo : undefined, + generatePermitHook, } } diff --git a/apps/cowswap-frontend/src/modules/swap/hooks/useSwapRawState.ts b/apps/cowswap-frontend/src/modules/swap/hooks/useSwapRawState.ts index 481307e5d8..bab6dc5cdb 100644 --- a/apps/cowswap-frontend/src/modules/swap/hooks/useSwapRawState.ts +++ b/apps/cowswap-frontend/src/modules/swap/hooks/useSwapRawState.ts @@ -2,10 +2,11 @@ import { useCallback } from 'react' import { useAppDispatch } from 'legacy/state/hooks' import { replaceOnlyTradeRawState, ReplaceOnlyTradeRawStatePayload } from 'legacy/state/swap/actions' -import { useSwapState } from 'legacy/state/swap/hooks' import { ExtendedTradeRawState, TradeRawState } from 'modules/trade/types/TradeRawState' +import { useSwapState } from './useSwapState' + export function useSwapRawState(): TradeRawState { const swapState = useSwapState() diff --git a/apps/cowswap-frontend/src/modules/swap/hooks/useSwapSlippage.ts b/apps/cowswap-frontend/src/modules/swap/hooks/useSwapSlippage.ts index bbb7308b06..1ccd9f92e4 100644 --- a/apps/cowswap-frontend/src/modules/swap/hooks/useSwapSlippage.ts +++ b/apps/cowswap-frontend/src/modules/swap/hooks/useSwapSlippage.ts @@ -1,6 +1,6 @@ +import { INITIAL_ALLOWED_SLIPPAGE_PERCENT } from '@cowprotocol/common-const' import { Percent } from '@uniswap/sdk-core' -import { INITIAL_ALLOWED_SLIPPAGE_PERCENT } from 'legacy/constants' import { useUserSlippageToleranceWithDefault } from 'legacy/state/user/hooks' export function useSwapSlippage(): Percent { diff --git a/apps/cowswap-frontend/src/legacy/state/swap/hooks.test.ts b/apps/cowswap-frontend/src/modules/swap/hooks/useSwapState.test.ts similarity index 95% rename from apps/cowswap-frontend/src/legacy/state/swap/hooks.test.ts rename to apps/cowswap-frontend/src/modules/swap/hooks/useSwapState.test.ts index 04ac6376f1..9dbd371abb 100644 --- a/apps/cowswap-frontend/src/legacy/state/swap/hooks.test.ts +++ b/apps/cowswap-frontend/src/modules/swap/hooks/useSwapState.test.ts @@ -1,9 +1,9 @@ import { parse } from 'qs' -import { Field } from './actions' -import { queryParametersToSwapState } from './utils' +import { queryParametersToSwapState } from 'legacy/state/swap/utils' +import { Field } from 'legacy/state/types' -jest.mock('legacy/components/analytics/hooks/useAnalyticsReporter.ts') +jest.mock('common/hooks/useAnalyticsReporter') describe('hooks', () => { describe('#queryParametersToSwapState', () => { diff --git a/apps/cowswap-frontend/src/legacy/state/swap/hooks.tsx b/apps/cowswap-frontend/src/modules/swap/hooks/useSwapState.tsx similarity index 95% rename from apps/cowswap-frontend/src/legacy/state/swap/hooks.tsx rename to apps/cowswap-frontend/src/modules/swap/hooks/useSwapState.tsx index 835cf5f5c7..c0de1c1112 100644 --- a/apps/cowswap-frontend/src/legacy/state/swap/hooks.tsx +++ b/apps/cowswap-frontend/src/modules/swap/hooks/useSwapState.tsx @@ -1,38 +1,36 @@ import { useCallback, useEffect, useMemo, useState } from 'react' +import { changeSwapAmountAnalytics, switchTokensAnalytics } from '@cowprotocol/analytics' +import { FEE_SIZE_THRESHOLD } from '@cowprotocol/common-const' +import { formatSymbol, isAddress, tryParseCurrencyAmount } from '@cowprotocol/common-utils' import { SupportedChainId } from '@cowprotocol/cow-sdk' +import { useENS } from '@cowprotocol/ens' +import { useWalletInfo } from '@cowprotocol/wallet' import { Currency, CurrencyAmount, Percent } from '@uniswap/sdk-core' import { t } from '@lingui/macro' -import { changeSwapAmountAnalytics, switchTokensAnalytics } from 'legacy/components/analytics' -import { FEE_SIZE_THRESHOLD } from 'legacy/constants' import { useCurrency } from 'legacy/hooks/Tokens' -import useENS from 'legacy/hooks/useENS' import { PriceImpact } from 'legacy/hooks/usePriceImpact' import { AppState } from 'legacy/state' import { useAppDispatch, useAppSelector } from 'legacy/state/hooks' import { useGetQuoteAndStatus, useQuote } from 'legacy/state/price/hooks' +import { setRecipient, switchCurrencies, typeInput } from 'legacy/state/swap/actions' import { stringToCurrency, useTradeExactInWithFee, useTradeExactOutWithFee } from 'legacy/state/swap/extension' import TradeGp from 'legacy/state/swap/TradeGp' import { isWrappingTrade } from 'legacy/state/swap/utils' +import { Field } from 'legacy/state/types' import { useIsExpertMode } from 'legacy/state/user/hooks' -import { isAddress } from 'legacy/utils' -import { registerOnWindow } from 'legacy/utils/misc' -import { useSwapSlippage } from 'modules/swap/hooks/useSwapSlippage' import { useCurrencyBalances } from 'modules/tokens/hooks/useCurrencyBalance' import { useNavigateOnCurrencySelection } from 'modules/trade/hooks/useNavigateOnCurrencySelection' import { useTradeNavigate } from 'modules/trade/hooks/useTradeNavigate' -import { useWalletInfo } from 'modules/wallet' import { useAreThereTokensWithSameSymbol } from 'common/hooks/useAreThereTokensWithSameSymbol' import { useIsProviderNetworkUnsupported } from 'common/hooks/useIsProviderNetworkUnsupported' import { useTokenBySymbolOrAddress } from 'common/hooks/useTokenBySymbolOrAddress' -import tryParseCurrencyAmount from 'lib/utils/tryParseCurrencyAmount' -import { formatSymbol } from 'utils/format' -import { Field, setRecipient, switchCurrencies, typeInput } from './actions' +import { useSwapSlippage } from './useSwapSlippage' export const BAD_RECIPIENT_ADDRESSES: { [address: string]: true } = { '0x5C69bEe701ef814a2B6a3EDD4B1652CB9cc5aA6f': true, // v2 factory @@ -282,9 +280,6 @@ export function useDerivedSwapInfo(): DerivedSwapInfo { // TODO: rename v2Trade to just "trade" we dont have versions const v2Trade = isExactIn ? bestTradeExactIn : bestTradeExactOut - registerOnWindow({ trade: v2Trade }) - // -- MOD -- - const currencyBalances = useMemo( () => ({ [Field.INPUT]: relevantTokenBalances[0], diff --git a/apps/cowswap-frontend/src/modules/swap/hooks/useTradePricesUpdate.ts b/apps/cowswap-frontend/src/modules/swap/hooks/useTradePricesUpdate.ts index 7d809f81e8..a171af0670 100644 --- a/apps/cowswap-frontend/src/modules/swap/hooks/useTradePricesUpdate.ts +++ b/apps/cowswap-frontend/src/modules/swap/hooks/useTradePricesUpdate.ts @@ -1,8 +1,12 @@ import { useMemo } from 'react' -import { LONG_LOAD_THRESHOLD, SHORT_LOAD_THRESHOLD } from 'legacy/constants' -import useLoadingWithTimeout from 'legacy/hooks/useLoadingWithTimeout' -import { useIsBestQuoteLoading, useIsQuoteLoading, useIsQuoteRefreshing } from 'legacy/state/price/hooks' +import { LONG_LOAD_THRESHOLD, SHORT_LOAD_THRESHOLD } from '@cowprotocol/common-const' +import { useLoadingWithTimeout } from '@cowprotocol/common-hooks' +import { useWalletInfo } from '@cowprotocol/wallet' + +import { useGetQuoteAndStatus, useIsBestQuoteLoading, useIsQuoteLoading } from 'legacy/state/price/hooks' + +import { useSwapState } from './useSwapState' export function useTradePricesUpdate(): boolean { const isRefreshingQuote = useIsQuoteRefreshing() @@ -14,3 +18,12 @@ export function useTradePricesUpdate(): boolean { return useMemo(() => showCowLoader || showQuoteLoader, [showCowLoader, showQuoteLoader]) } + +function useIsQuoteRefreshing(): boolean { + const { chainId } = useWalletInfo() + const { + INPUT: { currencyId }, + } = useSwapState() + const { isRefreshingQuote } = useGetQuoteAndStatus({ token: currencyId, chainId }) + return isRefreshingQuote +} diff --git a/apps/cowswap-frontend/src/modules/swap/pure/EthFlow/EthFlowBanner/index.cosmos.tsx b/apps/cowswap-frontend/src/modules/swap/pure/EthFlow/EthFlowBanner/index.cosmos.tsx index 9d534210a3..4745047b58 100644 --- a/apps/cowswap-frontend/src/modules/swap/pure/EthFlow/EthFlowBanner/index.cosmos.tsx +++ b/apps/cowswap-frontend/src/modules/swap/pure/EthFlow/EthFlowBanner/index.cosmos.tsx @@ -1,8 +1,7 @@ +import { GpEther } from '@cowprotocol/common-const' import { SupportedChainId } from '@cowprotocol/cow-sdk' import { Token } from '@uniswap/sdk-core' -import { GpEther } from 'legacy/constants/tokens' - import { EthFlowBannerContent, EthFlowBannerContentProps } from '.' const defaultProps: EthFlowBannerContentProps = { diff --git a/apps/cowswap-frontend/src/modules/swap/pure/EthFlow/EthFlowBanner/index.tsx b/apps/cowswap-frontend/src/modules/swap/pure/EthFlow/EthFlowBanner/index.tsx index b590076c12..d972e7937d 100644 --- a/apps/cowswap-frontend/src/modules/swap/pure/EthFlow/EthFlowBanner/index.tsx +++ b/apps/cowswap-frontend/src/modules/swap/pure/EthFlow/EthFlowBanner/index.tsx @@ -1,13 +1,12 @@ +import savingsIcon from '@cowprotocol/assets/cow-swap/savings.svg' +import { MINIMUM_ETH_FLOW_SLIPPAGE, PERCENTAGE_PRECISION } from '@cowprotocol/common-const' +import { ButtonPrimary } from '@cowprotocol/ui' import { Currency, Token } from '@uniswap/sdk-core' import { Trans } from '@lingui/macro' import { ChevronDown, ChevronUp } from 'react-feather' import SVG from 'react-inlinesvg' -import savingsIcon from 'legacy/assets/cow-swap/savings.svg' -import { ButtonPrimary } from 'legacy/components/Button' -import { MINIMUM_ETH_FLOW_SLIPPAGE, PERCENTAGE_PRECISION } from 'legacy/constants' - import { EthFlowBannerCallbacks } from 'modules/swap/containers/EthFlow/EthFlowBanner' import * as styledEl from './styleds' diff --git a/apps/cowswap-frontend/src/modules/swap/pure/EthFlow/EthFlowBanner/styleds.ts b/apps/cowswap-frontend/src/modules/swap/pure/EthFlow/EthFlowBanner/styleds.ts index 99a597f61b..f96c023a53 100644 --- a/apps/cowswap-frontend/src/modules/swap/pure/EthFlow/EthFlowBanner/styleds.ts +++ b/apps/cowswap-frontend/src/modules/swap/pure/EthFlow/EthFlowBanner/styleds.ts @@ -1,7 +1,9 @@ +import { ButtonPrimary } from '@cowprotocol/ui' + import { transparentize } from 'polished' import styled from 'styled-components/macro' -import { ButtonPrimary } from 'legacy/components/Button' +import { UI } from 'common/constants/theme' export const BannerWrapper = styled.div` display: flex; @@ -36,7 +38,7 @@ export const ClosedBannerWrapper = styled.div` cursor: pointer; > path { - fill: ${({ theme }) => theme.text1}; + fill: var(${UI.COLOR_TEXT1}); } } @@ -45,7 +47,7 @@ export const ClosedBannerWrapper = styled.div` } &:hover > svg:last-child { - stroke: ${({ theme }) => theme.text1}; + stroke: var(${UI.COLOR_TEXT1}); } ` diff --git a/apps/cowswap-frontend/src/modules/swap/pure/EthFlow/EthFlowModalContent/ActionButton.tsx b/apps/cowswap-frontend/src/modules/swap/pure/EthFlow/EthFlowModalContent/ActionButton.tsx index 7da6af2af4..9a118dcd73 100644 --- a/apps/cowswap-frontend/src/modules/swap/pure/EthFlow/EthFlowModalContent/ActionButton.tsx +++ b/apps/cowswap-frontend/src/modules/swap/pure/EthFlow/EthFlowModalContent/ActionButton.tsx @@ -1,9 +1,8 @@ +import { Loader, ButtonPrimary } from '@cowprotocol/ui' + import { Trans } from '@lingui/macro' import styled from 'styled-components/macro' -import { ButtonPrimary } from 'legacy/components/Button' -import Loader from 'legacy/components/Loader' - const ButtonWrapper = styled.div` display: flex; flex-flow: row nowrap; diff --git a/apps/cowswap-frontend/src/modules/swap/pure/EthFlow/EthFlowModalContent/EthFlowModalTopContent.tsx b/apps/cowswap-frontend/src/modules/swap/pure/EthFlow/EthFlowModalContent/EthFlowModalTopContent.tsx index be5dba945a..fc0d0a5445 100644 --- a/apps/cowswap-frontend/src/modules/swap/pure/EthFlow/EthFlowModalContent/EthFlowModalTopContent.tsx +++ b/apps/cowswap-frontend/src/modules/swap/pure/EthFlow/EthFlowModalContent/EthFlowModalTopContent.tsx @@ -4,6 +4,8 @@ import styled from 'styled-components/macro' import { EthFlowState } from 'modules/swap/services/ethFlow/types' +import { UI } from 'common/constants/theme' + const ModalMessage = styled.div` display: flex; flex-flow: row wrap; @@ -25,7 +27,7 @@ const ModalMessage = styled.div` const LowBalanceMessage = styled(ModalMessage)` margin: 0 0 10px; background: ${({ theme }) => (theme.darkMode ? transparentize(0.9, theme.alert) : transparentize(0.85, theme.alert))}; - color: ${({ theme }) => (theme.darkMode ? theme.alert : darken(0.2, theme.alert))}; + color: ${({ theme }) => (theme.darkMode ? `var(${UI.COLOR_ALERT})` : darken(0.2, theme.alert))}; padding: 16px; border-radius: 16px; width: 100%; diff --git a/apps/cowswap-frontend/src/modules/swap/pure/EthFlow/EthFlowStepper/index.cosmos.tsx b/apps/cowswap-frontend/src/modules/swap/pure/EthFlow/EthFlowStepper/index.cosmos.tsx index 1fd39c2845..022dcc648e 100644 --- a/apps/cowswap-frontend/src/modules/swap/pure/EthFlow/EthFlowStepper/index.cosmos.tsx +++ b/apps/cowswap-frontend/src/modules/swap/pure/EthFlow/EthFlowStepper/index.cosmos.tsx @@ -1,6 +1,7 @@ import 'inter-ui' // TODO: We need to do a cosmos wrapper with the global styles! Will reiterate to remove this line import { useSelect } from 'react-cosmos/client' +import styled from 'styled-components/macro' import { EthFlowStepper, EthFlowStepperProps, SmartOrderStatus } from '.' @@ -376,6 +377,11 @@ const STEPS_BY_DESCRIPTION = STEPS.reduce<{ [description: string]: EthFlowSteppe return acc }, {}) +const Wrapper = styled.div` + width: 80%; + margin: 20px auto; +` + function Fixture() { const [stepDescription] = useSelect('steps', { options: STEPS.map((step) => step.description), @@ -383,13 +389,13 @@ function Fixture() { const props = STEPS_BY_DESCRIPTION[stepDescription] return ( - <> +

Params

{JSON.stringify(props, null, 2)}
- +
) } diff --git a/apps/cowswap-frontend/src/modules/swap/pure/EthFlow/EthFlowStepper/index.tsx b/apps/cowswap-frontend/src/modules/swap/pure/EthFlow/EthFlowStepper/index.tsx index 85f7e02e7c..543dcf6803 100644 --- a/apps/cowswap-frontend/src/modules/swap/pure/EthFlow/EthFlowStepper/index.tsx +++ b/apps/cowswap-frontend/src/modules/swap/pure/EthFlow/EthFlowStepper/index.tsx @@ -3,6 +3,8 @@ import React from 'react' import { transparentize } from 'polished' import styled from 'styled-components/macro' +import { UI } from 'common/constants/theme' + import { StatusIconState } from './StatusIcon' import { Progress1 } from './steps/Progress1' import { Progress2 } from './steps/Progress2' @@ -72,7 +74,7 @@ const Wrapper = styled.div` width: 100%; padding: 22px; border-radius: 0 0 12px 12px; - background: ${({ theme }) => theme.grey1}; + background: var(${UI.COLOR_GREY}); font-size: 15px; line-height: 1; @@ -117,7 +119,7 @@ export const Progress = styled.div` transition: width 0.3s ease-in-out, background 0.2s ease-in-out; width: ${({ value }) => (value ? `${value}%` : '0%')}; background: ${({ status, theme }) => - status === 'error' ? theme.danger : status === 'success' ? theme.success : theme.text3}; + status === 'error' ? `var(${UI.COLOR_DANGER})` : status === 'success' ? `var(${UI.COLOR_SUCCESS})` : theme.text3}; border-radius: var(--height); ${({ theme }) => theme.mediaWidth.upToSmall` diff --git a/apps/cowswap-frontend/src/modules/swap/pure/EthFlow/EthFlowStepper/steps/Step1.tsx b/apps/cowswap-frontend/src/modules/swap/pure/EthFlow/EthFlowStepper/steps/Step1.tsx index 1041c2d8aa..3916be3635 100644 --- a/apps/cowswap-frontend/src/modules/swap/pure/EthFlow/EthFlowStepper/steps/Step1.tsx +++ b/apps/cowswap-frontend/src/modules/swap/pure/EthFlow/EthFlowStepper/steps/Step1.tsx @@ -1,9 +1,9 @@ import React from 'react' -import Checkmark from 'legacy/assets/cow-swap/checkmark.svg' -import Exclamation from 'legacy/assets/cow-swap/exclamation.svg' -import Send from 'legacy/assets/cow-swap/send.svg' -import X from 'legacy/assets/cow-swap/x.svg' +import Checkmark from '@cowprotocol/assets/cow-swap/checkmark.svg' +import Exclamation from '@cowprotocol/assets/cow-swap/exclamation.svg' +import Send from '@cowprotocol/assets/cow-swap/send.svg' +import X from '@cowprotocol/assets/cow-swap/x.svg' import { EthFlowStepperProps, SmartOrderStatus } from '..' import { StatusIconState } from '../StatusIcon' diff --git a/apps/cowswap-frontend/src/modules/swap/pure/EthFlow/EthFlowStepper/steps/Step2.tsx b/apps/cowswap-frontend/src/modules/swap/pure/EthFlow/EthFlowStepper/steps/Step2.tsx index bf5c8137d0..15a3f843f0 100644 --- a/apps/cowswap-frontend/src/modules/swap/pure/EthFlow/EthFlowStepper/steps/Step2.tsx +++ b/apps/cowswap-frontend/src/modules/swap/pure/EthFlow/EthFlowStepper/steps/Step2.tsx @@ -1,9 +1,9 @@ import React, { useMemo } from 'react' -import Checkmark from 'legacy/assets/cow-swap/checkmark.svg' -import Exclamation from 'legacy/assets/cow-swap/exclamation.svg' -import Plus from 'legacy/assets/cow-swap/plus.svg' -import X from 'legacy/assets/cow-swap/x.svg' +import Checkmark from '@cowprotocol/assets/cow-swap/checkmark.svg' +import Exclamation from '@cowprotocol/assets/cow-swap/exclamation.svg' +import Plus from '@cowprotocol/assets/cow-swap/plus.svg' +import X from '@cowprotocol/assets/cow-swap/x.svg' import { EthFlowStepperProps, SmartOrderStatus } from '..' import { ExplorerLinkStyled, Step, StepProps } from '../Step' diff --git a/apps/cowswap-frontend/src/modules/swap/pure/EthFlow/EthFlowStepper/steps/Step3.tsx b/apps/cowswap-frontend/src/modules/swap/pure/EthFlow/EthFlowStepper/steps/Step3.tsx index d7b5871985..61896a3dec 100644 --- a/apps/cowswap-frontend/src/modules/swap/pure/EthFlow/EthFlowStepper/steps/Step3.tsx +++ b/apps/cowswap-frontend/src/modules/swap/pure/EthFlow/EthFlowStepper/steps/Step3.tsx @@ -1,17 +1,19 @@ import React, { useMemo } from 'react' +import Checkmark from '@cowprotocol/assets/cow-swap/checkmark.svg' +import Exclamation from '@cowprotocol/assets/cow-swap/exclamation.svg' +import Finish from '@cowprotocol/assets/cow-swap/finish.svg' +import Refund from '@cowprotocol/assets/cow-swap/refund.svg' + import styled from 'styled-components/macro' -import Checkmark from 'legacy/assets/cow-swap/checkmark.svg' -import Exclamation from 'legacy/assets/cow-swap/exclamation.svg' -import Finish from 'legacy/assets/cow-swap/finish.svg' -import Refund from 'legacy/assets/cow-swap/refund.svg' +import { UI } from 'common/constants/theme' import { EthFlowStepperProps, SmartOrderStatus } from '..' import { Step, StepProps, ExplorerLinkStyled } from '../Step' const RefundMessage = styled.span` - color: ${({ theme }) => theme.text1}; + color: var(${UI.COLOR_TEXT1}); font-weight: 500; ` diff --git a/apps/cowswap-frontend/src/modules/swap/pure/EthFlow/WrappingPreview/WrapCard.cosmos.tsx b/apps/cowswap-frontend/src/modules/swap/pure/EthFlow/WrappingPreview/WrapCard.cosmos.tsx index 38b74f34ea..5a4bf5c5aa 100644 --- a/apps/cowswap-frontend/src/modules/swap/pure/EthFlow/WrappingPreview/WrapCard.cosmos.tsx +++ b/apps/cowswap-frontend/src/modules/swap/pure/EthFlow/WrappingPreview/WrapCard.cosmos.tsx @@ -1,8 +1,7 @@ +import { WRAPPED_NATIVE_CURRENCY as WETH } from '@cowprotocol/common-const' import { SupportedChainId } from '@cowprotocol/cow-sdk' import { CurrencyAmount } from '@uniswap/sdk-core' -import { WRAPPED_NATIVE_CURRENCY as WETH } from 'legacy/constants/tokens' - import { WrapCard } from 'modules/swap/pure/EthFlow/WrappingPreview/WrapCard' const WrappedEther = WETH[SupportedChainId.GOERLI] diff --git a/apps/cowswap-frontend/src/modules/swap/pure/EthFlow/WrappingPreview/WrapCard.tsx b/apps/cowswap-frontend/src/modules/swap/pure/EthFlow/WrappingPreview/WrapCard.tsx index 7c7acc9a2d..ec22db099c 100644 --- a/apps/cowswap-frontend/src/modules/swap/pure/EthFlow/WrappingPreview/WrapCard.tsx +++ b/apps/cowswap-frontend/src/modules/swap/pure/EthFlow/WrappingPreview/WrapCard.tsx @@ -1,16 +1,15 @@ +import { CHAIN_INFO, WRAPPED_NATIVE_CURRENCY } from '@cowprotocol/common-const' import { SupportedChainId } from '@cowprotocol/cow-sdk' +import { TokenAmount } from '@cowprotocol/ui' import { CurrencyAmount, Currency } from '@uniswap/sdk-core' import styled from 'styled-components/macro' -import { CHAIN_INFO } from 'legacy/constants/chainInfo' -import { WRAPPED_NATIVE_CURRENCY } from 'legacy/constants/tokens' import { WrappedTokenInfo } from 'legacy/state/lists/wrappedTokenInfo' import * as styledEl from 'modules/swap/pure/EthFlow/WrappingPreview/styled' import { CurrencyLogo } from 'common/pure/CurrencyLogo' -import { TokenAmount } from 'common/pure/TokenAmount' const BackupTokenImg = styled.img.attrs((attrs) => ({ ...attrs, width: '24px' }))` filter: invert(1); diff --git a/apps/cowswap-frontend/src/modules/swap/pure/EthFlow/WrappingPreview/styled.tsx b/apps/cowswap-frontend/src/modules/swap/pure/EthFlow/WrappingPreview/styled.tsx index 93b00ba3cf..e85f4b6ab5 100644 --- a/apps/cowswap-frontend/src/modules/swap/pure/EthFlow/WrappingPreview/styled.tsx +++ b/apps/cowswap-frontend/src/modules/swap/pure/EthFlow/WrappingPreview/styled.tsx @@ -1,5 +1,7 @@ import styled from 'styled-components/macro' +import { UI } from 'common/constants/theme' + export const WrapCardWrapper = styled.div` ${({ theme }) => theme.flexColumnNoWrap} align-items: center; @@ -38,14 +40,14 @@ export const WrappingPreviewContainer = styled.div` border: 1px solid ${({ theme }) => theme.bg3}; &:nth-of-type(1) { - background-color: ${({ theme }) => theme.bg1}; + background-color: var(${UI.COLOR_CONTAINER_BG_01}); border-radius: 16px 0 0 16px; border-right: 0; } &:nth-of-type(2) { - color: ${({ theme }) => theme.text1}; - background-color: ${({ theme }) => theme.grey1}; + color: var(${UI.COLOR_TEXT1}); + background-color: var(${UI.COLOR_GREY}); border: 1px solid ${({ theme }) => theme.grey1}; border-radius: 0 16px 16px 0; } @@ -65,8 +67,8 @@ export const WrappingPreviewContainer = styled.div` bottom: 0; right: 0; margin: auto; - background: ${({ theme }) => theme.grey1}; - stroke: ${({ theme }) => theme.text1}; + background: var(${UI.COLOR_GREY}); + stroke: var(${UI.COLOR_TEXT1}); width: 32px; height: 32px; border-radius: 32px; diff --git a/apps/cowswap-frontend/src/modules/swap/pure/ReceiveAmount/styled.tsx b/apps/cowswap-frontend/src/modules/swap/pure/ReceiveAmount/styled.tsx index 40319ea55e..94a7f7b9a4 100644 --- a/apps/cowswap-frontend/src/modules/swap/pure/ReceiveAmount/styled.tsx +++ b/apps/cowswap-frontend/src/modules/swap/pure/ReceiveAmount/styled.tsx @@ -2,6 +2,8 @@ import styled from 'styled-components/macro' import QuestionHelper from 'legacy/components/QuestionHelper' +import { UI } from 'common/constants/theme' + export const ReceiveAmountBox = styled.div` display: flex; justify-content: space-between; @@ -9,7 +11,7 @@ export const ReceiveAmountBox = styled.div` border-radius: 0 0 16px 16px; font-size: 14px; font-weight: 600; - background: ${({ theme }) => theme.bg1}; + background: var(${UI.COLOR_CONTAINER_BG_01}); border: 2px solid ${({ theme }) => theme.grey1}; ${({ theme }) => theme.mediaWidth.upToSmall` diff --git a/apps/cowswap-frontend/src/modules/swap/pure/ReceiveAmountInfo/index.tsx b/apps/cowswap-frontend/src/modules/swap/pure/ReceiveAmountInfo/index.tsx index 25cadad0bd..0618a9552f 100644 --- a/apps/cowswap-frontend/src/modules/swap/pure/ReceiveAmountInfo/index.tsx +++ b/apps/cowswap-frontend/src/modules/swap/pure/ReceiveAmountInfo/index.tsx @@ -1,5 +1,6 @@ import React from 'react' +import { TokenSymbol } from '@cowprotocol/ui' import { Currency } from '@uniswap/sdk-core' import { Trans } from '@lingui/macro' @@ -9,8 +10,6 @@ import { BalanceAndSubsidy } from 'legacy/hooks/useCowBalanceAndSubsidy' import { ReceiveAmountInfo } from 'modules/swap/helpers/tradeReceiveAmount' import { useIsEoaEthFlow } from 'modules/swap/hooks/useIsEoaEthFlow' -import { TokenSymbol } from 'common/pure/TokenSymbol' - import * as styledEl from './styled' export interface ReceiveAmountInfoTooltipProps { diff --git a/apps/cowswap-frontend/src/modules/swap/pure/Row/RowDeadline/index.cosmos.tsx b/apps/cowswap-frontend/src/modules/swap/pure/Row/RowDeadline/index.cosmos.tsx index 70882c2d7d..06633ec398 100644 --- a/apps/cowswap-frontend/src/modules/swap/pure/Row/RowDeadline/index.cosmos.tsx +++ b/apps/cowswap-frontend/src/modules/swap/pure/Row/RowDeadline/index.cosmos.tsx @@ -1,4 +1,4 @@ -import { MINIMUM_ETH_FLOW_DEADLINE_SECONDS } from 'legacy/constants' +import { MINIMUM_ETH_FLOW_DEADLINE_SECONDS } from '@cowprotocol/common-const' import { RowDeadlineContent, RowDeadlineProps } from '.' diff --git a/apps/cowswap-frontend/src/modules/swap/pure/Row/RowDeadline/index.tsx b/apps/cowswap-frontend/src/modules/swap/pure/Row/RowDeadline/index.tsx index 53d298f009..2fd4e68630 100644 --- a/apps/cowswap-frontend/src/modules/swap/pure/Row/RowDeadline/index.tsx +++ b/apps/cowswap-frontend/src/modules/swap/pure/Row/RowDeadline/index.tsx @@ -1,8 +1,8 @@ -import { Trans } from '@lingui/macro' +import { INPUT_OUTPUT_EXPLANATION, MINIMUM_ETH_FLOW_DEADLINE_SECONDS } from '@cowprotocol/common-const' +import { RowFixed } from '@cowprotocol/ui' +import { MouseoverTooltipContent } from '@cowprotocol/ui' -import { RowFixed } from 'legacy/components/Row' -import { MouseoverTooltipContent } from 'legacy/components/Tooltip' -import { INPUT_OUTPUT_EXPLANATION, MINIMUM_ETH_FLOW_DEADLINE_SECONDS } from 'legacy/constants' +import { Trans } from '@lingui/macro' import { RowSlippageProps } from 'modules/swap/containers/Row/RowSlippage' import { ClickableText } from 'modules/swap/pure/Row/RowSlippageContent' diff --git a/apps/cowswap-frontend/src/modules/swap/pure/Row/RowFeeContent/index.cosmos.tsx b/apps/cowswap-frontend/src/modules/swap/pure/Row/RowFeeContent/index.cosmos.tsx index eda944b2f3..e843ec7148 100644 --- a/apps/cowswap-frontend/src/modules/swap/pure/Row/RowFeeContent/index.cosmos.tsx +++ b/apps/cowswap-frontend/src/modules/swap/pure/Row/RowFeeContent/index.cosmos.tsx @@ -1,7 +1,7 @@ +import { COW, GNO } from '@cowprotocol/common-const' import { SupportedChainId } from '@cowprotocol/cow-sdk' import { CurrencyAmount, TradeType, Price } from '@uniswap/sdk-core' -import { COW, GNO } from 'legacy/constants/tokens' import TradeGp from 'legacy/state/swap/TradeGp' import { RowFeeProps } from 'modules/swap/containers/Row/RowFee' diff --git a/apps/cowswap-frontend/src/modules/swap/pure/Row/RowFeeContent/index.tsx b/apps/cowswap-frontend/src/modules/swap/pure/Row/RowFeeContent/index.tsx index df06abd7ad..37046508e1 100644 --- a/apps/cowswap-frontend/src/modules/swap/pure/Row/RowFeeContent/index.tsx +++ b/apps/cowswap-frontend/src/modules/swap/pure/Row/RowFeeContent/index.tsx @@ -1,5 +1,5 @@ -import { RowFixed } from 'legacy/components/Row' -import { MouseoverTooltipContent } from 'legacy/components/Tooltip' +import { RowFixed } from '@cowprotocol/ui' +import { MouseoverTooltipContent } from '@cowprotocol/ui' import { StyledRowBetween, TextWrapper } from 'modules/swap/pure/Row/styled' import { RowStyleProps, RowWithShowHelpersProps } from 'modules/swap/pure/Row/types' diff --git a/apps/cowswap-frontend/src/modules/swap/pure/Row/RowReceivedAfterSlippageContent/index.cosmos.tsx b/apps/cowswap-frontend/src/modules/swap/pure/Row/RowReceivedAfterSlippageContent/index.cosmos.tsx index 1e7b790d32..bb9e9357ed 100644 --- a/apps/cowswap-frontend/src/modules/swap/pure/Row/RowReceivedAfterSlippageContent/index.cosmos.tsx +++ b/apps/cowswap-frontend/src/modules/swap/pure/Row/RowReceivedAfterSlippageContent/index.cosmos.tsx @@ -1,7 +1,7 @@ +import { COW, GNO } from '@cowprotocol/common-const' import { SupportedChainId } from '@cowprotocol/cow-sdk' import { CurrencyAmount, TradeType, Price, Percent } from '@uniswap/sdk-core' -import { COW, GNO } from 'legacy/constants/tokens' import TradeGp from 'legacy/state/swap/TradeGp' import { RowReceivedAfterSlippageProps } from 'modules/swap/containers/Row/RowReceivedAfterSlippage' diff --git a/apps/cowswap-frontend/src/modules/swap/pure/Row/RowReceivedAfterSlippageContent/index.tsx b/apps/cowswap-frontend/src/modules/swap/pure/Row/RowReceivedAfterSlippageContent/index.tsx index d1d772eab2..a3d6f5a7f9 100644 --- a/apps/cowswap-frontend/src/modules/swap/pure/Row/RowReceivedAfterSlippageContent/index.tsx +++ b/apps/cowswap-frontend/src/modules/swap/pure/Row/RowReceivedAfterSlippageContent/index.tsx @@ -1,17 +1,14 @@ +import { getMinimumReceivedTooltip } from '@cowprotocol/common-utils' +import { TokenAmount, RowFixed } from '@cowprotocol/ui' +import { MouseoverTooltipContent } from '@cowprotocol/ui' import { CurrencyAmount, Currency, TradeType } from '@uniswap/sdk-core' import { Trans } from '@lingui/macro' -import { RowFixed } from 'legacy/components/Row' -import { MouseoverTooltipContent } from 'legacy/components/Tooltip' -import { getMinimumReceivedTooltip } from 'legacy/utils/tooltips' - import { RowReceivedAfterSlippageProps } from 'modules/swap/containers/Row/RowReceivedAfterSlippage' import { RowStyleProps } from 'modules/swap/pure/Row/types' import { StyledInfoIcon } from 'modules/swap/pure/styled' -import { TokenAmount } from 'common/pure/TokenAmount' - import { StyledRowBetween, TextWrapper } from '../styled' export interface RowReceivedAfterSlippageContentProps extends RowReceivedAfterSlippageProps { diff --git a/apps/cowswap-frontend/src/modules/swap/pure/Row/RowSlippageContent/index.tsx b/apps/cowswap-frontend/src/modules/swap/pure/Row/RowSlippageContent/index.tsx index f3245de41e..cae8d10647 100644 --- a/apps/cowswap-frontend/src/modules/swap/pure/Row/RowSlippageContent/index.tsx +++ b/apps/cowswap-frontend/src/modules/swap/pure/Row/RowSlippageContent/index.tsx @@ -1,10 +1,10 @@ +import { INPUT_OUTPUT_EXPLANATION, MINIMUM_ETH_FLOW_SLIPPAGE, PERCENTAGE_PRECISION } from '@cowprotocol/common-const' +import { RowFixed } from '@cowprotocol/ui' +import { MouseoverTooltipContent } from '@cowprotocol/ui' + import { Trans } from '@lingui/macro' import styled from 'styled-components/macro' -import { RowFixed } from 'legacy/components/Row' -import { MouseoverTooltipContent } from 'legacy/components/Tooltip' -import { INPUT_OUTPUT_EXPLANATION, MINIMUM_ETH_FLOW_SLIPPAGE, PERCENTAGE_PRECISION } from 'legacy/constants' - import { RowSlippageProps } from 'modules/swap/containers/Row/RowSlippage' import { StyledRowBetween, TextWrapper } from 'modules/swap/pure/Row/styled' import { RowStyleProps } from 'modules/swap/pure/Row/types' diff --git a/apps/cowswap-frontend/src/modules/swap/pure/Row/styled.ts b/apps/cowswap-frontend/src/modules/swap/pure/Row/styled.ts index 7be251e7e4..f8fd766a05 100644 --- a/apps/cowswap-frontend/src/modules/swap/pure/Row/styled.ts +++ b/apps/cowswap-frontend/src/modules/swap/pure/Row/styled.ts @@ -1,9 +1,11 @@ +import { RowBetween, RowFixed } from '@cowprotocol/ui' +import { MouseoverTooltipContent } from '@cowprotocol/ui' + import { transparentize } from 'polished' import { Text } from 'rebass' import styled from 'styled-components/macro' -import { RowBetween, RowFixed } from 'legacy/components/Row' -import { MouseoverTooltipContent } from 'legacy/components/Tooltip' +import { UI } from 'common/constants/theme' import { RowStyleProps } from './types' @@ -21,7 +23,7 @@ export const StyledRowBetween = styled(RowBetween)` } ${TextWrapper} { - color: ${({ theme }) => theme.text1}; + color: var(${UI.COLOR_TEXT1}); font-size: ${({ fontSize = 13 }) => fontSize}px; font-weight: ${({ fontWeight = 500 }) => fontWeight}; @@ -30,7 +32,7 @@ export const StyledRowBetween = styled(RowBetween)` font-weight: 400; &:hover { - color: ${({ theme }) => theme.text1}; + color: var(${UI.COLOR_TEXT1}); } } @@ -45,6 +47,6 @@ export const StyledRowBetween = styled(RowBetween)` ${StyledMouseoverTooltipContent} { background-color: ${({ theme }) => theme.bg3}; - color: ${({ theme }) => theme.text1}; + color: var(${UI.COLOR_TEXT1}); } ` diff --git a/apps/cowswap-frontend/src/modules/swap/pure/SwapButton/index.tsx b/apps/cowswap-frontend/src/modules/swap/pure/SwapButton/index.tsx index 7720b3b6d0..1436d521a8 100644 --- a/apps/cowswap-frontend/src/modules/swap/pure/SwapButton/index.tsx +++ b/apps/cowswap-frontend/src/modules/swap/pure/SwapButton/index.tsx @@ -1,5 +1,4 @@ -import { ButtonError } from 'legacy/components/Button' -import { ButtonSize } from 'legacy/theme/enum' +import { ButtonSize, ButtonError } from '@cowprotocol/ui' export interface SwapButtonProps { disabled: boolean diff --git a/apps/cowswap-frontend/src/modules/swap/pure/SwapButtons/index.cosmos.tsx b/apps/cowswap-frontend/src/modules/swap/pure/SwapButtons/index.cosmos.tsx index 1ac4344f6a..e38c510c54 100644 --- a/apps/cowswap-frontend/src/modules/swap/pure/SwapButtons/index.cosmos.tsx +++ b/apps/cowswap-frontend/src/modules/swap/pure/SwapButtons/index.cosmos.tsx @@ -1,9 +1,9 @@ +import { WETH_GOERLI } from '@cowprotocol/common-const' import { CurrencyAmount } from '@uniswap/sdk-core' import { useSelect } from 'react-cosmos/client' -import { Field } from 'legacy/state/swap/actions' -import { WETH_GOERLI } from 'legacy/utils/goerli/constants' +import { Field } from 'legacy/state/types' import { SwapButtonState } from 'modules/swap/helpers/getSwapButtonState' diff --git a/apps/cowswap-frontend/src/modules/swap/pure/SwapButtons/index.tsx b/apps/cowswap-frontend/src/modules/swap/pure/SwapButtons/index.tsx index a225e29457..8605cc9de6 100644 --- a/apps/cowswap-frontend/src/modules/swap/pure/SwapButtons/index.tsx +++ b/apps/cowswap-frontend/src/modules/swap/pure/SwapButtons/index.tsx @@ -1,26 +1,23 @@ import React, { ReactNode } from 'react' +import { GpEther } from '@cowprotocol/common-const' +import { genericPropsChecker } from '@cowprotocol/common-utils' import { SupportedChainId } from '@cowprotocol/cow-sdk' +import { AutoRow, ButtonError, ButtonPrimary, ButtonSize, TokenSymbol } from '@cowprotocol/ui' import { Currency, CurrencyAmount, Token } from '@uniswap/sdk-core' import { Trans } from '@lingui/macro' import { Text } from 'rebass' -import { ButtonError, ButtonPrimary } from 'legacy/components/Button' import { GreyCard } from 'legacy/components/Card' import { AutoColumn } from 'legacy/components/Column' -import { AutoRow } from 'legacy/components/Row' -import { GpEther } from 'legacy/constants/tokens' import { WrapUnwrapCallback } from 'legacy/hooks/useWrapCallback' -import { Field } from 'legacy/state/swap/actions' -import { ButtonSize } from 'legacy/theme/enum' +import { Field } from 'legacy/state/types' import { EthFlowBanner } from 'modules/swap/containers/EthFlow/EthFlowBanner' import { SwapButtonState } from 'modules/swap/helpers/getSwapButtonState' import { TradeApproveButton } from 'common/containers/TradeApprove/TradeApproveButton' -import { TokenSymbol } from 'common/pure/TokenSymbol' -import { genericPropsChecker } from 'utils/genericPropsChecker' import * as styledEl from './styled' diff --git a/apps/cowswap-frontend/src/modules/swap/pure/SwapButtons/styled.tsx b/apps/cowswap-frontend/src/modules/swap/pure/SwapButtons/styled.tsx index b650ca0ec7..67b300bd11 100644 --- a/apps/cowswap-frontend/src/modules/swap/pure/SwapButtons/styled.tsx +++ b/apps/cowswap-frontend/src/modules/swap/pure/SwapButtons/styled.tsx @@ -1,8 +1,6 @@ -import { Text } from 'rebass' +import { ButtonSize, ButtonError, RowBetween } from '@cowprotocol/ui' -import { ButtonError } from 'legacy/components/Button' -import { RowBetween } from 'legacy/components/Row' -import { ButtonSize } from 'legacy/theme/enum' +import { Text } from 'rebass' import { TradeLoadingButton } from 'common/pure/TradeLoadingButton' diff --git a/apps/cowswap-frontend/src/modules/swap/pure/TradeRates/index.cosmos.tsx b/apps/cowswap-frontend/src/modules/swap/pure/TradeRates/index.cosmos.tsx index aa549df0a8..bbf5431c70 100644 --- a/apps/cowswap-frontend/src/modules/swap/pure/TradeRates/index.cosmos.tsx +++ b/apps/cowswap-frontend/src/modules/swap/pure/TradeRates/index.cosmos.tsx @@ -1,7 +1,7 @@ +import { COW, GNO } from '@cowprotocol/common-const' import { SupportedChainId } from '@cowprotocol/cow-sdk' import { CurrencyAmount, TradeType, Price, Percent } from '@uniswap/sdk-core' -import { COW, GNO } from 'legacy/constants/tokens' import TradeGp from 'legacy/state/swap/TradeGp' import { TradeRates, TradeRatesProps } from 'modules/swap/pure/TradeRates/index' diff --git a/apps/cowswap-frontend/src/modules/swap/pure/TradeRates/index.tsx b/apps/cowswap-frontend/src/modules/swap/pure/TradeRates/index.tsx index efc3ae3ce3..7a29e549f0 100644 --- a/apps/cowswap-frontend/src/modules/swap/pure/TradeRates/index.tsx +++ b/apps/cowswap-frontend/src/modules/swap/pure/TradeRates/index.tsx @@ -1,5 +1,6 @@ import React from 'react' +import { genericPropsChecker } from '@cowprotocol/common-utils' import { Currency, CurrencyAmount, Percent } from '@uniswap/sdk-core' import TradeGp from 'legacy/state/swap/TradeGp' @@ -8,7 +9,6 @@ import { RowDeadline } from 'modules/swap/containers/Row/RowDeadline' import { TradeBasicDetails } from 'modules/swap/containers/TradeBasicDetails' import { RateInfoParams } from 'common/pure/RateInfo' -import { genericPropsChecker } from 'utils/genericPropsChecker' import * as styledEl from './styled' diff --git a/apps/cowswap-frontend/src/modules/swap/pure/TradeRates/styled.tsx b/apps/cowswap-frontend/src/modules/swap/pure/TradeRates/styled.tsx index 20b75dc857..9e03f75df1 100644 --- a/apps/cowswap-frontend/src/modules/swap/pure/TradeRates/styled.tsx +++ b/apps/cowswap-frontend/src/modules/swap/pure/TradeRates/styled.tsx @@ -4,6 +4,7 @@ import styled from 'styled-components/macro' import QuestionHelper from 'legacy/components/QuestionHelper' +import { UI } from 'common/constants/theme' import { RateInfo } from 'common/pure/RateInfo' export const Box = styled.div` @@ -15,7 +16,7 @@ export const Row = styled.div` justify-content: space-between; font-size: 13px; font-weight: 400; - color: ${({ theme }) => theme.text1}; + color: var(${UI.COLOR_TEXT1}); min-height: 24px; gap: 3px; @@ -33,7 +34,7 @@ export const Row = styled.div` transition: color 0.15s ease-in-out; &:hover { - color: ${({ theme }) => theme.text1}; + color: var(${UI.COLOR_TEXT1}); } } @@ -63,8 +64,8 @@ export const Discount = styled.span` display: flex; cursor: pointer; padding: 2px 8px; - background: ${({ theme }) => theme.grey1}; - color: ${({ theme }) => theme.text1}; + background: var(${UI.COLOR_GREY}); + color: var(${UI.COLOR_TEXT1}); border-radius: 5px; font-weight: 400; transition: background 0.2s ease-in-out, color 0.2s ease-in-out; diff --git a/apps/cowswap-frontend/src/modules/swap/pure/TradeSummary/index.cosmos.tsx b/apps/cowswap-frontend/src/modules/swap/pure/TradeSummary/index.cosmos.tsx index 2569881d99..e6029d9b64 100644 --- a/apps/cowswap-frontend/src/modules/swap/pure/TradeSummary/index.cosmos.tsx +++ b/apps/cowswap-frontend/src/modules/swap/pure/TradeSummary/index.cosmos.tsx @@ -1,7 +1,7 @@ +import { COW, GNO } from '@cowprotocol/common-const' import { SupportedChainId } from '@cowprotocol/cow-sdk' import { CurrencyAmount, TradeType, Price, Percent } from '@uniswap/sdk-core' -import { COW, GNO } from 'legacy/constants/tokens' import TradeGp from 'legacy/state/swap/TradeGp' import { TradeSummaryProps } from 'modules/swap/containers/TradeSummary' diff --git a/apps/cowswap-frontend/src/modules/swap/pure/banners/TwapSuggestionBanner.tsx b/apps/cowswap-frontend/src/modules/swap/pure/banners/TwapSuggestionBanner.tsx index d8d4033eb3..76f54c9b2e 100644 --- a/apps/cowswap-frontend/src/modules/swap/pure/banners/TwapSuggestionBanner.tsx +++ b/apps/cowswap-frontend/src/modules/swap/pure/banners/TwapSuggestionBanner.tsx @@ -54,7 +54,7 @@ export function TwapSuggestionBanner({ parameterizeTradeRoute(tradeUrlParams, Routes.ADVANCED_ORDERS) + `?${TRADE_URL_SELL_AMOUNT_KEY}=${sellAmount}` return ( - + Minimize price impact with TWAP

The price impact is {+priceImpact.toFixed(2)}%. Consider breaking up your order using a{' '} diff --git a/apps/cowswap-frontend/src/modules/swap/pure/styled.tsx b/apps/cowswap-frontend/src/modules/swap/pure/styled.tsx index 19fe60b682..1c5c48b49a 100644 --- a/apps/cowswap-frontend/src/modules/swap/pure/styled.tsx +++ b/apps/cowswap-frontend/src/modules/swap/pure/styled.tsx @@ -1,8 +1,10 @@ +import { RowBetween } from '@cowprotocol/ui' + import { transparentize } from 'polished' import { Info } from 'react-feather' import styled from 'styled-components/macro' -import { RowBetween } from 'legacy/components/Row' +import { UI } from 'common/constants/theme' export const LowerSectionWrapper = styled(RowBetween).attrs((props) => ({ ...props, @@ -26,7 +28,7 @@ export const BottomGrouping = styled.div` div > svg, div > svg > path { - stroke: ${({ theme }) => theme.text2}; + stroke: var(${UI.COLOR_TEXT2}); } ` export const LightGreyText = styled.span` @@ -36,7 +38,7 @@ export const LightGreyText = styled.span` export const StyledInfoIcon = styled(Info)` opacity: 0.5; - stroke: ${({ theme }) => theme.text1}; + stroke: var(${UI.COLOR_TEXT1}); line-height: 0; vertical-align: middle; transition: opacity 0.2s ease-in-out; diff --git a/apps/cowswap-frontend/src/modules/swap/pure/warnings.tsx b/apps/cowswap-frontend/src/modules/swap/pure/warnings.tsx index c7720cf4f5..f7720bd985 100644 --- a/apps/cowswap-frontend/src/modules/swap/pure/warnings.tsx +++ b/apps/cowswap-frontend/src/modules/swap/pure/warnings.tsx @@ -1,5 +1,6 @@ import React from 'react' +import { genericPropsChecker } from '@cowprotocol/common-utils' import { SupportedChainId } from '@cowprotocol/cow-sdk' import { Currency, CurrencyAmount, Percent } from '@uniswap/sdk-core' @@ -12,10 +13,8 @@ import { CompatibilityIssuesWarning } from 'modules/trade/pure/CompatibilityIssu import { NoImpactWarning } from 'modules/trade/pure/NoImpactWarning' import { TradeUrlParams } from 'modules/trade/types/TradeRawState' -import { FeatureGuard } from 'common/containers/FeatureGuard' import { BundleTxApprovalBanner, BundleTxSafeWcBanner, BundleTxWrapBanner } from 'common/pure/InlineBanner/banners' import { ZeroApprovalWarning } from 'common/pure/ZeroApprovalWarning' -import { genericPropsChecker } from 'utils/genericPropsChecker' import { TwapSuggestionBanner } from './banners/TwapSuggestionBanner' @@ -97,15 +96,13 @@ export const SwapWarningsTop = React.memo(function (props: SwapWarningsTopProps) )} - - - + ) }, genericPropsChecker) diff --git a/apps/cowswap-frontend/src/modules/swap/services/ethFlow/index.ts b/apps/cowswap-frontend/src/modules/swap/services/ethFlow/index.ts index ba405d9814..0869204e42 100644 --- a/apps/cowswap-frontend/src/modules/swap/services/ethFlow/index.ts +++ b/apps/cowswap-frontend/src/modules/swap/services/ethFlow/index.ts @@ -25,7 +25,7 @@ export async function ethFlow( appDataInfo, dispatch, orderParams: orderParamsOriginal, - checkInFlightOrderIdExists, + checkEthFlowOrderExists, addInFlightOrderId, } = ethFlowContext @@ -40,11 +40,7 @@ export async function ethFlow( swapConfirmManager.sendTransaction(context.trade) logTradeFlow('ETH FLOW', 'STEP 3: Get Unique Order Id (prevent collisions)') - const { orderId, orderParams } = await calculateUniqueOrderId( - orderParamsOriginal, - contract, - checkInFlightOrderIdExists - ) + const { orderId, orderParams } = await calculateUniqueOrderId(orderParamsOriginal, contract, checkEthFlowOrderExists) try { logTradeFlow('ETH FLOW', 'STEP 4: sign order') diff --git a/apps/cowswap-frontend/src/modules/swap/services/ethFlow/mocks.ts b/apps/cowswap-frontend/src/modules/swap/services/ethFlow/mocks.ts index fcb7ba2530..669903f979 100644 --- a/apps/cowswap-frontend/src/modules/swap/services/ethFlow/mocks.ts +++ b/apps/cowswap-frontend/src/modules/swap/services/ethFlow/mocks.ts @@ -1,8 +1,7 @@ +import { nativeOnChain, WRAPPED_NATIVE_CURRENCY as WETH } from '@cowprotocol/common-const' import { SupportedChainId } from '@cowprotocol/cow-sdk' import { CurrencyAmount } from '@uniswap/sdk-core' -import { nativeOnChain, WRAPPED_NATIVE_CURRENCY as WETH } from 'legacy/constants/tokens' - import { EthFlowActions } from 'modules/swap/containers/EthFlow/hooks/useEthFlowActions' import { EthFlowModalContentProps } from 'modules/swap/pure/EthFlow/EthFlowModalContent' import { BalanceChecks } from 'modules/swap/pure/EthFlow/EthFlowModalContent/EthFlowModalTopContent' diff --git a/apps/cowswap-frontend/src/modules/swap/services/ethFlow/steps/calculateUniqueOrderId.ts b/apps/cowswap-frontend/src/modules/swap/services/ethFlow/steps/calculateUniqueOrderId.ts index 7ff21788dd..66e05b9d5c 100644 --- a/apps/cowswap-frontend/src/modules/swap/services/ethFlow/steps/calculateUniqueOrderId.ts +++ b/apps/cowswap-frontend/src/modules/swap/services/ethFlow/steps/calculateUniqueOrderId.ts @@ -1,14 +1,15 @@ +import { CoWSwapEthFlow } from '@cowprotocol/abis' +import { WRAPPED_NATIVE_CURRENCY } from '@cowprotocol/common-const' +import { MAX_VALID_TO_EPOCH } from '@cowprotocol/common-utils' import type { Order } from '@cowprotocol/contracts' import { OrderSigningUtils } from '@cowprotocol/cow-sdk' -import { CoWSwapEthFlow } from '@cowswap/abis' import { CurrencyAmount } from '@uniswap/sdk-core' -import { WRAPPED_NATIVE_CURRENCY } from 'legacy/constants/tokens' import { getSignOrderParams, PostOrderParams } from 'legacy/utils/trade' import { logTradeFlow } from 'modules/trade/utils/logger' -import { MAX_VALID_TO_EPOCH } from 'utils/time' +import { EthFlowOrderExistsCallback } from '../../../hooks/useCheckEthFlowOrderExists' export interface UniqueOrderIdResult { orderId: string @@ -33,7 +34,7 @@ function incrementFee(params: PostOrderParams): PostOrderParams { export async function calculateUniqueOrderId( orderParams: PostOrderParams, ethFlowContract: CoWSwapEthFlow, - checkInFlightOrderIdExists: (orderId: string) => boolean + checkEthFlowOrderExists: EthFlowOrderExistsCallback ): Promise { logTradeFlow('ETH FLOW', '[EthFlow::calculateUniqueOrderId] - Calculate unique order Id', orderParams) const { chainId } = orderParams @@ -59,11 +60,11 @@ export async function calculateUniqueOrderId( sellAmount: orderParams.inputAmount.quotient.toString(), fee: orderParams.feeAmount?.quotient.toString(), } - if (checkInFlightOrderIdExists(orderId)) { + if (await checkEthFlowOrderExists(orderId, orderDigest)) { logTradeFlow('ETH FLOW', '[calculateUniqueOrderId] ❌ Collision detected: ' + orderId, logParams) // Recursive call, increment one fee until we get an unique order Id - return calculateUniqueOrderId(incrementFee(orderParams), ethFlowContract, checkInFlightOrderIdExists) + return calculateUniqueOrderId(incrementFee(orderParams), ethFlowContract, checkEthFlowOrderExists) } logTradeFlow('ETH FLOW', '[calculateUniqueOrderId] ✅ Order Id is Unique' + orderId, logParams) diff --git a/apps/cowswap-frontend/src/modules/swap/services/ethFlow/steps/signEthFlowOrderStep.ts b/apps/cowswap-frontend/src/modules/swap/services/ethFlow/steps/signEthFlowOrderStep.ts index 1d8f6fa53a..2f905eff00 100644 --- a/apps/cowswap-frontend/src/modules/swap/services/ethFlow/steps/signEthFlowOrderStep.ts +++ b/apps/cowswap-frontend/src/modules/swap/services/ethFlow/steps/signEthFlowOrderStep.ts @@ -1,10 +1,10 @@ +import { CoWSwapEthFlow } from '@cowprotocol/abis' +import { calculateGasMargin } from '@cowprotocol/common-utils' import { OrderClass, UnsignedOrder } from '@cowprotocol/cow-sdk' -import { CoWSwapEthFlow } from '@cowswap/abis' import { ContractTransaction } from '@ethersproject/contracts' import { NativeCurrency } from '@uniswap/sdk-core' import { Order } from 'legacy/state/orders/actions' -import { calculateGasMargin } from 'legacy/utils/calculateGasMargin' import { getSignOrderParams, mapUnsignedOrderToOrder, PostOrderParams } from 'legacy/utils/trade' import { ETHFLOW_GAS_LIMIT_DEFAULT } from 'modules/swap/services/ethFlow/const' diff --git a/apps/cowswap-frontend/src/modules/swap/services/ethFlow/transactionsMocks.ts b/apps/cowswap-frontend/src/modules/swap/services/ethFlow/transactionsMocks.ts index ba49c9e096..aeac0d9705 100644 --- a/apps/cowswap-frontend/src/modules/swap/services/ethFlow/transactionsMocks.ts +++ b/apps/cowswap-frontend/src/modules/swap/services/ethFlow/transactionsMocks.ts @@ -1,4 +1,4 @@ -import store from 'legacy/state' +import { cowSwapStore } from 'legacy/state' import { addTransaction, finalizeTransaction } from 'legacy/state/enhancedTransactions/actions' import { HashType } from 'legacy/state/enhancedTransactions/reducer' @@ -12,7 +12,7 @@ export const ApproveErrorTxHashMock = '0x138b032570b443508a0a102f1d15949401acf2b export function mockEthFlowPendingTxs() { // Wrap transactions - store.dispatch( + cowSwapStore.dispatch( addTransaction({ hash: WrapPendingTxHashMock, hashType: HashType.ETHEREUM_TX, @@ -22,7 +22,7 @@ export function mockEthFlowPendingTxs() { }) ) - store.dispatch( + cowSwapStore.dispatch( addTransaction({ hash: WrapSuccessfulTxHashMock, hashType: HashType.ETHEREUM_TX, @@ -31,7 +31,7 @@ export function mockEthFlowPendingTxs() { summary: 'Wrap 0.02 WETH to Ether', }) ) - store.dispatch( + cowSwapStore.dispatch( finalizeTransaction({ hash: WrapSuccessfulTxHashMock, chainId: 5, @@ -48,7 +48,7 @@ export function mockEthFlowPendingTxs() { }) ) - store.dispatch( + cowSwapStore.dispatch( addTransaction({ hash: WrapErrorTxHashMock, hashType: HashType.ETHEREUM_TX, @@ -57,7 +57,7 @@ export function mockEthFlowPendingTxs() { summary: 'Wrap 0.02 WETH to Ether', }) ) - store.dispatch( + cowSwapStore.dispatch( finalizeTransaction({ hash: WrapErrorTxHashMock, chainId: 5, @@ -75,7 +75,7 @@ export function mockEthFlowPendingTxs() { ) // Approve transactions - store.dispatch( + cowSwapStore.dispatch( addTransaction({ hash: ApprovePendingTxHashMock, hashType: HashType.ETHEREUM_TX, @@ -89,7 +89,7 @@ export function mockEthFlowPendingTxs() { }) ) - store.dispatch( + cowSwapStore.dispatch( addTransaction({ hash: ApproveSuccessfulTxHashMock, hashType: HashType.ETHEREUM_TX, @@ -102,7 +102,7 @@ export function mockEthFlowPendingTxs() { summary: 'Approve GNO', }) ) - store.dispatch( + cowSwapStore.dispatch( finalizeTransaction({ hash: ApproveSuccessfulTxHashMock, chainId: 5, @@ -119,7 +119,7 @@ export function mockEthFlowPendingTxs() { }) ) - store.dispatch( + cowSwapStore.dispatch( addTransaction({ hash: ApproveErrorTxHashMock, hashType: HashType.ETHEREUM_TX, @@ -132,7 +132,7 @@ export function mockEthFlowPendingTxs() { summary: 'Approve GNO', }) ) - store.dispatch( + cowSwapStore.dispatch( finalizeTransaction({ hash: ApproveErrorTxHashMock, chainId: 5, diff --git a/apps/cowswap-frontend/src/modules/swap/services/safeBundleFlow/safeBundleEthFlow.ts b/apps/cowswap-frontend/src/modules/swap/services/safeBundleFlow/safeBundleEthFlow.ts index abcc1d9245..3186cbc225 100644 --- a/apps/cowswap-frontend/src/modules/swap/services/safeBundleFlow/safeBundleEthFlow.ts +++ b/apps/cowswap-frontend/src/modules/swap/services/safeBundleFlow/safeBundleEthFlow.ts @@ -1,4 +1,4 @@ -import { Erc20 } from '@cowswap/abis' +import { Erc20 } from '@cowprotocol/abis' import { MetaTransactionData } from '@safe-global/safe-core-sdk-types' import { Percent } from '@uniswap/sdk-core' diff --git a/apps/cowswap-frontend/src/modules/swap/services/swapFlow/index.ts b/apps/cowswap-frontend/src/modules/swap/services/swapFlow/index.ts index a23c0e492f..ec49a936b3 100644 --- a/apps/cowswap-frontend/src/modules/swap/services/swapFlow/index.ts +++ b/apps/cowswap-frontend/src/modules/swap/services/swapFlow/index.ts @@ -1,16 +1,17 @@ -import { Percent } from '@uniswap/sdk-core' +import { Percent, Token } from '@uniswap/sdk-core' import { PriceImpact } from 'legacy/hooks/usePriceImpact' import { partialOrderUpdate } from 'legacy/state/orders/utils' import { signAndPostOrder } from 'legacy/utils/trade' +import { handlePermit } from 'modules/permit' import { addPendingOrderStep } from 'modules/trade/utils/addPendingOrderStep' +import { tradeFlowAnalytics } from 'modules/trade/utils/analytics' import { logTradeFlow } from 'modules/trade/utils/logger' import { getSwapErrorMessage } from 'modules/trade/utils/swapErrorHelper' import { presignOrderStep } from './steps/presignOrderStep' -import { tradeFlowAnalytics } from '../../../trade/utils/analytics' import { SwapFlowContext } from '../types' export async function swapFlow( @@ -23,12 +24,24 @@ export async function swapFlow( return } - logTradeFlow('SWAP FLOW', 'STEP 2: send transaction') - tradeFlowAnalytics.trade(input.swapFlowAnalyticsContext) - input.swapConfirmManager.sendTransaction(input.context.trade) - try { - logTradeFlow('SWAP FLOW', 'STEP 3: sign and post order') + logTradeFlow('SWAP FLOW', 'STEP 2: handle permit') + if (input.permitInfo) input.swapConfirmManager.requestPermitSignature() + + input.orderParams.appData = await handlePermit({ + appData: input.orderParams.appData, + inputToken: input.context.trade.inputAmount.currency as Token, + account: input.orderParams.account, + permitInfo: input.permitInfo, + generatePermitHook: input.generatePermitHook, + }) + input.swapConfirmManager.permitSigned() + + logTradeFlow('SWAP FLOW', 'STEP 3: send transaction') + tradeFlowAnalytics.trade(input.swapFlowAnalyticsContext) + input.swapConfirmManager.sendTransaction(input.context.trade) + + logTradeFlow('SWAP FLOW', 'STEP 4: sign and post order') const { id: orderId, order } = await signAndPostOrder(input.orderParams).finally(() => { input.callbacks.closeModals() }) @@ -45,12 +58,12 @@ export async function swapFlow( input.dispatch ) - logTradeFlow('SWAP FLOW', 'STEP 4: presign order (optional)') + logTradeFlow('SWAP FLOW', 'STEP 5: presign order (optional)') const presignTx = await (input.flags.allowsOffchainSigning ? Promise.resolve(null) : presignOrderStep(orderId, input.contract)) - logTradeFlow('SWAP FLOW', 'STEP 5: unhide SC order (optional)') + logTradeFlow('SWAP FLOW', 'STEP 6: unhide SC order (optional)') if (presignTx) { partialOrderUpdate( { @@ -65,11 +78,11 @@ export async function swapFlow( ) } - logTradeFlow('SWAP FLOW', 'STEP 6: show UI of the successfully sent transaction', orderId) + logTradeFlow('SWAP FLOW', 'STEP 7: show UI of the successfully sent transaction', orderId) input.swapConfirmManager.transactionSent(orderId) tradeFlowAnalytics.sign(input.swapFlowAnalyticsContext) } catch (error: any) { - logTradeFlow('SWAP FLOW', 'STEP 7: ERROR: ', error) + logTradeFlow('SWAP FLOW', 'STEP 8: ERROR: ', error) const swapErrorMessage = getSwapErrorMessage(error) tradeFlowAnalytics.error(error, swapErrorMessage, input.swapFlowAnalyticsContext) diff --git a/apps/cowswap-frontend/src/modules/swap/services/swapFlow/steps/presignOrderStep.ts b/apps/cowswap-frontend/src/modules/swap/services/swapFlow/steps/presignOrderStep.ts index 54e4735871..3705c2df45 100644 --- a/apps/cowswap-frontend/src/modules/swap/services/swapFlow/steps/presignOrderStep.ts +++ b/apps/cowswap-frontend/src/modules/swap/services/swapFlow/steps/presignOrderStep.ts @@ -1,9 +1,8 @@ -import { GPv2Settlement } from '@cowswap/abis' +import { GPv2Settlement } from '@cowprotocol/abis' +import { calculateGasMargin } from '@cowprotocol/common-utils' import { BigNumber } from '@ethersproject/bignumber' import { ContractTransaction } from '@ethersproject/contracts' -import { calculateGasMargin } from 'legacy/utils/calculateGasMargin' - import { logTradeFlow, logTradeFlowError } from 'modules/trade/utils/logger' // Use a 150K gas as a fallback if there's issue calculating the gas estimation (fixes some issues with some nodes failing to calculate gas costs for SC wallets) diff --git a/apps/cowswap-frontend/src/modules/swap/services/types.ts b/apps/cowswap-frontend/src/modules/swap/services/types.ts index e8c963faba..52d3f55a30 100644 --- a/apps/cowswap-frontend/src/modules/swap/services/types.ts +++ b/apps/cowswap-frontend/src/modules/swap/services/types.ts @@ -1,5 +1,4 @@ -import { GPv2Settlement, CoWSwapEthFlow } from '@cowswap/abis' -import { Erc20, Weth } from '@cowswap/abis' +import { CoWSwapEthFlow, Erc20, GPv2Settlement, Weth } from '@cowprotocol/abis' import { Web3Provider } from '@ethersproject/providers' import SafeAppsSDK from '@safe-global/safe-apps-sdk' import { Currency, CurrencyAmount } from '@uniswap/sdk-core' @@ -11,9 +10,11 @@ import TradeGp from 'legacy/state/swap/TradeGp' import { PostOrderParams } from 'legacy/utils/trade' import { AppDataInfo, UploadAppDataParams } from 'modules/appData' +import { GeneratePermitHook, IsTokenPermittableResult } from 'modules/permit' import { SwapConfirmManager } from 'modules/swap/hooks/useSwapConfirmManager' import { SwapFlowAnalyticsContext } from 'modules/trade/utils/analytics' +import { EthFlowOrderExistsCallback } from '../hooks/useCheckEthFlowOrderExists' import { FlowType } from '../hooks/useFlowContext' export interface BaseFlowContext { @@ -33,6 +34,7 @@ export interface BaseFlowContext { addOrderCallback: AddOrderCallback uploadAppData: (params: UploadAppDataParams) => void } + sellTokenContract: Erc20 | null dispatch: AppDispatch swapFlowAnalyticsContext: SwapFlowAnalyticsContext swapConfirmManager: SwapConfirmManager @@ -42,12 +44,14 @@ export interface BaseFlowContext { export type SwapFlowContext = BaseFlowContext & { contract: GPv2Settlement + permitInfo: IsTokenPermittableResult + generatePermitHook: GeneratePermitHook } export type EthFlowContext = BaseFlowContext & { contract: CoWSwapEthFlow addTransaction: ReturnType - checkInFlightOrderIdExists: (orderId: string) => boolean + checkEthFlowOrderExists: EthFlowOrderExistsCallback addInFlightOrderId: (orderId: string) => void } diff --git a/apps/cowswap-frontend/src/modules/swap/state/EthFlow/updaters/EthFlowDeadlineUpdater.tsx b/apps/cowswap-frontend/src/modules/swap/state/EthFlow/updaters/EthFlowDeadlineUpdater.tsx index d2990c1112..21ba267bc1 100644 --- a/apps/cowswap-frontend/src/modules/swap/state/EthFlow/updaters/EthFlowDeadlineUpdater.tsx +++ b/apps/cowswap-frontend/src/modules/swap/state/EthFlow/updaters/EthFlowDeadlineUpdater.tsx @@ -1,12 +1,12 @@ import { useEffect, useRef } from 'react' -import { MINIMUM_ETH_FLOW_DEADLINE_SECONDS } from 'legacy/constants' +import { MINIMUM_ETH_FLOW_DEADLINE_SECONDS } from '@cowprotocol/common-const' +import { loadJsonFromLocalStorage, setJsonToLocalStorage } from '@cowprotocol/common-utils' + import { useUserTransactionTTL } from 'legacy/state/user/hooks' import { useIsEoaEthFlow } from 'modules/swap/hooks/useIsEoaEthFlow' -import { loadJsonFromLocalStorage, setJsonToLocalStorage } from 'utils/localStorage' - import { DeadlineSettings } from './types' const LOCAL_STORAGE_KEY = 'UserDeadlineSettings' diff --git a/apps/cowswap-frontend/src/modules/swap/state/EthFlow/updaters/EthFlowSlippageUpdater.tsx b/apps/cowswap-frontend/src/modules/swap/state/EthFlow/updaters/EthFlowSlippageUpdater.tsx index 3bdfa52fd9..04abefcc9e 100644 --- a/apps/cowswap-frontend/src/modules/swap/state/EthFlow/updaters/EthFlowSlippageUpdater.tsx +++ b/apps/cowswap-frontend/src/modules/swap/state/EthFlow/updaters/EthFlowSlippageUpdater.tsx @@ -1,14 +1,13 @@ import { useEffect, useRef } from 'react' +import { MINIMUM_ETH_FLOW_SLIPPAGE } from '@cowprotocol/common-const' +import { loadJsonFromLocalStorage, setJsonToLocalStorage } from '@cowprotocol/common-utils' import { Percent } from '@uniswap/sdk-core' -import { MINIMUM_ETH_FLOW_SLIPPAGE } from 'legacy/constants' import { useSetUserSlippageTolerance, useUserSlippageTolerance } from 'legacy/state/user/hooks' import { useIsEoaEthFlow } from 'modules/swap/hooks/useIsEoaEthFlow' -import { loadJsonFromLocalStorage, setJsonToLocalStorage } from 'utils/localStorage' - import { SerializedSlippage, SerializedSlippageSettings, Slippage, SlippageSettings } from './types' const LOCAL_STORAGE_KEY = 'UserSlippageSettings' diff --git a/apps/cowswap-frontend/src/modules/swap/state/swapConfirmAtom.ts b/apps/cowswap-frontend/src/modules/swap/state/swapConfirmAtom.ts index c69a80f056..0bd8d19589 100644 --- a/apps/cowswap-frontend/src/modules/swap/state/swapConfirmAtom.ts +++ b/apps/cowswap-frontend/src/modules/swap/state/swapConfirmAtom.ts @@ -8,6 +8,7 @@ export interface SwapConfirmState { attemptingTxn: boolean swapErrorMessage: string | undefined txHash: string | undefined + permitSignatureState: undefined | 'requested' | 'signed' } export const swapConfirmAtom = atom({ @@ -16,4 +17,5 @@ export const swapConfirmAtom = atom({ attemptingTxn: false, swapErrorMessage: undefined, txHash: undefined, + permitSignatureState: undefined, }) diff --git a/apps/cowswap-frontend/src/modules/swap/state/useSwapDerivedState.ts b/apps/cowswap-frontend/src/modules/swap/state/useSwapDerivedState.ts index 365c0a9dfd..51e0f63f12 100644 --- a/apps/cowswap-frontend/src/modules/swap/state/useSwapDerivedState.ts +++ b/apps/cowswap-frontend/src/modules/swap/state/useSwapDerivedState.ts @@ -3,15 +3,17 @@ import { useEffect } from 'react' import { OrderKind } from '@cowprotocol/cow-sdk' -import { Field } from 'legacy/state/swap/actions' -import { useDerivedSwapInfo, useSwapState } from 'legacy/state/swap/hooks' +import { Field } from 'legacy/state/types' +import { TradeType } from 'modules/trade' import { useTradeUsdAmounts } from 'modules/usdAmount' import { useSafeMemoObject } from 'common/hooks/useSafeMemo' import { SwapDerivedState, swapDerivedStateAtom } from './swapDerivedStateAtom' +import { useDerivedSwapInfo, useSwapState } from '../hooks/useSwapState' + export function useSwapDerivedState(): SwapDerivedState { return useAtomValue(swapDerivedStateAtom) } @@ -48,6 +50,7 @@ export function useFillSwapDerivedState() { recipient, recipientAddress, orderKind: isSellTrade ? OrderKind.SELL : OrderKind.BUY, + tradeType: TradeType.SWAP, }) useEffect(() => { diff --git a/apps/cowswap-frontend/src/modules/tokens/hooks/useBalancesAndAllowances.ts b/apps/cowswap-frontend/src/modules/tokens/hooks/useBalancesAndAllowances.ts index 38dcbd6df8..7d16e34069 100644 --- a/apps/cowswap-frontend/src/modules/tokens/hooks/useBalancesAndAllowances.ts +++ b/apps/cowswap-frontend/src/modules/tokens/hooks/useBalancesAndAllowances.ts @@ -5,7 +5,7 @@ import { BalancesAndAllowances, BalancesAndAllowancesParams } from '../types' /** * Return the balances and allowances of the tokens. * - * This hooks is different than the useOnchainBalancesAndAllowance one in the fact that the user might contain some + * This hook is different from the useOnchainBalancesAndAllowance one in the fact that the user might contain some * un-commited transaction that might affect the balances. */ export function useBalancesAndAllowances(params: BalancesAndAllowancesParams): BalancesAndAllowances { diff --git a/apps/cowswap-frontend/src/modules/tokens/hooks/useCurrencyBalance.ts b/apps/cowswap-frontend/src/modules/tokens/hooks/useCurrencyBalance.ts index dfc031323e..f2a4d6ad19 100644 --- a/apps/cowswap-frontend/src/modules/tokens/hooks/useCurrencyBalance.ts +++ b/apps/cowswap-frontend/src/modules/tokens/hooks/useCurrencyBalance.ts @@ -2,17 +2,16 @@ import { useMemo } from 'react' +import { nativeOnChain } from '@cowprotocol/common-const' +import { useInterfaceMulticall } from '@cowprotocol/common-hooks' +import { isAddress } from '@cowprotocol/common-utils' +import { useWalletInfo } from '@cowprotocol/wallet' import { Currency, CurrencyAmount, Token } from '@uniswap/sdk-core' import JSBI from 'jsbi' -import { nativeOnChain } from 'legacy/constants/tokens' -import { useInterfaceMulticall } from 'legacy/hooks/useContract' -import { isAddress } from 'legacy/utils' - import { useOnchainBalances } from 'modules/tokens' import { TokenAmounts } from 'modules/tokens' -import { useWalletInfo } from 'modules/wallet' import { useSingleContractMultipleData } from 'lib/hooks/multicall' diff --git a/apps/cowswap-frontend/src/modules/tokens/hooks/useEnoughBalance.ts b/apps/cowswap-frontend/src/modules/tokens/hooks/useEnoughBalance.ts index cdadded320..e3fb3eeb8e 100644 --- a/apps/cowswap-frontend/src/modules/tokens/hooks/useEnoughBalance.ts +++ b/apps/cowswap-frontend/src/modules/tokens/hooks/useEnoughBalance.ts @@ -1,8 +1,7 @@ +import { isEnoughAmount, getAddress } from '@cowprotocol/common-utils' import { Currency, CurrencyAmount, Token } from '@uniswap/sdk-core' import useNativeCurrency from 'lib/hooks/useNativeCurrency' -import { getAddress } from 'utils/getAddress' -import { isEnoughAmount } from 'utils/isEnoughAmount' import { useBalancesAndAllowances } from './useBalancesAndAllowances' import { useCurrencyBalances } from './useCurrencyBalance' @@ -26,12 +25,19 @@ export interface UseEnoughBalanceParams { checkAllowanceAddress?: string } +export type UseEnoughBalanceAndAllowanceResult = { + enoughBalance: boolean | undefined + enoughAllowance: boolean | undefined +} + +const DEFAULT_BALANCE_AND_ALLOWANCE = { enoughBalance: undefined, enoughAllowance: undefined } + /** * Check if the account has enough balance and optionally allowance - * @param params Parameters to check balance and optionally the allowance - * @returns true if the account has enough balance (and allowance if it applies) + * @param params UseEnoughBalanceParams to check balance and optionally the allowance + * @returns UseEnoughBalanceAndAllowanceResult */ -export function useEnoughBalanceAndAllowance(params: UseEnoughBalanceParams): boolean | undefined { +export function useEnoughBalanceAndAllowance(params: UseEnoughBalanceParams): UseEnoughBalanceAndAllowanceResult { const { account, amount, checkAllowanceAddress } = params const isNativeCurrency = amount?.currency.isNative const token = amount?.currency.wrapped @@ -75,11 +81,11 @@ export interface EnoughBalanceParams extends Omit + + + ), + importList: ( + + + + ), + loadedLists: ( + + + + ), +} + +export default Fixtures diff --git a/apps/cowswap-frontend/src/modules/tokensList/containers/ManageLists/index.tsx b/apps/cowswap-frontend/src/modules/tokensList/containers/ManageLists/index.tsx new file mode 100644 index 0000000000..2aa322a3d6 --- /dev/null +++ b/apps/cowswap-frontend/src/modules/tokensList/containers/ManageLists/index.tsx @@ -0,0 +1,56 @@ +import * as styledEl from './styled' + +import { PrimaryInput, PrimaryInputBox } from '../../pure/commonElements' +import { ImportTokenListItem } from '../../pure/ImportTokenListItem' +import { LoadedTokenListItem } from '../../pure/LoadedTokenListItem' +import { TokenListItem } from '../../pure/TokenListItem' +import { TokenList } from '../../types' + +export interface ManageListsProps { + lists: TokenList[] + loadedLists?: TokenList[] + listsToImport?: TokenList[] +} + +export function ManageLists(props: ManageListsProps) { + const { lists, loadedLists, listsToImport } = props + + const viewList = (id: string) => { + console.log('TODO viewList', id) + } + + const removeList = (id: string) => { + console.log('TODO removeList', id) + } + + const importList = (list: TokenList) => { + console.log('TODO importList', list.id) + } + + return ( + + + + + {!!loadedLists?.length && ( + + {loadedLists.map((list) => ( + + ))} + + )} + {!!listsToImport?.length && ( + + {listsToImport.map((list) => ( + + ))} + + )} + + {lists.map((list) => ( + + ))} + + + ) +} diff --git a/apps/cowswap-frontend/src/modules/tokensList/containers/ManageLists/styled.ts b/apps/cowswap-frontend/src/modules/tokensList/containers/ManageLists/styled.ts new file mode 100644 index 0000000000..f84c70adc6 --- /dev/null +++ b/apps/cowswap-frontend/src/modules/tokensList/containers/ManageLists/styled.ts @@ -0,0 +1,16 @@ +import styled from 'styled-components/macro' + +import { UI } from 'common/constants/theme' + +export const Wrapper = styled.div` + display: block; + width: 100%; +` + +export const ListsContainer = styled.div` + padding-bottom: 20px; +` + +export const ImportListsContainer = styled.div` + border-bottom: 1px solid var(${UI.COLOR_BORDER}); +` diff --git a/apps/cowswap-frontend/src/modules/tokensList/containers/ManageListsAndTokens/index.cosmos.tsx b/apps/cowswap-frontend/src/modules/tokensList/containers/ManageListsAndTokens/index.cosmos.tsx new file mode 100644 index 0000000000..7df1d8115c --- /dev/null +++ b/apps/cowswap-frontend/src/modules/tokensList/containers/ManageListsAndTokens/index.cosmos.tsx @@ -0,0 +1,19 @@ +import styled from 'styled-components/macro' + +import { customTokensMock, listsMock } from '../../mocks' + +import { ManageListsAndTokens } from './index' + +const Wrapper = styled.div` + width: 450px; +` + +const Fixtures = { + default: ( + + + + ), +} + +export default Fixtures diff --git a/apps/cowswap-frontend/src/modules/tokensList/containers/ManageListsAndTokens/index.tsx b/apps/cowswap-frontend/src/modules/tokensList/containers/ManageListsAndTokens/index.tsx new file mode 100644 index 0000000000..dc8d6234b7 --- /dev/null +++ b/apps/cowswap-frontend/src/modules/tokensList/containers/ManageListsAndTokens/index.tsx @@ -0,0 +1,44 @@ +import { useState } from 'react' + +import * as styledEl from './styled' + +import { ModalHeader } from '../../pure/ModalHeader' +import { TokenList, TokenWithLogo } from '../../types' +import { ManageLists } from '../ManageLists' +import { ManageTokens } from '../ManageTokens' + +export interface ManageListsAndTokensProps { + lists: TokenList[] + customTokens: TokenWithLogo[] +} + +export function ManageListsAndTokens(props: ManageListsAndTokensProps) { + const { lists, customTokens } = props + + const [currentTab, setCurrentTab] = useState<'tokens' | 'lists'>('lists') + + const onBack = () => { + console.log('TODO onBack') + } + + const onClose = () => { + console.log('TODO onClose') + } + + return ( + + + Manage + + + setCurrentTab('lists')}> + Lists + + setCurrentTab('tokens')}> + Tokens + + + {currentTab === 'lists' ? : } + + ) +} diff --git a/apps/cowswap-frontend/src/modules/tokensList/containers/ManageListsAndTokens/styled.ts b/apps/cowswap-frontend/src/modules/tokensList/containers/ManageListsAndTokens/styled.ts new file mode 100644 index 0000000000..bc39147ac1 --- /dev/null +++ b/apps/cowswap-frontend/src/modules/tokensList/containers/ManageListsAndTokens/styled.ts @@ -0,0 +1,37 @@ +import styled from 'styled-components/macro' + +import { UI } from 'common/constants/theme' + +import { blankButtonMixin } from '../../pure/commonElements' + +export const Wrapper = styled.div` + display: block; + width: 100%; + background: var(${UI.COLOR_CONTAINER_BG_01}); + border-radius: 20px; +` + +export const TabsContainer = styled.div` + display: flex; + flex-direction: row; + flex-shrink: 0; + margin-top: 10px; + + > button { + width: 50%; + } +` + +export const Tab = styled.button<{ active$: boolean }>` + ${blankButtonMixin}; + + color: var(${UI.COLOR_TEXT1}); + opacity: ${({ active$ }) => (active$ ? 1 : 0.5)}; + padding: 10px; + font-size: 16px; + font-weight: 600; + + &:hover { + color: var(${UI.COLOR_TEXT2}); + } +` diff --git a/apps/cowswap-frontend/src/modules/tokensList/containers/ManageTokens/index.tsx b/apps/cowswap-frontend/src/modules/tokensList/containers/ManageTokens/index.tsx new file mode 100644 index 0000000000..c35b48b186 --- /dev/null +++ b/apps/cowswap-frontend/src/modules/tokensList/containers/ManageTokens/index.tsx @@ -0,0 +1,67 @@ +import { ExplorerDataType, getExplorerLink } from '@cowprotocol/common-utils' +import { TokenSymbol } from '@cowprotocol/ui' + +import { ExternalLink, Trash } from 'react-feather' + +import * as styledEl from './styled' + +import { PrimaryInput, PrimaryInputBox } from '../../pure/commonElements' +import { TokenLogo } from '../../pure/TokenLogo' +import { TokenWithLogo } from '../../types' + +export interface ManageTokensProps { + tokens: TokenWithLogo[] +} + +export function ManageTokens(props: ManageTokensProps) { + const { tokens } = props + + const clearAll = () => { + console.log('TODO clearAll') + } + + const removeToken = (token: TokenWithLogo) => { + console.log('TODO removeToken', token.symbol) + } + + return ( +

+ + + +
+ + {tokens.length} Custom Tokens + Clear all + +
+ {tokens.map((token) => { + return ( + + + + + +
+ removeToken(token)}> + + + + + + + +
+
+ ) + })} +
+ Tip: Custom tokens are stored locally in your browser +
+
+ ) +} diff --git a/apps/cowswap-frontend/src/modules/tokensList/containers/ManageTokens/styled.ts b/apps/cowswap-frontend/src/modules/tokensList/containers/ManageTokens/styled.ts new file mode 100644 index 0000000000..6586717106 --- /dev/null +++ b/apps/cowswap-frontend/src/modules/tokensList/containers/ManageTokens/styled.ts @@ -0,0 +1,54 @@ +import styled from 'styled-components/macro' + +import { UI } from 'common/constants/theme' + +import { blankButtonMixin } from '../../pure/commonElements' + +const RowBox = styled.div` + display: flex; + flex-direction: row; + justify-content: space-between; + align-items: center; +` + +export const Header = styled(RowBox)` + padding: 20px; +` + +export const Title = styled.div` + font-weight: 600; + opacity: 0.65; +` + +export const LinkButton = styled.button` + ${blankButtonMixin}; + + font-size: 16px; + font-weight: 500; + color: var(${UI.COLOR_LINK}); + margin-left: 10px; + + &:hover { + opacity: 0.8; + } +` + +export const TokenItem = styled(RowBox)` + padding: 0 20px; + margin-bottom: 20px; +` + +export const TokenInfo = styled(RowBox)` + gap: 10px; + font-weight: 600; +` + +export const TipText = styled.div` + font-size: 13px; + font-weight: 500; + color: var(${UI.COLOR_LINK}); + text-align: center; + padding: 20px 0; + border-top: 1px solid var(${UI.COLOR_GREY}); + margin-top: 20px; +` diff --git a/apps/cowswap-frontend/src/modules/tokensList/containers/SelectTokenModal/index.cosmos.tsx b/apps/cowswap-frontend/src/modules/tokensList/containers/SelectTokenModal/index.cosmos.tsx new file mode 100644 index 0000000000..651c415fb3 --- /dev/null +++ b/apps/cowswap-frontend/src/modules/tokensList/containers/SelectTokenModal/index.cosmos.tsx @@ -0,0 +1,61 @@ +import { getRandomInt } from '@cowprotocol/common-utils' +import { CurrencyAmount } from '@uniswap/sdk-core' +import { Currency } from '@uniswap/sdk-core' + +import styled from 'styled-components/macro' + +import { allTokensMock, favouriteTokensMock } from '../../mocks' + +import { SelectTokenModal } from './index' + +const Wrapper = styled.div` + width: 450px; +` + +const selectedToken = favouriteTokensMock[0] + +const balances = allTokensMock.reduce<{ [key: string]: CurrencyAmount }>((acc, token) => { + acc[token.address.toLowerCase()] = CurrencyAmount.fromRawAmount( + token, + getRandomInt(20_000, 120_000_000) * 10 ** token.decimals + ) + + return acc +}, {}) + +const defaultProps = { + selectedToken, + balances, + allTokens: allTokensMock, + favouriteTokens: favouriteTokensMock, +} + +const Fixtures = { + default: ( + + + + ), + importByAddress: ( + + + + ), + NoTokenFound: ( + + + + ), + searchFromInactiveLists: ( + + + + ), + searchFromExternalSources: ( + + + + ), +} + +export default Fixtures diff --git a/apps/cowswap-frontend/src/modules/tokensList/containers/SelectTokenModal/index.tsx b/apps/cowswap-frontend/src/modules/tokensList/containers/SelectTokenModal/index.tsx new file mode 100644 index 0000000000..92defb25f7 --- /dev/null +++ b/apps/cowswap-frontend/src/modules/tokensList/containers/SelectTokenModal/index.tsx @@ -0,0 +1,147 @@ +import { useEffect, useMemo, useState } from 'react' + +import { useDebounce, useNetworkName } from '@cowprotocol/common-hooks' +import { Currency, CurrencyAmount } from '@uniswap/sdk-core' + +import { Edit, X } from 'react-feather' + +import { searchToken, TokenSearchSource } from './searchToken' +import * as styledEl from './styled' + +import { AllTokensList } from '../../pure/AllTokensList' +import { IconButton } from '../../pure/commonElements' +import { FavouriteTokensList } from '../../pure/FavouriteTokensList' +import { ImportTokenItem } from '../../pure/ImportTokenItem' +import { TokenSourceTitle } from '../../pure/TokenSourceTitle' +import { TokenWithLogo } from '../../types' +export interface SelectTokenModalProps { + allTokens: TokenWithLogo[] + favouriteTokens: TokenWithLogo[] + balances: { [key: string]: CurrencyAmount } + selectedToken?: TokenWithLogo + defaultInputValue?: string +} + +export function SelectTokenModal(props: SelectTokenModalProps) { + const { defaultInputValue = '', favouriteTokens, allTokens, selectedToken, balances } = props + + const networkName = useNetworkName() + + const [isSearchInProgress, setIsSearchInProgress] = useState(false) + const [inputValue, setInputValue] = useState(defaultInputValue) + const debouncedInputValue = useDebounce(inputValue, 500) + + const [tokensFromBlockChain, setTokensFromBlockChain] = useState([]) + const [tokensFromInactiveLists, setTokensFromInactiveLists] = useState([]) + const [tokensFromExternal, setTokensFromExternal] = useState([]) + + const importToken = (token: TokenWithLogo) => { + console.log('TODO: import token', token) + } + + const isTokenNotFound = useMemo(() => { + if (isSearchInProgress || !debouncedInputValue) return false + + return tokensFromExternal.length === 0 && tokensFromBlockChain.length === 0 && tokensFromInactiveLists.length === 0 + }, [debouncedInputValue, isSearchInProgress, tokensFromBlockChain, tokensFromInactiveLists, tokensFromExternal]) + + useEffect(() => { + if (!debouncedInputValue) return + + setIsSearchInProgress(true) + setTokensFromBlockChain([]) + setTokensFromInactiveLists([]) + setTokensFromExternal([]) + + searchToken(debouncedInputValue) + .then((result) => { + if (!result) { + return + } + + const { source, tokens } = result + + if (source === TokenSearchSource.Blockchain) { + setTokensFromBlockChain(tokens) + return + } + if (source === TokenSearchSource.InactiveList) { + setTokensFromInactiveLists(tokens) + return + } + if (source === TokenSearchSource.External) { + setTokensFromExternal(tokens) + return + } + }) + .finally(() => { + setIsSearchInProgress(false) + }) + }, [debouncedInputValue]) + + return ( + + +

Select a token

+ + + +
+ + setInputValue(e.target.value)} + type="text" + placeholder="Search name or past address" + /> + + + + + {isTokenNotFound && ( + No tokens found for this name in {networkName} + )} + {tokensFromBlockChain.length > 0 && ( +
+ {tokensFromBlockChain.map((token) => { + return + })} +
+ )} + {tokensFromInactiveLists.length > 0 && ( +
+ + Expanded results from inactive Token Lists + +
+ {tokensFromInactiveLists.map((token) => { + return + })} +
+
+ )} + {tokensFromExternal.length > 0 && ( +
+ + Additional Results from External Sources + +
+ {tokensFromExternal.map((token) => { + return + })} +
+
+ )} + {!debouncedInputValue && ( +
+ +
+ )} +
+ + Manage Token Lists + +
+
+ ) +} diff --git a/apps/cowswap-frontend/src/modules/tokensList/containers/SelectTokenModal/mocks.ts b/apps/cowswap-frontend/src/modules/tokensList/containers/SelectTokenModal/mocks.ts new file mode 100644 index 0000000000..77ed5e8e8e --- /dev/null +++ b/apps/cowswap-frontend/src/modules/tokensList/containers/SelectTokenModal/mocks.ts @@ -0,0 +1,77 @@ +import { TokenWithLogo } from '../../types' + +export const allTokensMock: TokenWithLogo[] = [ + { + name: 'Gnosis', + chainId: 5, + symbol: 'GNO', + decimals: 18, + address: '0x02abbdbaaa7b1bb64b5c878f7ac17f8dda169532', + logoURI: + 'https://raw.githubusercontent.com/trustwallet/assets/master/blockchains/ethereum/assets/0x6810e776880C02933D47DB1b9fc05908e5386b96/logo.png', + }, + { + name: 'Basic Attention Token', + chainId: 5, + symbol: 'BAT', + decimals: 18, + address: '0x70cBa46d2e933030E2f274AE58c951C800548AeF', + logoURI: + 'https://raw.githubusercontent.com/trustwallet/assets/master/blockchains/ethereum/assets/0x0D8775F648430679A709E98d2b0Cb6250d2887EF/logo.png', + }, + { + name: 'CoW Protocol Token', + chainId: 5, + symbol: 'COW', + decimals: 18, + address: '0x91056D4A53E1faa1A84306D4deAEc71085394bC8', + logoURI: 'https://gnosis.mypinata.cloud/ipfs/Qme9B6jRpGtZsRFcPjHvA5T4ugFuL4c3SzWfxyMPa59AMo', + }, + { + name: 'USD Coin', + chainId: 5, + symbol: 'USDC', + decimals: 6, + address: '0xD87Ba7A50B2E7E660f678A895E4B72E7CB4CCd9C', + logoURI: + 'https://raw.githubusercontent.com/trustwallet/assets/master/blockchains/ethereum/assets/0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48/logo.png', + }, + { + name: 'DAI', + chainId: 5, + symbol: 'DAI', + decimals: 18, + address: '0xdc31Ee1784292379Fbb2964b3B9C4124D8F89C60', + logoURI: + 'https://raw.githubusercontent.com/trustwallet/assets/master/blockchains/ethereum/assets/0x6B175474E89094C44Da98b954EedeAC495271d0F/logo.png', + }, + { + name: '0x', + chainId: 5, + symbol: 'ZRX', + decimals: 18, + address: '0xe4E81Fa6B16327D4B78CFEB83AAdE04bA7075165', + logoURI: + 'https://raw.githubusercontent.com/trustwallet/assets/master/blockchains/ethereum/assets/0xE41d2489571d322189246DaFA5ebDe1F4699F498/logo.png', + }, +].map((item) => new TokenWithLogo(item.logoURI, item.chainId, item.address, item.decimals, item.symbol, item.name)) + +export const favouriteTokensMock: TokenWithLogo[] = [ + { + name: 'Basic Attention Token', + chainId: 5, + symbol: 'BAT', + decimals: 18, + address: '0x70cBa46d2e933030E2f274AE58c951C800548AeF', + logoURI: + 'https://raw.githubusercontent.com/trustwallet/assets/master/blockchains/ethereum/assets/0x0D8775F648430679A709E98d2b0Cb6250d2887EF/logo.png', + }, + { + name: 'Polymath Network', + chainId: 5, + symbol: 'POLY', + decimals: 18, + address: '0x9e32c0EfF886B6Ccae99350Fd5e7002dCED55F15', + logoURI: 'https://assets.coingecko.com/coins/images/2784/thumb/inKkF01.png?1605007034', + }, +].map((item) => new TokenWithLogo(item.logoURI, item.chainId, item.address, item.decimals, item.symbol, item.name)) diff --git a/apps/cowswap-frontend/src/modules/tokensList/containers/SelectTokenModal/searchToken.ts b/apps/cowswap-frontend/src/modules/tokensList/containers/SelectTokenModal/searchToken.ts new file mode 100644 index 0000000000..04623a4139 --- /dev/null +++ b/apps/cowswap-frontend/src/modules/tokensList/containers/SelectTokenModal/searchToken.ts @@ -0,0 +1,55 @@ +import { TokenWithLogo } from '../../types' + +export enum TokenSearchSource { + Blockchain = 'Blockchain', + External = 'External', + InactiveList = 'InactiveList', +} + +type TokenSearchResult = { + source: TokenSearchSource + tokens: TokenWithLogo[] +} + +// TODO: implement search +export async function searchToken(input: string): Promise { + if (input === '0x252d98fab648203aa33310721bbbddfa8f1b6587') { + return { + source: TokenSearchSource.Blockchain, + tokens: [new TokenWithLogo(undefined, 5, '0x252d98fab648203aa33310721bbbddfa8f1b6587', 18, 'GSUc', 'GSU Coin')], + } + } + if (input === 'cDAI') { + return { + source: TokenSearchSource.InactiveList, + tokens: [ + new TokenWithLogo(undefined, 5, '0x822397d9a55d0fefd20F5c4bCaB33C5F65bd28Eb', 6, 'cDAI', 'Compound DAI'), + ], + } + } + if (input === 'Coo') { + return { + source: TokenSearchSource.External, + tokens: [ + new TokenWithLogo( + 'https://etherscan.io/token/images/indexcoop_new_32.png', + 5, + '0x0954906da0Bf32d5479e25f46056d22f08464cab', + 18, + 'INDEX', + 'Index DAI' + ), + new TokenWithLogo( + 'https://etherscan.io/token/images/ETH2x-FLI_32.png', + 5, + '0xAa6E8127831c9DE45ae56bB1b0d4D4Da6e5665BD', + 18, + 'ETH2x-FLI', + 'ETH 2x Flexible Leverage Index' + ), + ], + } + } + + return undefined +} diff --git a/apps/cowswap-frontend/src/modules/tokensList/containers/SelectTokenModal/styled.ts b/apps/cowswap-frontend/src/modules/tokensList/containers/SelectTokenModal/styled.ts new file mode 100644 index 0000000000..dc00bb5fb7 --- /dev/null +++ b/apps/cowswap-frontend/src/modules/tokensList/containers/SelectTokenModal/styled.ts @@ -0,0 +1,81 @@ +import styled from 'styled-components/macro' + +import { UI } from 'common/constants/theme' + +import { blankButtonMixin } from '../../pure/commonElements' + +export const Wrapper = styled.div` + display: flex; + flex-direction: column; + background: var(${UI.COLOR_CONTAINER_BG_01}); + border-radius: 20px; +` + +export const Row = styled.div` + margin: 0 20px 15px 20px; +` + +export const Header = styled.div` + display: flex; + flex-direction: row; + justify-content: space-between; + padding: 20px 20px 0 20px; + margin-bottom: 15px; + + > h3 { + font-size: 16px; + font-weight: 500; + margin: 0; + } +` + +export const SearchInput = styled.input` + width: 100%; + outline: none; + border-radius: 20px; + color: var(${UI.COLOR_TEXT1}); + padding: 16px; + border: 1px solid var(${UI.COLOR_GREY}); + -webkit-appearance: none; + transition: border 100ms; + background: transparent; + + font-size: 18px; + + ::placeholder { + color: var(${UI.COLOR_LINK}); + } + + :focus { + border: 1px solid var(${UI.COLOR_CONTAINER_BG_02}); + outline: none; + } +` + +export const ActionButton = styled.button` + ${blankButtonMixin}; + + display: flex; + width: 100%; + align-items: center; + flex-direction: row; + justify-content: center; + gap: 10px; + cursor: pointer; + padding: 20px 0; + margin: 0; + font-size: 16px; + font-weight: 500; + color: var(${UI.COLOR_TEXT1}); + + &:hover { + opacity: 0.7; + } +` + +export const TokenNotFound = styled.div` + color: var(${UI.COLOR_LINK}); + font-weight: 500; + padding: 10px 0; + text-align: center; +` diff --git a/apps/cowswap-frontend/src/modules/tokensList/mocks.ts b/apps/cowswap-frontend/src/modules/tokensList/mocks.ts new file mode 100644 index 0000000000..016c5e101e --- /dev/null +++ b/apps/cowswap-frontend/src/modules/tokensList/mocks.ts @@ -0,0 +1,130 @@ +import { TokenList, TokenWithLogo } from './types' + +export const allTokensMock: TokenWithLogo[] = [ + { + name: 'Gnosis', + chainId: 5, + symbol: 'GNO', + decimals: 18, + address: '0x02abbdbaaa7b1bb64b5c878f7ac17f8dda169532', + logoURI: + 'https://raw.githubusercontent.com/trustwallet/assets/master/blockchains/ethereum/assets/0x6810e776880C02933D47DB1b9fc05908e5386b96/logo.png', + }, + { + name: 'Basic Attention Token', + chainId: 5, + symbol: 'BAT', + decimals: 18, + address: '0x70cBa46d2e933030E2f274AE58c951C800548AeF', + logoURI: + 'https://raw.githubusercontent.com/trustwallet/assets/master/blockchains/ethereum/assets/0x0D8775F648430679A709E98d2b0Cb6250d2887EF/logo.png', + }, + { + name: 'CoW Protocol Token', + chainId: 5, + symbol: 'COW', + decimals: 18, + address: '0x91056D4A53E1faa1A84306D4deAEc71085394bC8', + logoURI: 'https://gnosis.mypinata.cloud/ipfs/Qme9B6jRpGtZsRFcPjHvA5T4ugFuL4c3SzWfxyMPa59AMo', + }, + { + name: 'USD Coin', + chainId: 5, + symbol: 'USDC', + decimals: 6, + address: '0xD87Ba7A50B2E7E660f678A895E4B72E7CB4CCd9C', + logoURI: + 'https://raw.githubusercontent.com/trustwallet/assets/master/blockchains/ethereum/assets/0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48/logo.png', + }, + { + name: 'DAI', + chainId: 5, + symbol: 'DAI', + decimals: 18, + address: '0xdc31Ee1784292379Fbb2964b3B9C4124D8F89C60', + logoURI: + 'https://raw.githubusercontent.com/trustwallet/assets/master/blockchains/ethereum/assets/0x6B175474E89094C44Da98b954EedeAC495271d0F/logo.png', + }, + { + name: '0x', + chainId: 5, + symbol: 'ZRX', + decimals: 18, + address: '0xe4E81Fa6B16327D4B78CFEB83AAdE04bA7075165', + logoURI: + 'https://raw.githubusercontent.com/trustwallet/assets/master/blockchains/ethereum/assets/0xE41d2489571d322189246DaFA5ebDe1F4699F498/logo.png', + }, +].map((item) => new TokenWithLogo(item.logoURI, item.chainId, item.address, item.decimals, item.symbol, item.name)) + +export const favouriteTokensMock: TokenWithLogo[] = [ + { + name: 'Basic Attention Token', + chainId: 5, + symbol: 'BAT', + decimals: 18, + address: '0x70cBa46d2e933030E2f274AE58c951C800548AeF', + logoURI: + 'https://raw.githubusercontent.com/trustwallet/assets/master/blockchains/ethereum/assets/0x0D8775F648430679A709E98d2b0Cb6250d2887EF/logo.png', + }, + { + name: 'Polymath Network', + chainId: 5, + symbol: 'POLY', + decimals: 18, + address: '0x9e32c0EfF886B6Ccae99350Fd5e7002dCED55F15', + logoURI: 'https://assets.coingecko.com/coins/images/2784/thumb/inKkF01.png?1605007034', + }, +].map((item) => new TokenWithLogo(item.logoURI, item.chainId, item.address, item.decimals, item.symbol, item.name)) + +export const customTokensMock: TokenWithLogo[] = [ + { + name: 'Tether USD', + chainId: 5, + symbol: 'USDT', + decimals: 6, + address: '0x7b77F953e703E80CD97F6911385c0b1ceabC96Bc', + logoURI: undefined, + }, + { + name: 'Euro Coin', + chainId: 5, + symbol: 'EUROC', + decimals: 6, + address: '0x1aBaEA1f7C830bD89Acc67eC4af516284b1bC33c', + logoURI: + 'https://raw.githubusercontent.com/Uniswap/assets/master/blockchains/ethereum/assets/0x1aBaEA1f7C830bD89Acc67eC4af516284b1bC33c/logo.png', + }, +].map((item) => new TokenWithLogo(item.logoURI, item.chainId, item.address, item.decimals, item.symbol, item.name)) + +export const listsMock: TokenList[] = [ + { + id: '1', + name: 'CowSwap Goerli', + url: 'https://tokenlists.org/token-list?url=https://raw.githubusercontent.com/cowprotocol/cowswap/develop/apps/cowswap-frontend/src/tokens/goerli-token-list.json', + logoUrl: 'https://gnosis.mypinata.cloud/ipfs/Qme9B6jRpGtZsRFcPjHvA5T4ugFuL4c3SzWfxyMPa59AMo', + tokensCount: 7, + enabled: true, + version: 'v0.0.0', + }, + { + id: '2', + name: 'Compound', + url: 'https://tokenlists.org/token-list?url=https://raw.githubusercontent.com/compound-finance/token-list/master/compound.tokenlist.json', + logoUrl: 'https://raw.githubusercontent.com/compound-finance/token-list/master/assets/compound-interface.svg', + tokensCount: 16, + enabled: false, + version: 'v0.2.1', + }, +] + +export const importListsMock: TokenList[] = [ + { + id: '4', + name: 'CoW Swap', + url: 'https://files.cow.fi/tokens/CowSwap.json', + logoUrl: 'https://raw.githubusercontent.com/cowprotocol/token-lists/main/src/public/images/list-logo.png', + tokensCount: 113, + enabled: true, + version: 'v0.0.0', + }, +] diff --git a/apps/cowswap-frontend/src/modules/tokensList/pure/AllTokensList/index.tsx b/apps/cowswap-frontend/src/modules/tokensList/pure/AllTokensList/index.tsx new file mode 100644 index 0000000000..a687a0b832 --- /dev/null +++ b/apps/cowswap-frontend/src/modules/tokensList/pure/AllTokensList/index.tsx @@ -0,0 +1,34 @@ +import { TokenAmount } from '@cowprotocol/ui' +import { Currency, CurrencyAmount } from '@uniswap/sdk-core' + +import * as styledEl from './styled' + +import { TokenWithLogo } from '../../types' +import { TokenInfo } from '../TokenInfo' + +export interface AllTokensListProps { + tokens: TokenWithLogo[] + selectedToken?: TokenWithLogo + balances: { [key: string]: CurrencyAmount } +} + +export function AllTokensList(props: AllTokensListProps) { + const { tokens, selectedToken, balances } = props + + return ( + + {tokens.map((token) => { + const isTokenSelected = token.address.toLowerCase() === selectedToken?.address.toLowerCase() + + return ( + + + + + + + ) + })} + + ) +} diff --git a/apps/cowswap-frontend/src/modules/tokensList/pure/AllTokensList/styled.ts b/apps/cowswap-frontend/src/modules/tokensList/pure/AllTokensList/styled.ts new file mode 100644 index 0000000000..27b207ebf1 --- /dev/null +++ b/apps/cowswap-frontend/src/modules/tokensList/pure/AllTokensList/styled.ts @@ -0,0 +1,33 @@ +import styled from 'styled-components/macro' + +import { UI } from 'common/constants/theme' + +export const Wrapper = styled.div` + border-top: 1px solid var(${UI.COLOR_BORDER}); + border-bottom: 1px solid var(${UI.COLOR_BORDER}); +` + +export const TokenItem = styled.button` + display: flex; + flex-direction: row; + justify-content: space-between; + align-items: center; + width: 100%; + background: none; + border: 0; + outline: none; + color: var(${UI.COLOR_TEXT1}); + cursor: pointer; + font-size: 16px; + padding: 10px 20px; + margin-bottom: 10px; + opacity: ${({ disabled }) => (disabled ? 0.5 : 1)}; + + &:last-child { + margin-bottom: 0; + } + + &:hover { + background-color: ${({ disabled }) => !disabled && `var(${UI.COLOR_GREY})`}; + } +` diff --git a/apps/cowswap-frontend/src/modules/tokensList/pure/FavouriteTokensList/index.tsx b/apps/cowswap-frontend/src/modules/tokensList/pure/FavouriteTokensList/index.tsx new file mode 100644 index 0000000000..cecb000792 --- /dev/null +++ b/apps/cowswap-frontend/src/modules/tokensList/pure/FavouriteTokensList/index.tsx @@ -0,0 +1,37 @@ +import { TokenSymbol } from '@cowprotocol/ui' + +import { InfoIcon } from 'legacy/components/InfoIcon' + +import * as styledEl from './styled' + +import { TokenWithLogo } from '../../types' + +export interface FavouriteTokensListProps { + tokens: TokenWithLogo[] + selectedToken?: TokenWithLogo +} + +export function FavouriteTokensList(props: FavouriteTokensListProps) { + const { tokens, selectedToken } = props + + return ( +
+ +

Favourite tokens

+ +
+ + {tokens.map((token) => { + const isTokenSelected = token.address.toLowerCase() === selectedToken?.address.toLowerCase() + + return ( + + {token.name} + + + ) + })} + +
+ ) +} diff --git a/apps/cowswap-frontend/src/modules/tokensList/pure/FavouriteTokensList/styled.ts b/apps/cowswap-frontend/src/modules/tokensList/pure/FavouriteTokensList/styled.ts new file mode 100644 index 0000000000..614464bcf1 --- /dev/null +++ b/apps/cowswap-frontend/src/modules/tokensList/pure/FavouriteTokensList/styled.ts @@ -0,0 +1,53 @@ +import styled from 'styled-components/macro' + +import { UI } from 'common/constants/theme' + +export const Header = styled.div` + display: flex; + gap: 5px; + flex-direction: row; + align-items: center; + + > h4 { + font-size: 14px; + font-weight: 500; + margin: 0; + } +` + +export const TokensList = styled.div` + margin: 10px 0; +` + +export const TokensItem = styled.button` + display: inline-flex; + flex-direction: row; + align-items: center; + gap: 6px; + justify-content: center; + min-width: 140px; + margin: 5px 5px 5px 0; + background: none; + outline: none; + padding: 6px 0; + border-radius: 10px; + color: var(${UI.COLOR_TEXT1}); + border: 1px solid var(${UI.COLOR_GREY}); + font-weight: 500; + font-size: 16px; + cursor: ${({ disabled }) => (disabled ? '' : 'pointer')}; + background-color: ${({ theme, disabled }) => disabled && theme.bg3}; + opacity: ${({ disabled }) => (disabled ? 0.5 : 1)}; + + :hover { + background-color: ${({ theme, disabled }) => !disabled && theme.bg4}; + } + + > img { + --size: 24px; + width: var(--size); + height: var(--size); + border-radius: 50%; + background: var(${UI.COLOR_LIGHT_BLUE}); + } +` diff --git a/apps/cowswap-frontend/src/modules/tokensList/pure/ImportListModal/index.cosmos.tsx b/apps/cowswap-frontend/src/modules/tokensList/pure/ImportListModal/index.cosmos.tsx new file mode 100644 index 0000000000..c12de15cad --- /dev/null +++ b/apps/cowswap-frontend/src/modules/tokensList/pure/ImportListModal/index.cosmos.tsx @@ -0,0 +1,24 @@ +import styled from 'styled-components/macro' + +import { importListsMock } from '../../mocks' + +import { ImportListModal } from './index' + +const Wrapper = styled.div` + width: 450px; +` + +const Fixtures = { + default: ( + + console.log('onBack')} + onClose={() => console.log('onClose')} + onImport={() => console.log('onImport')} + /> + + ), +} + +export default Fixtures diff --git a/apps/cowswap-frontend/src/modules/tokensList/pure/ImportListModal/index.tsx b/apps/cowswap-frontend/src/modules/tokensList/pure/ImportListModal/index.tsx new file mode 100644 index 0000000000..7be3afa732 --- /dev/null +++ b/apps/cowswap-frontend/src/modules/tokensList/pure/ImportListModal/index.tsx @@ -0,0 +1,65 @@ +import { useState } from 'react' + +import { ButtonPrimary } from '@cowprotocol/ui' + +import { AlertTriangle } from 'react-feather' + +import * as styledEl from './styled' + +import { TokenList } from '../../types' +import { ModalHeader } from '../ModalHeader' +import { TokenLogo } from '../TokenLogo' + +export interface ImportListModalProps { + list: TokenList + onImport(): void + onBack(): void + onClose(): void +} + +export function ImportListModal(props: ImportListModalProps) { + const { list, onBack, onClose, onImport } = props + + const [isAccepted, setIsAccepted] = useState(false) + + return ( + + + Import List + + + +
+ + {list.name} · {list.tokensCount} tokens + + + {list.url} + +
+
+ + +

Import at your own risk

+

+ By adding this list you are implicitly trusting that the data is correct. Anyone can create a list, including + creating fake versions of existing lists and lists that claim to represent projects that do not have one. +

+

+ If you purchase a token from this list, you may not be able to sell it back. +

+
+ + setIsAccepted((state) => !state)} /> + I understand + +
+
+ + + Import + + +
+ ) +} diff --git a/apps/cowswap-frontend/src/modules/tokensList/pure/ImportListModal/styled.ts b/apps/cowswap-frontend/src/modules/tokensList/pure/ImportListModal/styled.ts new file mode 100644 index 0000000000..d5d4221900 --- /dev/null +++ b/apps/cowswap-frontend/src/modules/tokensList/pure/ImportListModal/styled.ts @@ -0,0 +1,50 @@ +import styled from 'styled-components/macro' + +import { UI } from 'common/constants/theme' + +export const Wrapper = styled.div` + display: block; + width: 100%; + background: var(${UI.COLOR_CONTAINER_BG_01}); + border-radius: 20px; +` + +export const Contents = styled.div` + display: flex; + flex-direction: column; + align-items: center; + text-align: center; + gap: 5px; + padding: 20px; + margin: 20px; + border-radius: 20px; + color: var(${UI.COLOR_RED}); + background: var(${UI.COLOR_DANGER_BG}); +` + +export const ActionButtonWrapper = styled.div` + padding: 0 20px 20px 20px; +` + +export const AcceptanceBox = styled.label` + display: flex; + gap: 6px; + cursor: pointer; +` + +export const ListInfo = styled.div` + display: flex; + flex-direction: row; + margin: 20px; + gap: 20px; + padding: 0 10px; +` + +export const ListTitle = styled.div` + font-weight: 600; + font-size: 18px; +` + +export const ListLink = styled.a` + font-size: 14px; +` diff --git a/apps/cowswap-frontend/src/modules/tokensList/pure/ImportTokenItem/index.tsx b/apps/cowswap-frontend/src/modules/tokensList/pure/ImportTokenItem/index.tsx new file mode 100644 index 0000000000..c9a158eaa5 --- /dev/null +++ b/apps/cowswap-frontend/src/modules/tokensList/pure/ImportTokenItem/index.tsx @@ -0,0 +1,25 @@ +import * as styledEl from './styled' + +import { TokenWithLogo } from '../../types' +import { ImportButton } from '../commonElements' +import { TokenInfo } from '../TokenInfo' + +export interface ImportTokenItemProps { + token: TokenWithLogo + importToken(token: TokenWithLogo): void + shadowed?: boolean +} + +export function ImportTokenItem(props: ImportTokenItemProps) { + const { token, importToken, shadowed } = props + return ( + +
+ +
+
+ importToken(token)}>Import +
+
+ ) +} diff --git a/apps/cowswap-frontend/src/modules/tokensList/pure/ImportTokenItem/styled.ts b/apps/cowswap-frontend/src/modules/tokensList/pure/ImportTokenItem/styled.ts new file mode 100644 index 0000000000..446ba08db5 --- /dev/null +++ b/apps/cowswap-frontend/src/modules/tokensList/pure/ImportTokenItem/styled.ts @@ -0,0 +1,13 @@ +import styled from 'styled-components/macro' + +export const Wrapper = styled.div` + display: flex; + flex-direction: row; + justify-content: space-between; + padding: 0 20px; + margin-bottom: 20px; + + &:last-child { + margin-bottom: 0; + } +` diff --git a/apps/cowswap-frontend/src/modules/tokensList/pure/ImportTokenListItem/index.tsx b/apps/cowswap-frontend/src/modules/tokensList/pure/ImportTokenListItem/index.tsx new file mode 100644 index 0000000000..efd6d6b44a --- /dev/null +++ b/apps/cowswap-frontend/src/modules/tokensList/pure/ImportTokenListItem/index.tsx @@ -0,0 +1,23 @@ +import * as styledEl from './styled' + +import { TokenList } from '../../types' +import { ImportButton } from '../commonElements' +import { TokenListInfo } from '../TokenListInfo' + +export interface ImportTokenListItemProps { + list: TokenList + importList(list: TokenList): void +} + +export function ImportTokenListItem(props: ImportTokenListItemProps) { + const { list } = props + + return ( + + +
+ Import +
+
+ ) +} diff --git a/apps/cowswap-frontend/src/modules/tokensList/pure/ImportTokenListItem/styled.ts b/apps/cowswap-frontend/src/modules/tokensList/pure/ImportTokenListItem/styled.ts new file mode 100644 index 0000000000..524b879730 --- /dev/null +++ b/apps/cowswap-frontend/src/modules/tokensList/pure/ImportTokenListItem/styled.ts @@ -0,0 +1,9 @@ +import styled from 'styled-components/macro' + +export const Wrapper = styled.div` + display: flex; + flex-direction: row; + justify-content: space-between; + margin: 20px; + padding: 0 10px; +` diff --git a/apps/cowswap-frontend/src/modules/tokensList/pure/ImportTokenModal/index.cosmos.tsx b/apps/cowswap-frontend/src/modules/tokensList/pure/ImportTokenModal/index.cosmos.tsx new file mode 100644 index 0000000000..75bff5e775 --- /dev/null +++ b/apps/cowswap-frontend/src/modules/tokensList/pure/ImportTokenModal/index.cosmos.tsx @@ -0,0 +1,23 @@ +import styled from 'styled-components/macro' + +import { customTokensMock } from '../../mocks' + +import { ImportTokenModal } from './index' + +const Wrapper = styled.div` + width: 450px; +` + +const Fixtures = { + default: ( + + console.log('onBack')} + onClose={() => console.log('onClose')} + /> + + ), +} + +export default Fixtures diff --git a/apps/cowswap-frontend/src/modules/tokensList/pure/ImportTokenModal/index.tsx b/apps/cowswap-frontend/src/modules/tokensList/pure/ImportTokenModal/index.tsx new file mode 100644 index 0000000000..579ac595be --- /dev/null +++ b/apps/cowswap-frontend/src/modules/tokensList/pure/ImportTokenModal/index.tsx @@ -0,0 +1,51 @@ +import { ExplorerDataType, getExplorerLink } from '@cowprotocol/common-utils' +import { ButtonPrimary } from '@cowprotocol/ui' + +import { AlertCircle } from 'react-feather' + +import * as styledEl from './styled' + +import { TokenWithLogo } from '../../types' +import { ModalHeader } from '../ModalHeader' +import { TokenLogo } from '../TokenLogo' + +export interface ImportTokenModalProps { + token: TokenWithLogo + onBack(): void + onClose(): void +} + +export function ImportTokenModal(props: ImportTokenModalProps) { + const { token, onBack, onClose } = props + + return ( + + + Import token + + + +

+ This token doesn't appear on the active token list(s). Make sure this is the token that you want to trade. +

+ + + + {token.name} + + {token.address} + + + + Unknown Source + + + Import token +
+
+ ) +} diff --git a/apps/cowswap-frontend/src/modules/tokensList/pure/ImportTokenModal/styled.ts b/apps/cowswap-frontend/src/modules/tokensList/pure/ImportTokenModal/styled.ts new file mode 100644 index 0000000000..4f99b6d7f4 --- /dev/null +++ b/apps/cowswap-frontend/src/modules/tokensList/pure/ImportTokenModal/styled.ts @@ -0,0 +1,56 @@ +import { TokenSymbol } from '@cowprotocol/ui' + +import { AlertCircle } from 'react-feather' +import styled from 'styled-components/macro' + +import { UI } from 'common/constants/theme' + +export const Wrapper = styled.div` + display: block; + width: 100%; + background: var(${UI.COLOR_CONTAINER_BG_01}); + border-radius: 20px; +` + +export const Contents = styled.div` + display: flex; + flex-direction: column; + align-items: center; + text-align: center; + gap: 20px; + padding: 20px; +` + +export const AlertIcon = styled(AlertCircle)` + color: var(${UI.COLOR_RED}); + margin-top: 20px; +` + +export const TokenInfo = styled.div` + display: flex; + flex-direction: column; + align-items: center; + text-align: center; + gap: 10px; + font-size: 14px; +` + +export const StyledTokenSymbol = styled(TokenSymbol)` + font-weight: 600; + font-size: 20px; +` + +export const TokenName = styled.div` + color: var(${UI.COLOR_LINK}); +` + +export const UnknownSourceWarning = styled.div` + display: flex; + gap: 8px; + align-items: center; + background: var(${UI.COLOR_DANGER_BG}); + color: var(${UI.COLOR_DANGER_TEXT}); + border-radius: 10px; + font-size: 13px; + padding: 6px 12px; +` diff --git a/apps/cowswap-frontend/src/modules/tokensList/pure/LoadedTokenListItem/index.tsx b/apps/cowswap-frontend/src/modules/tokensList/pure/LoadedTokenListItem/index.tsx new file mode 100644 index 0000000000..714a00b983 --- /dev/null +++ b/apps/cowswap-frontend/src/modules/tokensList/pure/LoadedTokenListItem/index.tsx @@ -0,0 +1,26 @@ +import { CheckCircle } from 'react-feather' + +import * as styledEl from './styled' + +import { TokenList } from '../../types' +import { TokenListInfo } from '../TokenListInfo' + +export interface LoadedTokenListItemProps { + list: TokenList +} + +export function LoadedTokenListItem(props: LoadedTokenListItemProps) { + const { list } = props + + return ( + + +
+ + + Loaded + +
+
+ ) +} diff --git a/apps/cowswap-frontend/src/modules/tokensList/pure/LoadedTokenListItem/styled.ts b/apps/cowswap-frontend/src/modules/tokensList/pure/LoadedTokenListItem/styled.ts new file mode 100644 index 0000000000..5125a5e65b --- /dev/null +++ b/apps/cowswap-frontend/src/modules/tokensList/pure/LoadedTokenListItem/styled.ts @@ -0,0 +1,17 @@ +import styled from 'styled-components/macro' + +export const Wrapper = styled.div` + display: flex; + flex-direction: row; + justify-content: space-between; + align-items: center; + margin: 20px; + padding: 0 10px; +` + +export const LoadedInfo = styled.div` + display: flex; + flex-direction: row; + gap: 10px; + align-items: center; +` diff --git a/apps/cowswap-frontend/src/modules/tokensList/pure/ModalHeader/index.tsx b/apps/cowswap-frontend/src/modules/tokensList/pure/ModalHeader/index.tsx new file mode 100644 index 0000000000..10ef4f5d85 --- /dev/null +++ b/apps/cowswap-frontend/src/modules/tokensList/pure/ModalHeader/index.tsx @@ -0,0 +1,41 @@ +import { ArrowLeft, X } from 'react-feather' +import styled from 'styled-components/macro' + +import { UI } from 'common/constants/theme' + +import { IconButton } from '../commonElements' + +const Header = styled.div` + display: flex; + flex-direction: row; + justify-content: space-between; + font-weight: 500; + font-size: 20px; + padding: 20px; + border-bottom: 1px solid var(${UI.COLOR_BORDER}); +` + +export interface ModalHeaderProps { + children: string + onBack(): void + onClose(): void + className?: string +} + +export function ModalHeader({ children, className, onBack, onClose }: ModalHeaderProps) { + return ( +
+
+ + + +
+
{children}
+
+ + + +
+
+ ) +} diff --git a/apps/cowswap-frontend/src/modules/tokensList/pure/TokenInfo/index.tsx b/apps/cowswap-frontend/src/modules/tokensList/pure/TokenInfo/index.tsx new file mode 100644 index 0000000000..52c40d4936 --- /dev/null +++ b/apps/cowswap-frontend/src/modules/tokensList/pure/TokenInfo/index.tsx @@ -0,0 +1,25 @@ +import { TokenSymbol } from '@cowprotocol/ui' + +import * as styledEl from './styled' + +import { TokenWithLogo } from '../../types' +import { TokenLogo } from '../TokenLogo' + +export interface TokenInfoProps { + token: TokenWithLogo + className?: string +} + +export function TokenInfo(props: TokenInfoProps) { + const { token, className } = props + + return ( + + +
+ + {token.name} +
+
+ ) +} diff --git a/apps/cowswap-frontend/src/modules/tokensList/pure/TokenInfo/styled.ts b/apps/cowswap-frontend/src/modules/tokensList/pure/TokenInfo/styled.ts new file mode 100644 index 0000000000..0c0f1dabe9 --- /dev/null +++ b/apps/cowswap-frontend/src/modules/tokensList/pure/TokenInfo/styled.ts @@ -0,0 +1,17 @@ +import styled from 'styled-components/macro' + +import { UI } from 'common/constants/theme' + +export const Wrapper = styled.div` + display: flex; + flex-direction: row; + text-align: left; + gap: 16px; + font-weight: 500; +` + +export const TokenName = styled.div` + font-size: 12px; + font-weight: 400; + color: var(${UI.COLOR_TEXT2}); +` diff --git a/apps/cowswap-frontend/src/modules/tokensList/pure/TokenListInfo/index.tsx b/apps/cowswap-frontend/src/modules/tokensList/pure/TokenListInfo/index.tsx new file mode 100644 index 0000000000..53ade782b0 --- /dev/null +++ b/apps/cowswap-frontend/src/modules/tokensList/pure/TokenListInfo/index.tsx @@ -0,0 +1,30 @@ +import { ReactNode } from 'react' + +import * as styledEl from './styled' + +import { TokenList } from '../../types' +import { TokenLogo } from '../TokenLogo' + +export interface TokenListItemProps { + list: TokenList + className?: string + children?: ReactNode +} + +export function TokenListInfo(props: TokenListItemProps) { + const { list, children, className } = props + + return ( + +
+ +
+
+ {list.name} + + {list.tokensCount} tokens {children} + +
+
+ ) +} diff --git a/apps/cowswap-frontend/src/modules/tokensList/pure/TokenListInfo/styled.ts b/apps/cowswap-frontend/src/modules/tokensList/pure/TokenListInfo/styled.ts new file mode 100644 index 0000000000..c97f74be3e --- /dev/null +++ b/apps/cowswap-frontend/src/modules/tokensList/pure/TokenListInfo/styled.ts @@ -0,0 +1,21 @@ +import styled from 'styled-components/macro' + +export const ListInfo = styled.div` + display: flex; + flex-direction: row; + justify-content: space-between; + align-items: center; + gap: 10px; + font-size: 12px; +` + +export const ListName = styled.div` + font-size: 16px; + font-weight: 600; + margin-bottom: 5px; +` + +export const TokensInfo = styled.div` + display: flex; + gap: 5px; +` diff --git a/apps/cowswap-frontend/src/modules/tokensList/pure/TokenListItem/index.tsx b/apps/cowswap-frontend/src/modules/tokensList/pure/TokenListItem/index.tsx new file mode 100644 index 0000000000..b7bc926eb4 --- /dev/null +++ b/apps/cowswap-frontend/src/modules/tokensList/pure/TokenListItem/index.tsx @@ -0,0 +1,53 @@ +import { useState } from 'react' + +import { Menu, MenuItem } from '@reach/menu-button' +import { Settings } from 'react-feather' + +import { Toggle } from 'legacy/components/Toggle' + +import * as styledEl from './styled' + +import { TokenList } from '../../types' +import { IconButton } from '../commonElements' +import { TokenListInfo } from '../TokenListInfo' + +export interface TokenListItemProps { + list: TokenList + removeList(id: string): void + viewList(id: string): void +} + +export function TokenListItem(props: TokenListItemProps) { + const { list, removeList, viewList } = props + + // TODO: bind logic + const [isActive, setIsActive] = useState(list.enabled) + + return ( + + + + + + + + + + void 0}> + {list.version} + + viewList(list.id)}> + View List + + removeList(list.id)}> + Remove list + + + + +
+ setIsActive((state) => !state)} /> +
+
+ ) +} diff --git a/apps/cowswap-frontend/src/modules/tokensList/pure/TokenListItem/styled.ts b/apps/cowswap-frontend/src/modules/tokensList/pure/TokenListItem/styled.ts new file mode 100644 index 0000000000..f48bdcec19 --- /dev/null +++ b/apps/cowswap-frontend/src/modules/tokensList/pure/TokenListItem/styled.ts @@ -0,0 +1,46 @@ +import { MenuButton, MenuList } from '@reach/menu-button' +import { transparentize } from 'polished' +import styled from 'styled-components/macro' + +import { UI } from 'common/constants/theme' + +import { blankButtonMixin } from '../commonElements' + +export const Wrapper = styled.div<{ $enabled: boolean }>` + display: flex; + flex-direction: row; + justify-content: space-between; + margin: 20px; + padding: 20px; + border-radius: 20px; + border: 1px solid var(${UI.COLOR_GREY}); + background-color: ${({ $enabled, theme }) => ($enabled ? transparentize(0.8, theme.bg2) : 'transparent')}; +` + +export const SettingsButton = styled(MenuButton)` + ${blankButtonMixin} +` + +export const SettingsContainer = styled(MenuList)` + background: var(${UI.COLOR_CONTAINER_BG_01}); + padding: 10px; + border-radius: 10px; + border: 1px solid var(${UI.COLOR_GREY}); +` + +export const SettingsAction = styled.div` + color: var(${UI.COLOR_LINK}); + cursor: pointer; + padding: 5px; + box-sizing: content-box; + + &:hover { + text-decoration: underline; + } +` + +export const ListVersion = styled.div` + color: var(${UI.COLOR_TEXT1_INACTIVE}); + border-bottom: 1px solid var(${UI.COLOR_GREY}); + padding: 0 5px 10px 5px; +` diff --git a/apps/cowswap-frontend/src/modules/tokensList/pure/TokenLogo/index.tsx b/apps/cowswap-frontend/src/modules/tokensList/pure/TokenLogo/index.tsx new file mode 100644 index 0000000000..4ffc0aed23 --- /dev/null +++ b/apps/cowswap-frontend/src/modules/tokensList/pure/TokenLogo/index.tsx @@ -0,0 +1,38 @@ +import { atom, useAtom } from 'jotai' + +import { Slash } from 'react-feather' +import styled from 'styled-components/macro' + +import { UI } from 'common/constants/theme' + +const invalidUrlsAtom = atom<{ [url: string]: boolean }>({}) + +const TokenLogoWrapper = styled.div` + display: inline-block; + background: var(${UI.COLOR_CONTAINER_BG_01}); + border-radius: 50%; +` + +export interface TokenLogoProps { + logoURI: string | undefined + className?: string + size?: number +} + +export function TokenLogo({ logoURI, className, size = 36 }: TokenLogoProps) { + const [invalidUrls, setInvalidUrls] = useAtom(invalidUrlsAtom) + + const hasError = invalidUrls[logoURI!] + + const onError = () => setInvalidUrls({ ...invalidUrls, [logoURI!]: true }) + + return ( + + {hasError || !logoURI ? ( + + ) : ( + + )} + + ) +} diff --git a/apps/cowswap-frontend/src/modules/tokensList/pure/TokenSourceTitle/index.tsx b/apps/cowswap-frontend/src/modules/tokensList/pure/TokenSourceTitle/index.tsx new file mode 100644 index 0000000000..36d55445ba --- /dev/null +++ b/apps/cowswap-frontend/src/modules/tokensList/pure/TokenSourceTitle/index.tsx @@ -0,0 +1,45 @@ +import TokenListLogo from '@cowprotocol/assets/svg/tokenlist.svg' + +import styled from 'styled-components/macro' + +import { InfoIcon } from 'legacy/components/InfoIcon' + +const Wrapper = styled.div` + display: flex; + justify-content: space-between; + align-items: center; + margin-bottom: 10px; + padding: 0 20px; +` + +const Title = styled.h4` + font-size: 13px; + font-weight: 500; + + > img { + width: 18px; + vertical-align: middle; + margin-right: 6px; + } +` + +export interface TokenSourceTitleProps { + children: string + tooltip: string +} + +export function TokenSourceTitle(props: TokenSourceTitleProps) { + const { children, tooltip } = props + + return ( + + + <img src={TokenListLogo} /> + {children} + +
+ +
+
+ ) +} diff --git a/apps/cowswap-frontend/src/modules/tokensList/pure/commonElements.ts b/apps/cowswap-frontend/src/modules/tokensList/pure/commonElements.ts new file mode 100644 index 0000000000..b8edf20eec --- /dev/null +++ b/apps/cowswap-frontend/src/modules/tokensList/pure/commonElements.ts @@ -0,0 +1,73 @@ +import { transparentize } from 'polished' +import styled, { css } from 'styled-components/macro' + +import { UI } from 'common/constants/theme' + +export const blankButtonMixin = css` + background: none; + padding: 0; + margin: 0; + outline: none; + border: 0; + cursor: pointer; + + &:disabled { + cursor: default; + } +` + +export const PrimaryInputBox = styled.div` + margin: 20px 0 10px 0; + padding: 0 20px 20px 20px; + border-bottom: 1px solid var(${UI.COLOR_GREY}); +` + +export const PrimaryInput = styled.input` + width: 100%; + border: none; + background: var(${UI.COLOR_GREY}); + font-size: 18px; + border-radius: 20px; + padding: 16px; + color: var(${UI.COLOR_TEXT1}); + outline: none; + + ::placeholder { + color: var(${UI.COLOR_TEXT1}); + } + + &:focus { + ::placeholder { + color: ${({ theme }) => transparentize(0.7, theme.text1)}; + } + } +` + +export const IconButton = styled.button` + ${blankButtonMixin} + + > svg { + color: var(${UI.COLOR_TEXT1}); + + &:hover { + color: var(${UI.COLOR_TEXT2}); + } + } +` + +export const ImportButton = styled.button` + ${blankButtonMixin}; + + background-color: var(${UI.COLOR_CONTAINER_BG_02}); + color: var(${UI.COLOR_WHITE}); + font-size: 16px; + font-weight: 600; + padding: 6px 15px; + border-radius: 24px; + cursor: pointer; + transition: background-color 0.2s ease-in-out; + + &:hover { + background-color: var(${UI.COLOR_LINK}); + } +` diff --git a/apps/cowswap-frontend/src/modules/tokensList/state/tokensListAtom.ts b/apps/cowswap-frontend/src/modules/tokensList/state/tokensListAtom.ts index 0abca1bf79..39d2add888 100644 --- a/apps/cowswap-frontend/src/modules/tokensList/state/tokensListAtom.ts +++ b/apps/cowswap-frontend/src/modules/tokensList/state/tokensListAtom.ts @@ -1,21 +1,6 @@ import { atom } from 'jotai' -import { Token } from '@uniswap/sdk-core' - -// It's a hack for useCurrencyLogoURIs(), must be refactored -export class TokenWithLogo extends Token { - constructor( - public logoURI: string | undefined, - chainId: number, - address: string, - decimals: number, - symbol?: string, - name?: string, - bypassChecksum?: boolean - ) { - super(chainId, address, decimals, symbol, name, bypassChecksum) - } -} +import { TokenWithLogo } from '../types' export type TokensByAddress = { [address: string]: TokenWithLogo } diff --git a/apps/cowswap-frontend/src/modules/tokensList/types.ts b/apps/cowswap-frontend/src/modules/tokensList/types.ts new file mode 100644 index 0000000000..77a7608e7a --- /dev/null +++ b/apps/cowswap-frontend/src/modules/tokensList/types.ts @@ -0,0 +1,25 @@ +import { Token } from '@uniswap/sdk-core' + +export class TokenWithLogo extends Token { + constructor( + public logoURI: string | undefined, + chainId: number, + address: string, + decimals: number, + symbol?: string, + name?: string, + bypassChecksum?: boolean + ) { + super(chainId, address, decimals, symbol, name, bypassChecksum) + } +} + +export interface TokenList { + id: string + name: string + logoUrl: string + url: string + enabled: boolean + tokensCount: number + version: string +} diff --git a/apps/cowswap-frontend/src/modules/tokensList/updaters/TokensListUpdater.ts b/apps/cowswap-frontend/src/modules/tokensList/updaters/TokensListUpdater.ts index d9708e316e..2f6aa18f98 100644 --- a/apps/cowswap-frontend/src/modules/tokensList/updaters/TokensListUpdater.ts +++ b/apps/cowswap-frontend/src/modules/tokensList/updaters/TokensListUpdater.ts @@ -3,7 +3,9 @@ import { useEffect, useMemo } from 'react' import { useTokensListWithDefaults } from 'legacy/state/lists/hooks' -import { tokensByAddressAtom, tokensBySymbolAtom, TokenWithLogo } from 'modules/tokensList/state/tokensListAtom' +import { tokensByAddressAtom, tokensBySymbolAtom } from 'modules/tokensList/state/tokensListAtom' + +import { TokenWithLogo } from '../types' /** * This updater protects from redundant recalculations diff --git a/apps/cowswap-frontend/src/modules/tokensList/utils/getTokensByAddress.ts b/apps/cowswap-frontend/src/modules/tokensList/utils/getTokensByAddress.ts index 1cde518e0a..3895274499 100644 --- a/apps/cowswap-frontend/src/modules/tokensList/utils/getTokensByAddress.ts +++ b/apps/cowswap-frontend/src/modules/tokensList/utils/getTokensByAddress.ts @@ -1,10 +1,8 @@ +import { NATIVE_CURRENCY_BUY_TOKEN } from '@cowprotocol/common-const' +import { doesTokenMatchSymbolOrAddress } from '@cowprotocol/common-utils' import { SupportedChainId } from '@cowprotocol/cow-sdk' import { Token } from '@uniswap/sdk-core' -import { NATIVE_CURRENCY_BUY_TOKEN } from 'legacy/constants' - -import { doesTokenMatchSymbolOrAddress } from 'utils/doesTokenMatchSymbolOrAddress' - import { TokensByAddress } from '../state/tokensListAtom' export function getTokensByAddress( diff --git a/apps/cowswap-frontend/src/modules/trade/containers/TradeConfirmModal/TradeConfirmPendingContent.tsx b/apps/cowswap-frontend/src/modules/trade/containers/TradeConfirmModal/TradeConfirmPendingContent.tsx index ee8bacce8b..82521c3d65 100644 --- a/apps/cowswap-frontend/src/modules/trade/containers/TradeConfirmModal/TradeConfirmPendingContent.tsx +++ b/apps/cowswap-frontend/src/modules/trade/containers/TradeConfirmModal/TradeConfirmPendingContent.tsx @@ -1,10 +1,10 @@ import React from 'react' -import { useWalletDisplayedAddress } from 'modules/wallet' +import { TokenAmount } from '@cowprotocol/ui' +import { useWalletDisplayedAddress } from '@cowprotocol/wallet' import { useWalletStatusIcon } from 'common/hooks/useWalletStatusIcon' import { ConfirmationPendingContent } from 'common/pure/ConfirmationPendingContent' -import { TokenAmount } from 'common/pure/TokenAmount' import { TradeAmounts } from 'common/types' const description = `Almost there! \n Follow these steps:` diff --git a/apps/cowswap-frontend/src/modules/trade/containers/TradeConfirmModal/index.cosmos.tsx b/apps/cowswap-frontend/src/modules/trade/containers/TradeConfirmModal/index.cosmos.tsx index 1729f198aa..6266f269f2 100644 --- a/apps/cowswap-frontend/src/modules/trade/containers/TradeConfirmModal/index.cosmos.tsx +++ b/apps/cowswap-frontend/src/modules/trade/containers/TradeConfirmModal/index.cosmos.tsx @@ -2,11 +2,10 @@ import { useSetAtom } from 'jotai' import React, { useEffect } from 'react' import { SupportedChainId } from '@cowprotocol/cow-sdk' +import { walletInfoAtom } from '@cowprotocol/wallet' import { inputCurrencyInfoMock, outputCurrencyInfoMock, priceImpactMock } from 'mocks/tradeStateMock' -import { walletInfoAtom } from 'modules/wallet/api/state' - import { TradeAmounts } from 'common/types' import { useTradeConfirmActions } from '../../hooks/useTradeConfirmActions' diff --git a/apps/cowswap-frontend/src/modules/trade/containers/TradeConfirmModal/index.tsx b/apps/cowswap-frontend/src/modules/trade/containers/TradeConfirmModal/index.tsx index 76cad91c7c..4d6e9c4fd3 100644 --- a/apps/cowswap-frontend/src/modules/trade/containers/TradeConfirmModal/index.tsx +++ b/apps/cowswap-frontend/src/modules/trade/containers/TradeConfirmModal/index.tsx @@ -1,10 +1,13 @@ import { useAtomValue } from 'jotai' -import { useIsSafeWallet, useWalletInfo } from 'modules/wallet' +import { SupportedChainId } from '@cowprotocol/cow-sdk' +import { useIsSafeWallet, useWalletInfo } from '@cowprotocol/wallet' -import { CowModal } from 'common/pure/Modal' +import { PermitModal } from 'common/containers/PermitModal' +import { CowModal, NewCowModal } from 'common/pure/Modal' import { OrderSubmittedContent } from 'common/pure/OrderSubmittedContent' import { TransactionErrorContent } from 'common/pure/TransactionErrorContent' +import { TradeAmounts } from 'common/types' import { TradeConfirmPendingContent } from './TradeConfirmPendingContent' @@ -20,37 +23,90 @@ export function TradeConfirmModal(props: TradeConfirmModalProps) { const { chainId, account } = useWalletInfo() const isSafeWallet = useIsSafeWallet() - const { isOpen, pendingTrade, transactionHash, error } = useAtomValue(tradeConfirmStateAtom) + const { isOpen, permitSignatureState, pendingTrade, transactionHash, error } = useAtomValue(tradeConfirmStateAtom) const { onDismiss } = useTradeConfirmActions() if (!account) return null + const Modal = permitSignatureState ? NewCowModal : CowModal + return ( - - {(() => { - if (error) { - return - } - - if (pendingTrade) { - return - } - - // TODO: use for Swap - if (transactionHash) { - return ( - - ) - } - - return children - })()} - + + + {children} + + ) } + +type InnerComponentProps = { + children: JSX.Element + chainId: SupportedChainId + account: string + error: string | null + pendingTrade: TradeAmounts | null + transactionHash: string | null + onDismiss: () => void + permitSignatureState: string | undefined + isSafeWallet: boolean +} + +function InnerComponent(props: InnerComponentProps) { + const { + account, + chainId, + children, + error, + isSafeWallet, + onDismiss, + pendingTrade, + permitSignatureState, + transactionHash, + } = props + + if (error) { + return + } + + if (pendingTrade && permitSignatureState) { + // TODO: potentially replace TradeConfirmPendingContent completely with PermitModal + // We could use this not just for permit, but for any token, even already approved + const step = permitSignatureState === 'signed' ? 'submit' : 'approve' + return ( + + ) + } + + if (pendingTrade) { + return + } + + if (transactionHash) { + return ( + + ) + } + + return children +} diff --git a/apps/cowswap-frontend/src/modules/trade/containers/TradeWidget/TradeWidgetModals.tsx b/apps/cowswap-frontend/src/modules/trade/containers/TradeWidget/TradeWidgetModals.tsx index 1bd42bf439..930b93fc6b 100644 --- a/apps/cowswap-frontend/src/modules/trade/containers/TradeWidget/TradeWidgetModals.tsx +++ b/apps/cowswap-frontend/src/modules/trade/containers/TradeWidget/TradeWidgetModals.tsx @@ -1,6 +1,6 @@ import React from 'react' -import { useWalletInfo } from 'modules/wallet' +import { useWalletInfo } from '@cowprotocol/wallet' import { ImportTokenModal } from 'common/containers/ImportTokenModal' import { TradeApproveModal } from 'common/containers/TradeApprove' diff --git a/apps/cowswap-frontend/src/modules/trade/containers/TradeWidget/index.tsx b/apps/cowswap-frontend/src/modules/trade/containers/TradeWidget/index.tsx index 2eb4d26b48..bb5f1d3dcc 100644 --- a/apps/cowswap-frontend/src/modules/trade/containers/TradeWidget/index.tsx +++ b/apps/cowswap-frontend/src/modules/trade/containers/TradeWidget/index.tsx @@ -1,9 +1,11 @@ import { ReactNode, useEffect } from 'react' +import { maxAmountSpend } from '@cowprotocol/common-utils' +import { useIsSafeWallet, useWalletDetails, useWalletInfo } from '@cowprotocol/wallet' + import { t } from '@lingui/macro' import { PriceImpact } from 'legacy/hooks/usePriceImpact' -import { maxAmountSpend } from 'legacy/utils/maxAmountSpend' import { TradeWidgetLinks } from 'modules/application/containers/TradeWidgetLinks' import { SetRecipientProps } from 'modules/swap/containers/SetRecipient' @@ -11,7 +13,6 @@ import { useIsWrapOrUnwrap } from 'modules/trade/hooks/useIsWrapOrUnwrap' import { RecipientAddressUpdater } from 'modules/trade/updaters/RecipientAddressUpdater' import { TradeFormValidationUpdater } from 'modules/tradeFormValidation' import { TradeQuoteUpdater } from 'modules/tradeQuote' -import { useIsSafeWallet, useWalletDetails, useWalletInfo } from 'modules/wallet' import { useIsProviderNetworkUnsupported } from 'common/hooks/useIsProviderNetworkUnsupported' import { useThrottleFn } from 'common/hooks/useThrottleFn' diff --git a/apps/cowswap-frontend/src/modules/trade/containers/TradeWidget/styled.tsx b/apps/cowswap-frontend/src/modules/trade/containers/TradeWidget/styled.tsx index 49c68e8dda..e8643f3388 100644 --- a/apps/cowswap-frontend/src/modules/trade/containers/TradeWidget/styled.tsx +++ b/apps/cowswap-frontend/src/modules/trade/containers/TradeWidget/styled.tsx @@ -2,6 +2,8 @@ import styled from 'styled-components/macro' import { SetRecipient } from 'modules/swap/containers/SetRecipient' +import { UI } from 'common/constants/theme' + export const Container = styled.div` width: 100%; max-width: ${({ theme }) => theme.appBody.maxWidth.swap}; @@ -12,7 +14,7 @@ export const ContainerBox = styled.div` display: flex; flex-flow: column wrap; gap: 10px; - background: ${({ theme }) => theme.bg1}; + background: var(${UI.COLOR_CONTAINER_BG_01}); border: none; border-radius: 16px; box-shadow: ${({ theme }) => theme.boxShadow1}; diff --git a/apps/cowswap-frontend/src/modules/trade/containers/WrapNativeModal/index.tsx b/apps/cowswap-frontend/src/modules/trade/containers/WrapNativeModal/index.tsx index 402668a682..cdafbb4479 100644 --- a/apps/cowswap-frontend/src/modules/trade/containers/WrapNativeModal/index.tsx +++ b/apps/cowswap-frontend/src/modules/trade/containers/WrapNativeModal/index.tsx @@ -1,13 +1,12 @@ import { useAtom } from 'jotai' import { useCallback } from 'react' -import { useWalletDisplayedAddress } from 'modules/wallet' +import { TokenAmount, TokenSymbol } from '@cowprotocol/ui' +import { useWalletDisplayedAddress } from '@cowprotocol/wallet' import { useWalletStatusIcon } from 'common/hooks/useWalletStatusIcon' import { ConfirmationPendingContent } from 'common/pure/ConfirmationPendingContent' import { CowModal } from 'common/pure/Modal' -import { TokenAmount } from 'common/pure/TokenAmount' -import { TokenSymbol } from 'common/pure/TokenSymbol' import { useDerivedTradeState } from '../../hooks/useDerivedTradeState' import { wrapNativeStateAtom } from '../../state/wrapNativeStateAtom' diff --git a/apps/cowswap-frontend/src/modules/trade/hooks/setupTradeState/useResetStateWithSymbolDuplication.ts b/apps/cowswap-frontend/src/modules/trade/hooks/setupTradeState/useResetStateWithSymbolDuplication.ts index b2267c9076..db2c485178 100644 --- a/apps/cowswap-frontend/src/modules/trade/hooks/setupTradeState/useResetStateWithSymbolDuplication.ts +++ b/apps/cowswap-frontend/src/modules/trade/hooks/setupTradeState/useResetStateWithSymbolDuplication.ts @@ -1,8 +1,8 @@ import { useEffect } from 'react' -import { t } from '@lingui/macro' +import { useWalletInfo } from '@cowprotocol/wallet' -import { useWalletInfo } from 'modules/wallet' +import { t } from '@lingui/macro' import { useAreThereTokensWithSameSymbol } from 'common/hooks/useAreThereTokensWithSameSymbol' diff --git a/apps/cowswap-frontend/src/modules/trade/hooks/setupTradeState/useSetupTradeState.ts b/apps/cowswap-frontend/src/modules/trade/hooks/setupTradeState/useSetupTradeState.ts index 8f16f85ad7..7ada7d4922 100644 --- a/apps/cowswap-frontend/src/modules/trade/hooks/setupTradeState/useSetupTradeState.ts +++ b/apps/cowswap-frontend/src/modules/trade/hooks/setupTradeState/useSetupTradeState.ts @@ -1,14 +1,12 @@ import { useEffect, useState } from 'react' +import { usePrevious } from '@cowprotocol/common-hooks' import { SupportedChainId } from '@cowprotocol/cow-sdk' +import { useWalletInfo, switchChain } from '@cowprotocol/wallet' import { useWeb3React } from '@web3-react/core' -import usePrevious from 'legacy/hooks/usePrevious' - import { useTradeNavigate } from 'modules/trade/hooks/useTradeNavigate' import { getDefaultTradeRawState, TradeRawState } from 'modules/trade/types/TradeRawState' -import { useWalletInfo } from 'modules/wallet' -import { switchChain } from 'modules/wallet/web3-react/hooks/switchChain' import { useResetStateWithSymbolDuplication } from './useResetStateWithSymbolDuplication' import { useTradeStateFromUrl } from './useTradeStateFromUrl' diff --git a/apps/cowswap-frontend/src/modules/trade/hooks/useBuildTradeDerivedState.ts b/apps/cowswap-frontend/src/modules/trade/hooks/useBuildTradeDerivedState.ts index 286bc6e12b..27140cdd8d 100644 --- a/apps/cowswap-frontend/src/modules/trade/hooks/useBuildTradeDerivedState.ts +++ b/apps/cowswap-frontend/src/modules/trade/hooks/useBuildTradeDerivedState.ts @@ -1,13 +1,14 @@ import { Atom, useAtomValue } from 'jotai' +import { tryParseFractionalAmount } from '@cowprotocol/common-utils' +import { useWalletInfo } from '@cowprotocol/wallet' + import useCurrencyBalance from 'modules/tokens/hooks/useCurrencyBalance' import { ExtendedTradeRawState } from 'modules/trade/types/TradeRawState' import { useTradeUsdAmounts } from 'modules/usdAmount' -import { useWalletInfo } from 'modules/wallet' import { useSafeMemoObject } from 'common/hooks/useSafeMemo' import { useTokenBySymbolOrAddress } from 'common/hooks/useTokenBySymbolOrAddress' -import { tryParseFractionalAmount } from 'utils/tryParseFractionalAmount' export function useBuildTradeDerivedState(stateAtom: Atom) { const { account } = useWalletInfo() diff --git a/apps/cowswap-frontend/src/modules/trade/hooks/useDerivedTradeState.ts b/apps/cowswap-frontend/src/modules/trade/hooks/useDerivedTradeState.ts index 22e48f7710..5781562082 100644 --- a/apps/cowswap-frontend/src/modules/trade/hooks/useDerivedTradeState.ts +++ b/apps/cowswap-frontend/src/modules/trade/hooks/useDerivedTradeState.ts @@ -18,19 +18,13 @@ export function useDerivedTradeState(): { state?: TradeDerivedState } { if (!tradeTypeInfo) return {} if (tradeTypeInfo.tradeType === TradeType.SWAP) { - return { - state: swapDerivedState, - } + return { state: swapDerivedState } } if (tradeTypeInfo.tradeType === TradeType.ADVANCED_ORDERS) { - return { - state: advancedOrdersDerivedState, - } + return { state: advancedOrdersDerivedState } } - return { - state: limitOrdersDerivedState, - } + return { state: limitOrdersDerivedState } }, [tradeTypeInfo, swapDerivedState, limitOrdersDerivedState, advancedOrdersDerivedState]) } diff --git a/apps/cowswap-frontend/src/modules/trade/hooks/useDisableNativeTokenSelling.ts b/apps/cowswap-frontend/src/modules/trade/hooks/useDisableNativeTokenSelling.ts index 3c7e8417d6..610faa95ac 100644 --- a/apps/cowswap-frontend/src/modules/trade/hooks/useDisableNativeTokenSelling.ts +++ b/apps/cowswap-frontend/src/modules/trade/hooks/useDisableNativeTokenSelling.ts @@ -1,9 +1,8 @@ import { useEffect } from 'react' -import { NATIVE_CURRENCY_BUY_TOKEN } from 'legacy/constants' -import { WRAPPED_NATIVE_CURRENCY } from 'legacy/constants/tokens' - -import { useWalletInfo } from 'modules/wallet' +import { WRAPPED_NATIVE_CURRENCY } from '@cowprotocol/common-const' +import { NATIVE_CURRENCY_BUY_TOKEN } from '@cowprotocol/common-const' +import { useWalletInfo } from '@cowprotocol/wallet' import { useTradeNavigate } from './useTradeNavigate' import { useTradeState } from './useTradeState' diff --git a/apps/cowswap-frontend/src/modules/trade/hooks/useIsNativeInOrOut.ts b/apps/cowswap-frontend/src/modules/trade/hooks/useIsNativeInOrOut.ts index 57bf3b6efe..1deb924e48 100644 --- a/apps/cowswap-frontend/src/modules/trade/hooks/useIsNativeInOrOut.ts +++ b/apps/cowswap-frontend/src/modules/trade/hooks/useIsNativeInOrOut.ts @@ -1,8 +1,7 @@ import { useMemo } from 'react' -import { useWalletInfo } from 'modules/wallet' - -import { getIsNativeToken } from 'utils/getIsNativeToken' +import { getIsNativeToken } from '@cowprotocol/common-utils' +import { useWalletInfo } from '@cowprotocol/wallet' import { useTradeState } from './useTradeState' diff --git a/apps/cowswap-frontend/src/modules/trade/hooks/useIsWrapOrUnwrap.ts b/apps/cowswap-frontend/src/modules/trade/hooks/useIsWrapOrUnwrap.ts index 1949f6db02..ede54d04b3 100644 --- a/apps/cowswap-frontend/src/modules/trade/hooks/useIsWrapOrUnwrap.ts +++ b/apps/cowswap-frontend/src/modules/trade/hooks/useIsWrapOrUnwrap.ts @@ -1,9 +1,9 @@ import { useMemo } from 'react' -import { useTradeState } from 'modules/trade/hooks/useTradeState' -import { useWalletInfo } from 'modules/wallet' +import { getIsWrapOrUnwrap } from '@cowprotocol/common-utils' +import { useWalletInfo } from '@cowprotocol/wallet' -import { getIsWrapOrUnwrap } from 'utils/getIsWrapOrUnwrap' +import { useTradeState } from 'modules/trade/hooks/useTradeState' export function useIsWrapOrUnwrap(): boolean { const { chainId } = useWalletInfo() diff --git a/apps/cowswap-frontend/src/modules/trade/hooks/useIsWrappedInOrOut.ts b/apps/cowswap-frontend/src/modules/trade/hooks/useIsWrappedInOrOut.ts index ce62913a0c..ef4a07e9eb 100644 --- a/apps/cowswap-frontend/src/modules/trade/hooks/useIsWrappedInOrOut.ts +++ b/apps/cowswap-frontend/src/modules/trade/hooks/useIsWrappedInOrOut.ts @@ -1,12 +1,9 @@ import { useMemo } from 'react' +import { WRAPPED_NATIVE_CURRENCY } from '@cowprotocol/common-const' +import { doesTokenMatchSymbolOrAddress } from '@cowprotocol/common-utils' import { SupportedChainId } from '@cowprotocol/cow-sdk' - -import { WRAPPED_NATIVE_CURRENCY } from 'legacy/constants/tokens' - -import { useWalletInfo } from 'modules/wallet' - -import { doesTokenMatchSymbolOrAddress } from 'utils/doesTokenMatchSymbolOrAddress' +import { useWalletInfo } from '@cowprotocol/wallet' import { useTradeState } from './useTradeState' diff --git a/apps/cowswap-frontend/src/modules/trade/hooks/useNavigateOnCurrencySelection.ts b/apps/cowswap-frontend/src/modules/trade/hooks/useNavigateOnCurrencySelection.ts index 2616b476ad..1df5d47bd7 100644 --- a/apps/cowswap-frontend/src/modules/trade/hooks/useNavigateOnCurrencySelection.ts +++ b/apps/cowswap-frontend/src/modules/trade/hooks/useNavigateOnCurrencySelection.ts @@ -1,12 +1,12 @@ import { useCallback } from 'react' +import { useWalletInfo } from '@cowprotocol/wallet' import { Currency, Token } from '@uniswap/sdk-core' -import { Field } from 'legacy/state/swap/actions' +import { Field } from 'legacy/state/types' import { useTradeNavigate } from 'modules/trade/hooks/useTradeNavigate' import { useTradeState } from 'modules/trade/hooks/useTradeState' -import { useWalletInfo } from 'modules/wallet' import { useAreThereTokensWithSameSymbol } from 'common/hooks/useAreThereTokensWithSameSymbol' diff --git a/apps/cowswap-frontend/src/modules/trade/hooks/useOnCurrencySelection.ts b/apps/cowswap-frontend/src/modules/trade/hooks/useOnCurrencySelection.ts index 4d80ea1d35..872793f7a4 100644 --- a/apps/cowswap-frontend/src/modules/trade/hooks/useOnCurrencySelection.ts +++ b/apps/cowswap-frontend/src/modules/trade/hooks/useOnCurrencySelection.ts @@ -1,15 +1,15 @@ import { useSetAtom } from 'jotai' import { useCallback } from 'react' +import { FractionUtils } from '@cowprotocol/common-utils' import { Currency } from '@uniswap/sdk-core' -import { Field } from 'legacy/state/swap/actions' +import { Field } from 'legacy/state/types' import { updateLimitOrdersRawStateAtom } from 'modules/limitOrders' import { useLimitOrdersDerivedState } from 'modules/limitOrders/hooks/useLimitOrdersDerivedState' import { useNavigateOnCurrencySelection } from 'modules/trade/hooks/useNavigateOnCurrencySelection' -import { FractionUtils } from 'utils/fractionUtils' import { convertAmountToCurrency } from 'utils/orderUtils/calculateExecutionPrice' export function useOnCurrencySelection(): (field: Field, currency: Currency | null) => void { diff --git a/apps/cowswap-frontend/src/modules/trade/hooks/useSwitchTokensPlaces.ts b/apps/cowswap-frontend/src/modules/trade/hooks/useSwitchTokensPlaces.ts index a303893490..c46a42d864 100644 --- a/apps/cowswap-frontend/src/modules/trade/hooks/useSwitchTokensPlaces.ts +++ b/apps/cowswap-frontend/src/modules/trade/hooks/useSwitchTokensPlaces.ts @@ -1,10 +1,8 @@ import { useCallback } from 'react' -import { switchTokensAnalytics } from 'legacy/components/analytics' - -import { useWalletInfo } from 'modules/wallet' - -import { FractionUtils } from 'utils/fractionUtils' +import { switchTokensAnalytics } from '@cowprotocol/analytics' +import { FractionUtils } from '@cowprotocol/common-utils' +import { useWalletInfo } from '@cowprotocol/wallet' import { useDerivedTradeState } from './useDerivedTradeState' import { useIsWrapOrUnwrap } from './useIsWrapOrUnwrap' diff --git a/apps/cowswap-frontend/src/modules/trade/hooks/useTradeConfirmActions.ts b/apps/cowswap-frontend/src/modules/trade/hooks/useTradeConfirmActions.ts index 1fa198cf14..867269f267 100644 --- a/apps/cowswap-frontend/src/modules/trade/hooks/useTradeConfirmActions.ts +++ b/apps/cowswap-frontend/src/modules/trade/hooks/useTradeConfirmActions.ts @@ -7,6 +7,7 @@ import { setErrorTradeConfirmAtom, setOpenTradeConfirmAtom, setPendingTradeConfirmAtom, + setPermitSignatureRequestedTradeConfirmAtom, setTxHashTradeConfirmAtom, } from '../state/tradeConfirmStateAtom' @@ -15,15 +16,17 @@ export interface TradeConfirmActions { onError(error: string): void onSuccess(transactionHash: string): void onOpen(): void + requestPermitSignature(pendingTrade: TradeAmounts): void onDismiss(): void } export function useTradeConfirmActions(): TradeConfirmActions { - const setOpenTradeConfim = useSetAtom(setOpenTradeConfirmAtom) + const setOpenTradeConfirm = useSetAtom(setOpenTradeConfirmAtom) const setCloseTradeConfirm = useSetAtom(setCloseTradeConfirmAtom) const setErrorTradeConfirm = useSetAtom(setErrorTradeConfirmAtom) const setPendingTradeConfirm = useSetAtom(setPendingTradeConfirmAtom) const setTxHashTradeConfirm = useSetAtom(setTxHashTradeConfirmAtom) + const setPermitSignatureRequested = useSetAtom(setPermitSignatureRequestedTradeConfirmAtom) return { onSign(pendingTrade: TradeAmounts) { @@ -36,7 +39,10 @@ export function useTradeConfirmActions(): TradeConfirmActions { setTxHashTradeConfirm(transactionHash) }, onOpen() { - setOpenTradeConfim() + setOpenTradeConfirm() + }, + requestPermitSignature(pendingTrade: TradeAmounts) { + setPermitSignatureRequested(pendingTrade) }, onDismiss() { setCloseTradeConfirm() diff --git a/apps/cowswap-frontend/src/modules/trade/hooks/useTradeTypeInfo.ts b/apps/cowswap-frontend/src/modules/trade/hooks/useTradeTypeInfo.ts index 57a971ba4d..46de0eac16 100644 --- a/apps/cowswap-frontend/src/modules/trade/hooks/useTradeTypeInfo.ts +++ b/apps/cowswap-frontend/src/modules/trade/hooks/useTradeTypeInfo.ts @@ -6,9 +6,9 @@ import { useMatch } from 'react-router-dom' import { Routes, RoutesValues, TRADE_WIDGET_PREFIX } from 'common/constants/routes' export enum TradeType { - SWAP, - LIMIT_ORDER, - ADVANCED_ORDERS, + SWAP = 'SWAP', + LIMIT_ORDER = 'LIMIT_ORDER', + ADVANCED_ORDERS = 'ADVANCED_ORDERS', } export interface TradeTypeInfo { diff --git a/apps/cowswap-frontend/src/modules/trade/hooks/useUpdateCurrencyAmount.ts b/apps/cowswap-frontend/src/modules/trade/hooks/useUpdateCurrencyAmount.ts index eda576ba17..c8b6d98cd6 100644 --- a/apps/cowswap-frontend/src/modules/trade/hooks/useUpdateCurrencyAmount.ts +++ b/apps/cowswap-frontend/src/modules/trade/hooks/useUpdateCurrencyAmount.ts @@ -1,14 +1,12 @@ import { useCallback } from 'react' +import { FractionUtils, tryParseCurrencyAmount } from '@cowprotocol/common-utils' import { Currency, CurrencyAmount } from '@uniswap/sdk-core' -import { Field } from 'legacy/state/swap/actions' +import { Field } from 'legacy/state/types' import { useTradeState } from 'modules/trade/hooks/useTradeState' -import tryParseCurrencyAmount from 'lib/utils/tryParseCurrencyAmount' -import { FractionUtils } from 'utils/fractionUtils' - type AmountType = { value: string isTyped: boolean diff --git a/apps/cowswap-frontend/src/modules/trade/hooks/useWrapNativeFlow.ts b/apps/cowswap-frontend/src/modules/trade/hooks/useWrapNativeFlow.ts index 09a15df475..620af0c833 100644 --- a/apps/cowswap-frontend/src/modules/trade/hooks/useWrapNativeFlow.ts +++ b/apps/cowswap-frontend/src/modules/trade/hooks/useWrapNativeFlow.ts @@ -1,11 +1,12 @@ import { useSetAtom } from 'jotai' import { useCallback } from 'react' +import { useWETHContract } from '@cowprotocol/common-hooks' +import { useWalletInfo } from '@cowprotocol/wallet' import { Currency, CurrencyAmount } from '@uniswap/sdk-core' import { Nullish } from 'types' -import { useWETHContract } from 'legacy/hooks/useContract' import { wrapUnwrapCallback, WrapUnwrapCallback, @@ -14,8 +15,6 @@ import { } from 'legacy/hooks/useWrapCallback' import { useTransactionAdder } from 'legacy/state/enhancedTransactions/hooks' -import { useWalletInfo } from 'modules/wallet' - import { useDerivedTradeState } from './useDerivedTradeState' import { useTradeState } from './useTradeState' diff --git a/apps/cowswap-frontend/src/modules/trade/index.ts b/apps/cowswap-frontend/src/modules/trade/index.ts index cadc5d77d0..ce49753c7b 100644 --- a/apps/cowswap-frontend/src/modules/trade/index.ts +++ b/apps/cowswap-frontend/src/modules/trade/index.ts @@ -6,4 +6,5 @@ export * from './hooks/useTradeTypeInfo' export * from './hooks/useTradePriceImpact' export * from './hooks/setupTradeState/useSetupTradeState' export * from './hooks/useWrapNativeFlow' +export * from './hooks/useDerivedTradeState' export * from './types/TradeDerivedState' diff --git a/apps/cowswap-frontend/src/modules/trade/pure/CompatibilityIssuesWarning/index.tsx b/apps/cowswap-frontend/src/modules/trade/pure/CompatibilityIssuesWarning/index.tsx index ed91bf1955..c9e417f562 100644 --- a/apps/cowswap-frontend/src/modules/trade/pure/CompatibilityIssuesWarning/index.tsx +++ b/apps/cowswap-frontend/src/modules/trade/pure/CompatibilityIssuesWarning/index.tsx @@ -1,13 +1,12 @@ import React from 'react' +import { genericPropsChecker } from '@cowprotocol/common-utils' import { Currency } from '@uniswap/sdk-core' import { HashLink } from 'react-router-hash-link' import UnsupportedCurrencyFooter from 'legacy/components/swap/UnsupportedCurrencyFooter' -import { genericPropsChecker } from 'utils/genericPropsChecker' - export interface CompatibilityIssuesWarningProps { currencyIn: Currency currencyOut: Currency diff --git a/apps/cowswap-frontend/src/modules/trade/pure/ConfirmDetailsItem/index.tsx b/apps/cowswap-frontend/src/modules/trade/pure/ConfirmDetailsItem/index.tsx index 7b408b6ff8..e54f111a7e 100644 --- a/apps/cowswap-frontend/src/modules/trade/pure/ConfirmDetailsItem/index.tsx +++ b/apps/cowswap-frontend/src/modules/trade/pure/ConfirmDetailsItem/index.tsx @@ -1,9 +1,10 @@ import { ReactNode } from 'react' +import { RowFixed } from '@cowprotocol/ui' + import { CornerDownRight } from 'react-feather' import { InfoIcon } from 'legacy/components/InfoIcon' -import { RowFixed } from 'legacy/components/Row' import { TextWrapper } from 'modules/swap/pure/Row/styled' diff --git a/apps/cowswap-frontend/src/modules/trade/pure/ConfirmDetailsItem/styled.ts b/apps/cowswap-frontend/src/modules/trade/pure/ConfirmDetailsItem/styled.ts index caa261faef..aef244cb79 100644 --- a/apps/cowswap-frontend/src/modules/trade/pure/ConfirmDetailsItem/styled.ts +++ b/apps/cowswap-frontend/src/modules/trade/pure/ConfirmDetailsItem/styled.ts @@ -2,6 +2,8 @@ import styled from 'styled-components/macro' import { StyledRowBetween } from 'modules/swap/pure/Row/styled' +import { UI } from 'common/constants/theme' + export const Wrapper = styled.div` display: flex; align-items: center; @@ -15,7 +17,7 @@ export const Wrapper = styled.div` > svg:first-child { margin: 0 4px 0 0; - color: ${({ theme }) => theme.text1}; + color: var(${UI.COLOR_TEXT1}); opacity: 0.5; } diff --git a/apps/cowswap-frontend/src/modules/trade/pure/ReviewOrderModalAmountRow/index.tsx b/apps/cowswap-frontend/src/modules/trade/pure/ReviewOrderModalAmountRow/index.tsx index b5abb13d58..14fe26e8bf 100644 --- a/apps/cowswap-frontend/src/modules/trade/pure/ReviewOrderModalAmountRow/index.tsx +++ b/apps/cowswap-frontend/src/modules/trade/pure/ReviewOrderModalAmountRow/index.tsx @@ -1,12 +1,10 @@ import { ReactNode } from 'react' +import { FiatAmount, TokenAmount } from '@cowprotocol/ui' import { Currency, CurrencyAmount } from '@uniswap/sdk-core' import { Nullish } from 'types' -import { FiatAmount } from 'common/pure/FiatAmount' -import { TokenAmount } from 'common/pure/TokenAmount' - import { ConfirmDetailsItem } from '../ConfirmDetailsItem' export type ReviewOrderAmountRowProps = { diff --git a/apps/cowswap-frontend/src/modules/trade/pure/Settings/SettingsBox.tsx b/apps/cowswap-frontend/src/modules/trade/pure/Settings/SettingsBox.tsx index 13bd2385d2..18b1d6d72f 100644 --- a/apps/cowswap-frontend/src/modules/trade/pure/Settings/SettingsBox.tsx +++ b/apps/cowswap-frontend/src/modules/trade/pure/Settings/SettingsBox.tsx @@ -4,7 +4,7 @@ import { Trans } from '@lingui/macro' import { ThemeContext } from 'styled-components/macro' import QuestionHelper from 'legacy/components/QuestionHelper' -import Toggle from 'legacy/components/Toggle' +import { Toggle } from 'legacy/components/Toggle' import { SettingsBoxTitle, SettingsBoxWrapper } from './styled' diff --git a/apps/cowswap-frontend/src/modules/trade/pure/Settings/styled.ts b/apps/cowswap-frontend/src/modules/trade/pure/Settings/styled.ts index 77fdee8b7f..7c299250e6 100644 --- a/apps/cowswap-frontend/src/modules/trade/pure/Settings/styled.ts +++ b/apps/cowswap-frontend/src/modules/trade/pure/Settings/styled.ts @@ -3,10 +3,12 @@ import { transparentize } from 'polished' import { Settings as SettingsIconRaw } from 'react-feather' import styled from 'styled-components/macro' +import { UI } from 'common/constants/theme' + export const SettingsTitle = styled.h3` font-weight: 600; font-size: 14px; - color: ${({ theme }) => theme.text1}; + color: var(${UI.COLOR_TEXT1}); margin: 0 0 12px 0; ` @@ -16,8 +18,8 @@ export const SettingsContainer = styled.div` border-radius: 12px; box-shadow: ${({ theme }) => theme.boxShadow2}; border: 1px solid ${({ theme }) => transparentize(0.95, theme.white)}; - background: ${({ theme }) => theme.bg1}; - color: ${({ theme }) => theme.text1}; + background: var(${UI.COLOR_CONTAINER_BG_01}); + color: var(${UI.COLOR_TEXT1}); ` export const SettingsBoxWrapper = styled.div<{ disabled: boolean }>` @@ -37,7 +39,7 @@ export const SettingsBoxTitle = styled.div` display: flex; align-items: center; font-weight: 400; - color: ${({ theme }) => theme.text1}; + color: var(${UI.COLOR_TEXT1}); font-size: 14px; opacity: 0.85; margin-right: 2rem; @@ -116,6 +118,6 @@ export const SettingsIcon = styled(SettingsIconRaw)` &:hover > path, &:hover > circle { - stroke: ${({ theme }) => theme.text1}; + stroke: var(${UI.COLOR_TEXT1}); } ` diff --git a/apps/cowswap-frontend/src/modules/trade/pure/TradeConfirmation/index.tsx b/apps/cowswap-frontend/src/modules/trade/pure/TradeConfirmation/index.tsx index 8458312344..9e315575bb 100644 --- a/apps/cowswap-frontend/src/modules/trade/pure/TradeConfirmation/index.tsx +++ b/apps/cowswap-frontend/src/modules/trade/pure/TradeConfirmation/index.tsx @@ -1,11 +1,11 @@ import React, { useCallback, useEffect, useRef, useState } from 'react' +import { ButtonSize, ButtonPrimary } from '@cowprotocol/ui' + import { Trans } from '@lingui/macro' -import { ButtonPrimary } from 'legacy/components/Button' import { PriceImpact } from 'legacy/hooks/usePriceImpact' import { CloseIcon } from 'legacy/theme' -import { ButtonSize } from 'legacy/theme/enum' import { CurrencyArrowSeparator } from 'common/pure/CurrencyArrowSeparator' import { CurrencyAmountPreview, CurrencyPreviewInfo } from 'common/pure/CurrencyInputPanel' diff --git a/apps/cowswap-frontend/src/modules/trade/pure/TradeConfirmation/styled.tsx b/apps/cowswap-frontend/src/modules/trade/pure/TradeConfirmation/styled.tsx index d79c30c070..b72a62e11d 100644 --- a/apps/cowswap-frontend/src/modules/trade/pure/TradeConfirmation/styled.tsx +++ b/apps/cowswap-frontend/src/modules/trade/pure/TradeConfirmation/styled.tsx @@ -1,5 +1,7 @@ import styled from 'styled-components/macro' +import { UI } from 'common/constants/theme' + export const WidgetWrapper = styled.div` width: 100%; padding: 0; @@ -32,7 +34,7 @@ export const Header = styled.div` justify-content: space-between; align-items: center; position: sticky; - background: ${({ theme }) => theme.bg1}; + background: var(${UI.COLOR_CONTAINER_BG_01}); top: 0; left: 0; width: 100%; diff --git a/apps/cowswap-frontend/src/modules/trade/pure/TradeNumberInput/index.tsx b/apps/cowswap-frontend/src/modules/trade/pure/TradeNumberInput/index.tsx index cacd356cc6..ac9a5f722b 100644 --- a/apps/cowswap-frontend/src/modules/trade/pure/TradeNumberInput/index.tsx +++ b/apps/cowswap-frontend/src/modules/trade/pure/TradeNumberInput/index.tsx @@ -1,10 +1,10 @@ import { useCallback, useEffect, useState } from 'react' +import carretDown from '@cowprotocol/assets/cow-swap/carret-down.svg' + import BigNumberJs from 'bignumber.js' import SVG from 'react-inlinesvg' -import carretDown from 'legacy/assets/cow-swap/carret-down.svg' - import { TradeWidgetField, TradeWidgetFieldProps } from 'modules/trade/pure/TradeWidgetField' import { ArrowsWrapper, InputWrapper, NumericalInput, Suffix } from './styled' diff --git a/apps/cowswap-frontend/src/modules/trade/pure/TradeNumberInput/styled.tsx b/apps/cowswap-frontend/src/modules/trade/pure/TradeNumberInput/styled.tsx index 7dadb4c6d2..82414cb371 100644 --- a/apps/cowswap-frontend/src/modules/trade/pure/TradeNumberInput/styled.tsx +++ b/apps/cowswap-frontend/src/modules/trade/pure/TradeNumberInput/styled.tsx @@ -3,6 +3,8 @@ import styled from 'styled-components/macro' import Input from 'legacy/components/NumericalInput' +import { UI } from 'common/constants/theme' + export const Suffix = styled.span` margin: 0 0 0 3px; opacity: 0.7; @@ -47,7 +49,7 @@ export const ArrowsWrapper = styled.div` &:hover { > span > svg > path { - fill: ${({ theme }) => theme.text1}; + fill: var(${UI.COLOR_TEXT1}); } } } diff --git a/apps/cowswap-frontend/src/modules/trade/pure/TradeSelect/index.tsx b/apps/cowswap-frontend/src/modules/trade/pure/TradeSelect/index.tsx index ae2eb60d7c..ba783dd588 100644 --- a/apps/cowswap-frontend/src/modules/trade/pure/TradeSelect/index.tsx +++ b/apps/cowswap-frontend/src/modules/trade/pure/TradeSelect/index.tsx @@ -3,6 +3,8 @@ import { transparentize } from 'polished' import { ChevronDown } from 'react-feather' import styled from 'styled-components/macro' +import { UI } from 'common/constants/theme' + import { TradeWidgetField, TradeWidgetFieldProps } from '../TradeWidgetField' export type TradeSelectItem = { label: string; value: unknown } @@ -15,7 +17,7 @@ export interface TradeSelectProps extends TradeWidgetFieldProps { } const StyledMenuList = styled(MenuList)` - background: ${({ theme }) => theme.bg1}; + background: var(${UI.COLOR_CONTAINER_BG_01}); box-shadow: ${({ theme }) => theme.boxShadow2}; margin: 15px 0 0 0; padding: 16px; @@ -44,7 +46,7 @@ const StyledMenuButton = styled(MenuButton)` cursor: pointer; width: 100%; justify-content: space-between; - color: ${({ theme }) => theme.text1}; + color: var(${UI.COLOR_TEXT1}); ` const StyledMenuItem = styled(MenuItem)` @@ -53,7 +55,7 @@ const StyledMenuItem = styled(MenuItem)` color: ${({ theme }) => transparentize(0.2, theme.text1)}; &:hover { - color: ${({ theme }) => theme.text1}; + color: var(${UI.COLOR_TEXT1}); } &:not(:last-child) { diff --git a/apps/cowswap-frontend/src/modules/trade/pure/TradeTextBox/index.tsx b/apps/cowswap-frontend/src/modules/trade/pure/TradeTextBox/index.tsx index 7713ddf16c..346624ecbd 100644 --- a/apps/cowswap-frontend/src/modules/trade/pure/TradeTextBox/index.tsx +++ b/apps/cowswap-frontend/src/modules/trade/pure/TradeTextBox/index.tsx @@ -1,9 +1,11 @@ import styled from 'styled-components/macro' +import { UI } from 'common/constants/theme' + import { TradeWidgetField, TradeWidgetFieldProps } from '../TradeWidgetField' const StyledTradeWidgetField = styled(TradeWidgetField)` - background-color: ${({ theme }) => theme.bg1}; + background-color: var(${UI.COLOR_CONTAINER_BG_01}); border: 1px solid ${({ theme }) => theme.grey1}; display: flex; flex-flow: column wrap; diff --git a/apps/cowswap-frontend/src/modules/trade/pure/TradeWidgetField/index.tsx b/apps/cowswap-frontend/src/modules/trade/pure/TradeWidgetField/index.tsx index 4705d10da8..26e4a3788e 100644 --- a/apps/cowswap-frontend/src/modules/trade/pure/TradeWidgetField/index.tsx +++ b/apps/cowswap-frontend/src/modules/trade/pure/TradeWidgetField/index.tsx @@ -1,9 +1,10 @@ import React from 'react' +import { renderTooltip } from '@cowprotocol/ui' + import { Trans } from '@lingui/macro' import QuestionHelper from 'legacy/components/QuestionHelper' -import { renderTooltip } from 'legacy/components/Tooltip' import { Content, ErrorText, TradeWidgetFieldBox, TradeWidgetFieldLabel } from './styled' diff --git a/apps/cowswap-frontend/src/modules/trade/pure/UnlockWidgetScreen/index.tsx b/apps/cowswap-frontend/src/modules/trade/pure/UnlockWidgetScreen/index.tsx index 0cdc3c2799..9fe3f30b3c 100644 --- a/apps/cowswap-frontend/src/modules/trade/pure/UnlockWidgetScreen/index.tsx +++ b/apps/cowswap-frontend/src/modules/trade/pure/UnlockWidgetScreen/index.tsx @@ -1,8 +1,8 @@ -import SVG from 'react-inlinesvg' +import iconCompleted from '@cowprotocol/assets/cow-swap/check.svg' +import { ButtonPrimary } from '@cowprotocol/ui' +import { ExternalLink } from '@cowprotocol/ui' -import iconCompleted from 'legacy/assets/cow-swap/check.svg' -import { ButtonPrimary } from 'legacy/components/Button' -import { ExternalLink } from 'legacy/theme' +import SVG from 'react-inlinesvg' import * as styledEl from './styled' diff --git a/apps/cowswap-frontend/src/modules/trade/pure/UnlockWidgetScreen/styled.ts b/apps/cowswap-frontend/src/modules/trade/pure/UnlockWidgetScreen/styled.ts index 8572ebdf9b..c2dfd5fc45 100644 --- a/apps/cowswap-frontend/src/modules/trade/pure/UnlockWidgetScreen/styled.ts +++ b/apps/cowswap-frontend/src/modules/trade/pure/UnlockWidgetScreen/styled.ts @@ -1,6 +1,8 @@ import { transparentize, darken } from 'polished' import styled from 'styled-components/macro' +import { UI } from 'common/constants/theme' + export const Container = styled.div` padding: 16px; border-radius: 16px; @@ -10,7 +12,7 @@ export const Container = styled.div` export const TitleSection = styled.div` text-align: center; font-size: 20px; - color: ${({ theme }) => theme.text1}; + color: var(${UI.COLOR_TEXT1}); margin: 24px auto 42px; > h3 { diff --git a/apps/cowswap-frontend/src/modules/trade/state/tradeConfirmStateAtom.ts b/apps/cowswap-frontend/src/modules/trade/state/tradeConfirmStateAtom.ts index f2a06240e5..9e34917f6b 100644 --- a/apps/cowswap-frontend/src/modules/trade/state/tradeConfirmStateAtom.ts +++ b/apps/cowswap-frontend/src/modules/trade/state/tradeConfirmStateAtom.ts @@ -7,6 +7,7 @@ interface TradeConfirmModalState { pendingTrade: TradeAmounts | null transactionHash: string | null error: string | null + permitSignatureState: undefined | 'requested' | 'signed' } export const tradeConfirmStateAtom = atom({ @@ -14,63 +15,66 @@ export const tradeConfirmStateAtom = atom({ pendingTrade: null, transactionHash: null, error: null, + permitSignatureState: undefined, }) export const setOpenTradeConfirmAtom = atom(null, (get, set) => { - set(tradeConfirmStateAtom, () => { - return { - isOpen: true, - error: null, - pendingTrade: null, - transactionHash: null, - } - }) + set(tradeConfirmStateAtom, () => ({ + isOpen: true, + error: null, + pendingTrade: null, + transactionHash: null, + permitSignatureState: undefined, + })) }) export const setCloseTradeConfirmAtom = atom(null, (get, set) => { - set(tradeConfirmStateAtom, () => { - return { - ...get(tradeConfirmStateAtom), - isOpen: false, - } - }) + set(tradeConfirmStateAtom, () => ({ + ...get(tradeConfirmStateAtom), + isOpen: false, + permitSignatureState: undefined, + })) }) export const setErrorTradeConfirmAtom = atom(null, (get, set, error: string) => { - set(tradeConfirmStateAtom, () => { - const currentState = get(tradeConfirmStateAtom) + set(tradeConfirmStateAtom, () => ({ + ...get(tradeConfirmStateAtom), + error, + pendingTrade: null, + transactionHash: null, + permitSignatureState: undefined, + })) +}) - return { - isOpen: currentState.isOpen, - error, - pendingTrade: null, - transactionHash: null, - } - }) +export const setPermitSignatureRequestedTradeConfirmAtom = atom(null, (get, set, pendingTrade: TradeAmounts) => { + set(tradeConfirmStateAtom, () => ({ + ...get(tradeConfirmStateAtom), + pendingTrade, + permitSignatureState: 'requested', + })) }) export const setPendingTradeConfirmAtom = atom(null, (get, set, pendingTrade: TradeAmounts) => { - set(tradeConfirmStateAtom, () => { - const currentState = get(tradeConfirmStateAtom) + const currentState = get(tradeConfirmStateAtom) + set(tradeConfirmStateAtom, () => { return { - isOpen: currentState.isOpen, + ...currentState, error: null, pendingTrade, transactionHash: null, + // Only move to the next state if coming in the right sequence. + // Otherwise, reset it + permitSignatureState: currentState.permitSignatureState === 'requested' ? 'signed' : undefined, } }) }) export const setTxHashTradeConfirmAtom = atom(null, (get, set, transactionHash: string) => { - set(tradeConfirmStateAtom, () => { - const currentState = get(tradeConfirmStateAtom) - - return { - isOpen: currentState.isOpen, - error: null, - pendingTrade: null, - transactionHash, - } - }) + set(tradeConfirmStateAtom, () => ({ + ...get(tradeConfirmStateAtom), + error: null, + pendingTrade: null, + transactionHash, + })) }) diff --git a/apps/cowswap-frontend/src/modules/trade/types/TradeDerivedState.ts b/apps/cowswap-frontend/src/modules/trade/types/TradeDerivedState.ts index abf2be3627..aa80b975e7 100644 --- a/apps/cowswap-frontend/src/modules/trade/types/TradeDerivedState.ts +++ b/apps/cowswap-frontend/src/modules/trade/types/TradeDerivedState.ts @@ -1,6 +1,8 @@ import { OrderKind } from '@cowprotocol/cow-sdk' import { Currency, CurrencyAmount } from '@uniswap/sdk-core' +import { TradeType } from '../hooks/useTradeTypeInfo' + export interface TradeDerivedState { readonly inputCurrency: Currency | null readonly outputCurrency: Currency | null @@ -25,6 +27,7 @@ export interface TradeDerivedState { readonly recipient: string | null readonly recipientAddress: string | null readonly orderKind: OrderKind + readonly tradeType: TradeType | null } export const DEFAULT_TRADE_DERIVED_STATE: TradeDerivedState = { @@ -40,4 +43,5 @@ export const DEFAULT_TRADE_DERIVED_STATE: TradeDerivedState = { recipient: null, recipientAddress: null, orderKind: OrderKind.SELL, + tradeType: null, } diff --git a/apps/cowswap-frontend/src/modules/trade/types/TradeRawState.ts b/apps/cowswap-frontend/src/modules/trade/types/TradeRawState.ts index bfbd00e7d8..8403f3b0dc 100644 --- a/apps/cowswap-frontend/src/modules/trade/types/TradeRawState.ts +++ b/apps/cowswap-frontend/src/modules/trade/types/TradeRawState.ts @@ -1,7 +1,6 @@ +import { WRAPPED_NATIVE_CURRENCY as WETH } from '@cowprotocol/common-const' import { OrderKind, SupportedChainId } from '@cowprotocol/cow-sdk' -import { WRAPPED_NATIVE_CURRENCY as WETH } from 'legacy/constants/tokens' - export interface TradeUrlParams { readonly chainId: string | undefined readonly inputCurrencyId: string | undefined diff --git a/apps/cowswap-frontend/src/modules/trade/updaters/RecipientAddressUpdater.tsx b/apps/cowswap-frontend/src/modules/trade/updaters/RecipientAddressUpdater.tsx index 9322be5251..7e46c45981 100644 --- a/apps/cowswap-frontend/src/modules/trade/updaters/RecipientAddressUpdater.tsx +++ b/apps/cowswap-frontend/src/modules/trade/updaters/RecipientAddressUpdater.tsx @@ -1,6 +1,6 @@ import { useEffect } from 'react' -import useENSAddress from 'legacy/hooks/useENSAddress' +import { useENSAddress } from '@cowprotocol/ens' import { useTradeState } from '../hooks/useTradeState' diff --git a/apps/cowswap-frontend/src/modules/trade/utils/analytics.ts b/apps/cowswap-frontend/src/modules/trade/utils/analytics.ts index 7ebf50ffe0..f84ebaa76f 100644 --- a/apps/cowswap-frontend/src/modules/trade/utils/analytics.ts +++ b/apps/cowswap-frontend/src/modules/trade/utils/analytics.ts @@ -1,5 +1,5 @@ -import { signTradeAnalytics, tradeAnalytics } from 'legacy/components/analytics' -import { AnalyticsOrderType } from 'legacy/components/analytics/types' +import { signTradeAnalytics, tradeAnalytics } from '@cowprotocol/analytics' +import { AnalyticsOrderType } from '@cowprotocol/analytics' import { USER_SWAP_REJECTED_ERROR } from 'modules/trade/utils/swapErrorHelper' diff --git a/apps/cowswap-frontend/src/modules/trade/utils/swapErrorHelper.ts b/apps/cowswap-frontend/src/modules/trade/utils/swapErrorHelper.ts index aeae1e97ae..14d0416ed8 100644 --- a/apps/cowswap-frontend/src/modules/trade/utils/swapErrorHelper.ts +++ b/apps/cowswap-frontend/src/modules/trade/utils/swapErrorHelper.ts @@ -1,4 +1,6 @@ -import { getProviderErrorMessage, isRejectRequestProviderError } from 'legacy/utils/misc' +import { capitalizeFirstLetter, getProviderErrorMessage, isRejectRequestProviderError } from '@cowprotocol/common-utils' + +import { getIsOrderBookTypedError } from 'api/gnosisProtocol' export const USER_SWAP_REJECTED_ERROR = 'User rejected signing the order' @@ -6,6 +8,12 @@ export function getSwapErrorMessage(error: Error): string { if (isRejectRequestProviderError(error)) { return USER_SWAP_REJECTED_ERROR } else { - return getProviderErrorMessage(error) + const defaultErrorMessage = getProviderErrorMessage(error) + + if (getIsOrderBookTypedError(error)) { + return capitalizeFirstLetter(error.body?.description) || defaultErrorMessage + } + + return defaultErrorMessage } } diff --git a/apps/cowswap-frontend/src/modules/tradeFormValidation/hooks/useGetTradeFormValidation.ts b/apps/cowswap-frontend/src/modules/tradeFormValidation/hooks/useGetTradeFormValidation.ts index 04c2cb7275..43a1fa6dc3 100644 --- a/apps/cowswap-frontend/src/modules/tradeFormValidation/hooks/useGetTradeFormValidation.ts +++ b/apps/cowswap-frontend/src/modules/tradeFormValidation/hooks/useGetTradeFormValidation.ts @@ -1,6 +1,6 @@ import { useAtomValue } from 'jotai' -import useDebounce from 'legacy/hooks/useDebounce' +import { useDebounce } from '@cowprotocol/common-hooks' import { tradeFormValidationAtom } from '../state/tradeFormValidationAtom' import { TradeFormValidation } from '../types' diff --git a/apps/cowswap-frontend/src/modules/tradeFormValidation/hooks/useTradeFormButtonContext.ts b/apps/cowswap-frontend/src/modules/tradeFormValidation/hooks/useTradeFormButtonContext.ts index f39622e706..c69bfe49d0 100644 --- a/apps/cowswap-frontend/src/modules/tradeFormValidation/hooks/useTradeFormButtonContext.ts +++ b/apps/cowswap-frontend/src/modules/tradeFormValidation/hooks/useTradeFormButtonContext.ts @@ -1,11 +1,12 @@ import { useMemo } from 'react' +import { useWalletDetails } from '@cowprotocol/wallet' + import { useToggleWalletModal } from 'legacy/state/application/hooks' import { useWrapNativeFlow } from 'modules/trade' import { useDerivedTradeState } from 'modules/trade/hooks/useDerivedTradeState' import { useTradeQuote } from 'modules/tradeQuote' -import { useWalletDetails } from 'modules/wallet' import { TradeFormButtonContext } from '../types' diff --git a/apps/cowswap-frontend/src/modules/tradeFormValidation/hooks/useTradeFormValidationContext.ts b/apps/cowswap-frontend/src/modules/tradeFormValidation/hooks/useTradeFormValidationContext.ts index 0074bcfdf4..1c1d9ce845 100644 --- a/apps/cowswap-frontend/src/modules/tradeFormValidation/hooks/useTradeFormValidationContext.ts +++ b/apps/cowswap-frontend/src/modules/tradeFormValidation/hooks/useTradeFormValidationContext.ts @@ -1,16 +1,17 @@ import { useMemo } from 'react' -import useENSAddress from 'legacy/hooks/useENSAddress' +import { useENSAddress } from '@cowprotocol/ens' +import { useGnosisSafeInfo, useIsBundlingSupported, useWalletDetails, useWalletInfo } from '@cowprotocol/wallet' + import { useIsTradeUnsupported } from 'legacy/state/lists/hooks' import { isUnsupportedTokenInQuote } from 'modules/limitOrders/utils/isUnsupportedTokenInQuote' +import { useIsTokenPermittable } from 'modules/permit' import { useDerivedTradeState } from 'modules/trade/hooks/useDerivedTradeState' import { useIsWrapOrUnwrap } from 'modules/trade/hooks/useIsWrapOrUnwrap' import { useTradeQuote } from 'modules/tradeQuote' -import { useGnosisSafeInfo, useWalletDetails, useWalletInfo } from 'modules/wallet' import { useTradeApproveState } from 'common/containers/TradeApprove' -import { useIsTxBundlingEnabled } from 'common/hooks/featureFlags/useIsTxBundlingEnabled' import { TradeFormValidationCommonContext } from '../types' @@ -19,29 +20,32 @@ export function useTradeFormValidationContext(): TradeFormValidationCommonContex const { state: derivedTradeState } = useDerivedTradeState() const tradeQuote = useTradeQuote() - const { inputCurrency, outputCurrency, slippageAdjustedSellAmount, recipient } = derivedTradeState || {} + const { inputCurrency, outputCurrency, slippageAdjustedSellAmount, recipient, tradeType } = derivedTradeState || {} const approvalState = useTradeApproveState(slippageAdjustedSellAmount) const { address: recipientEnsAddress } = useENSAddress(recipient) const isSwapUnsupported = useIsTradeUnsupported(inputCurrency, outputCurrency) || isUnsupportedTokenInQuote(tradeQuote) - const isTxBundlingEnabled = useIsTxBundlingEnabled() + const isBundlingSupported = useIsBundlingSupported() const isWrapUnwrap = useIsWrapOrUnwrap() const { isSupportedWallet } = useWalletDetails() const gnosisSafeInfo = useGnosisSafeInfo() const isSafeReadonlyUser = gnosisSafeInfo?.isReadOnly || false + const isPermitSupported = !!useIsTokenPermittable(inputCurrency, tradeType) + const commonContext = { account, isWrapUnwrap, - isTxBundlingEnabled, + isBundlingSupported, isSupportedWallet, isSwapUnsupported, isSafeReadonlyUser, recipientEnsAddress, approvalState, tradeQuote, + isPermitSupported, } return useMemo(() => { diff --git a/apps/cowswap-frontend/src/modules/tradeFormValidation/pure/TradeFormBlankButton/index.tsx b/apps/cowswap-frontend/src/modules/tradeFormValidation/pure/TradeFormBlankButton/index.tsx index efda5ba520..2a17cc57c0 100644 --- a/apps/cowswap-frontend/src/modules/tradeFormValidation/pure/TradeFormBlankButton/index.tsx +++ b/apps/cowswap-frontend/src/modules/tradeFormValidation/pure/TradeFormBlankButton/index.tsx @@ -4,6 +4,8 @@ import { Trans } from '@lingui/macro' import { lighten, transparentize } from 'polished' import styled from 'styled-components/macro' +import { UI } from 'common/constants/theme' + const LONG_TEXT_LENGTH = 20 const ActionButton = styled.button<{ hasLongText$: boolean }>` @@ -27,7 +29,7 @@ const ActionButton = styled.button<{ hasLongText$: boolean }>` } &:disabled { - background-color: ${({ theme }) => theme.grey1}; + background-color: var(${UI.COLOR_GREY}); color: ${({ theme }) => transparentize(0.4, theme.text1)}; background-image: none; border: 0; diff --git a/apps/cowswap-frontend/src/modules/tradeFormValidation/pure/TradeFormButtons/tradeButtonsMap.tsx b/apps/cowswap-frontend/src/modules/tradeFormValidation/pure/TradeFormButtons/tradeButtonsMap.tsx index fac973ae41..af472af4f5 100644 --- a/apps/cowswap-frontend/src/modules/tradeFormValidation/pure/TradeFormButtons/tradeButtonsMap.tsx +++ b/apps/cowswap-frontend/src/modules/tradeFormValidation/pure/TradeFormButtons/tradeButtonsMap.tsx @@ -1,5 +1,7 @@ import React from 'react' +import { TokenSymbol } from '@cowprotocol/ui' + import { Trans } from '@lingui/macro' import styled from 'styled-components/macro' @@ -7,7 +9,6 @@ import { CompatibilityIssuesWarning } from 'modules/trade/pure/CompatibilityIssu import { GpQuoteErrorCodes } from 'api/gnosisProtocol/errors/QuoteError' import { TradeApproveButton } from 'common/containers/TradeApprove' -import { TokenSymbol } from 'common/pure/TokenSymbol' import { TradeLoadingButton } from 'common/pure/TradeLoadingButton' import { TradeFormButtonContext, TradeFormValidation } from '../../types' diff --git a/apps/cowswap-frontend/src/modules/tradeFormValidation/services/validateTradeForm.ts b/apps/cowswap-frontend/src/modules/tradeFormValidation/services/validateTradeForm.ts index ecd88eda97..c128750939 100644 --- a/apps/cowswap-frontend/src/modules/tradeFormValidation/services/validateTradeForm.ts +++ b/apps/cowswap-frontend/src/modules/tradeFormValidation/services/validateTradeForm.ts @@ -1,7 +1,6 @@ -import { ApprovalState } from 'legacy/hooks/useApproveCallback/useApproveCallbackMod' -import { isAddress } from 'legacy/utils' +import { isAddress, isFractionFalsy } from '@cowprotocol/common-utils' -import { isFractionFalsy } from 'utils/isFractionFalsy' +import { ApprovalState } from 'legacy/hooks/useApproveCallback/useApproveCallbackMod' import { TradeFormValidation, TradeFormValidationContext } from '../types' @@ -9,7 +8,7 @@ export function validateTradeForm(context: TradeFormValidationContext): TradeFor const { derivedTradeState, approvalState, - isTxBundlingEnabled, + isBundlingSupported, isWrapUnwrap, isExpertMode, isSupportedWallet, @@ -18,11 +17,13 @@ export function validateTradeForm(context: TradeFormValidationContext): TradeFor recipientEnsAddress, tradeQuote, account, + isPermitSupported, } = context const { inputCurrency, outputCurrency, inputCurrencyAmount, inputCurrencyBalance, recipient } = derivedTradeState - const approvalRequired = approvalState === ApprovalState.NOT_APPROVED || approvalState === ApprovalState.PENDING + const approvalRequired = + !isPermitSupported && (approvalState === ApprovalState.NOT_APPROVED || approvalState === ApprovalState.PENDING) const inputAmountIsNotSet = !inputCurrencyAmount || isFractionFalsy(inputCurrencyAmount) @@ -77,11 +78,8 @@ export function validateTradeForm(context: TradeFormValidationContext): TradeFor } if (approvalRequired) { - if (isTxBundlingEnabled) { - if (isExpertMode) { - return TradeFormValidation.ExpertApproveAndSwap - } - return TradeFormValidation.ApproveAndSwap + if (isBundlingSupported) { + return isExpertMode ? TradeFormValidation.ExpertApproveAndSwap : TradeFormValidation.ApproveAndSwap } return TradeFormValidation.ApproveRequired } diff --git a/apps/cowswap-frontend/src/modules/tradeFormValidation/types.ts b/apps/cowswap-frontend/src/modules/tradeFormValidation/types.ts index f90018345b..5f14fa9cb9 100644 --- a/apps/cowswap-frontend/src/modules/tradeFormValidation/types.ts +++ b/apps/cowswap-frontend/src/modules/tradeFormValidation/types.ts @@ -45,10 +45,11 @@ export interface TradeFormValidationCommonContext { tradeQuote: TradeQuoteState recipientEnsAddress: string | null isWrapUnwrap: boolean - isTxBundlingEnabled: boolean + isBundlingSupported: boolean isSupportedWallet: boolean isSwapUnsupported: boolean isSafeReadonlyUser: boolean + isPermitSupported: boolean } export interface TradeFormValidationContext extends TradeFormValidationLocalContext, TradeFormValidationCommonContext {} diff --git a/apps/cowswap-frontend/src/modules/tradeQuote/hooks/__snapshots__/useTradeQuotePolling.test.tsx.snap b/apps/cowswap-frontend/src/modules/tradeQuote/hooks/__snapshots__/useTradeQuotePolling.test.tsx.snap index 126e1be152..078816dcfa 100644 --- a/apps/cowswap-frontend/src/modules/tradeQuote/hooks/__snapshots__/useTradeQuotePolling.test.tsx.snap +++ b/apps/cowswap-frontend/src/modules/tradeQuote/hooks/__snapshots__/useTradeQuotePolling.test.tsx.snap @@ -1,33 +1,33 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`useTradeQuotePolling() When wallet is NOT connected Then the "useAddress" field in the quote request should be 0x000...0000 1`] = ` +exports[`useTradeQuotePolling() When wallet is NOT connected Then the "useAddress" field in the quote request should be 0x000...0000 1`] = ` { - "amount": "10000000", + "appData": "0xbace6e636671f2df6e59ef1eb4e63dce6b646a70c51b004ae5a07a9fbe4356fc", + "appDataHash": undefined, "buyToken": "0x91056D4A53E1faa1A84306D4deAEc71085394bC8", - "chainId": 1, - "fromDecimals": 18, - "isEthFlow": false, + "from": "0x0000000000000000000000000000000000000000", "kind": "sell", + "partiallyFillable": false, "priceQuality": "optimal", - "receiver": undefined, + "receiver": "0x0000000000000000000000000000000000000000", + "sellAmountBeforeFee": "10000000", "sellToken": "0xB4FBF271143F4FBf7B91A5ded31805e42b2208d6", - "toDecimals": 18, - "userAddress": undefined, + "validTo": undefined, } `; exports[`useTradeQuotePolling() When wallet is connected Then should put account address into "useAddress" field in the quote request 1`] = ` { - "amount": "10000000", + "appData": "0xbace6e636671f2df6e59ef1eb4e63dce6b646a70c51b004ae5a07a9fbe4356fc", + "appDataHash": undefined, "buyToken": "0x91056D4A53E1faa1A84306D4deAEc71085394bC8", - "chainId": 1, - "fromDecimals": 18, - "isEthFlow": false, + "from": "0x333333f332a06ecb5d20d35da44ba07986d6e203", "kind": "sell", + "partiallyFillable": false, "priceQuality": "optimal", "receiver": "0x333333f332a06ecb5d20d35da44ba07986d6e203", + "sellAmountBeforeFee": "10000000", "sellToken": "0xB4FBF271143F4FBf7B91A5ded31805e42b2208d6", - "toDecimals": 18, - "userAddress": "0x333333f332a06ecb5d20d35da44ba07986d6e203", + "validTo": undefined, } `; diff --git a/apps/cowswap-frontend/src/modules/tradeQuote/hooks/useProcessUnsupportedTokenError.ts b/apps/cowswap-frontend/src/modules/tradeQuote/hooks/useProcessUnsupportedTokenError.ts index 9d297e3d6d..6bd3d9a61e 100644 --- a/apps/cowswap-frontend/src/modules/tradeQuote/hooks/useProcessUnsupportedTokenError.ts +++ b/apps/cowswap-frontend/src/modules/tradeQuote/hooks/useProcessUnsupportedTokenError.ts @@ -1,11 +1,11 @@ import { useCallback } from 'react' -import { useAddGpUnsupportedToken } from 'legacy/state/lists/hooks' +import { getQuoteUnsupportedToken } from '@cowprotocol/common-utils' +import { useWalletInfo } from '@cowprotocol/wallet' -import { useWalletInfo } from 'modules/wallet' +import { useAddGpUnsupportedToken } from 'legacy/state/lists/hooks' import GpQuoteError from 'api/gnosisProtocol/errors/QuoteError' -import { getQuoteUnsupportedToken } from 'utils/getQuoteUnsupportedToken' export function useProcessUnsupportedTokenError() { const { chainId } = useWalletInfo() diff --git a/apps/cowswap-frontend/src/modules/tradeQuote/hooks/useQuoteParams.ts b/apps/cowswap-frontend/src/modules/tradeQuote/hooks/useQuoteParams.ts index d0d48b150e..bec2b7f889 100644 --- a/apps/cowswap-frontend/src/modules/tradeQuote/hooks/useQuoteParams.ts +++ b/apps/cowswap-frontend/src/modules/tradeQuote/hooks/useQuoteParams.ts @@ -1,21 +1,23 @@ import { useMemo } from 'react' +import { NATIVE_CURRENCY_BUY_ADDRESS } from '@cowprotocol/common-const' +import { getAddress } from '@cowprotocol/common-utils' +import { useWalletInfo } from '@cowprotocol/wallet' import { CurrencyAmount } from '@uniswap/sdk-core' -import { NATIVE_CURRENCY_BUY_ADDRESS } from 'legacy/constants' +import { LegacyFeeQuoteParams } from 'legacy/state/price/types' +import { useAppData } from 'modules/appData' import { useEnoughBalanceAndAllowance } from 'modules/tokens' import { useDerivedTradeState } from 'modules/trade/hooks/useDerivedTradeState' -import { useWalletInfo } from 'modules/wallet' import { getPriceQuality } from 'api/gnosisProtocol/api' -import { LegacyFeeQuoteParams } from 'api/gnosisProtocol/legacy/types' import { useVerifiedQuotesEnabled } from 'common/hooks/featureFlags/useVerifiedQuotesEnabled' -import { getAddress } from 'utils/getAddress' export function useQuoteParams(amount: string | null): LegacyFeeQuoteParams | undefined { const { chainId, account } = useWalletInfo() const verifiedQuotesEnabled = useVerifiedQuotesEnabled(chainId) + const appData = useAppData() const { state } = useDerivedTradeState() @@ -26,7 +28,7 @@ export function useQuoteParams(amount: string | null): LegacyFeeQuoteParams | un const fromDecimals = inputCurrency?.decimals const toDecimals = outputCurrency?.decimals - const enoughBalance = useEnoughBalanceAndAllowance({ + const { enoughBalance } = useEnoughBalanceAndAllowance({ account, amount: (inputCurrency && amount && CurrencyAmount.fromRawAmount(inputCurrency, amount)) || undefined, }) @@ -46,19 +48,23 @@ export function useQuoteParams(amount: string | null): LegacyFeeQuoteParams | un fromDecimals, isEthFlow: false, priceQuality: getPriceQuality({ verifyQuote: verifiedQuotesEnabled && enoughBalance }), + appData: appData?.fullAppData, + appDataHash: appData?.appDataKeccak256, } return params }, [ + sellToken, + buyToken, amount, - account, - chainId, orderKind, - enoughBalance, - buyToken, - fromDecimals, - sellToken, + chainId, + account, toDecimals, + fromDecimals, + enoughBalance, verifiedQuotesEnabled, + appData?.fullAppData, + appData?.appDataKeccak256, ]) } diff --git a/apps/cowswap-frontend/src/modules/tradeQuote/hooks/useTradeQuotePolling.test.tsx b/apps/cowswap-frontend/src/modules/tradeQuote/hooks/useTradeQuotePolling.test.tsx index b1282614ec..4961fa1015 100644 --- a/apps/cowswap-frontend/src/modules/tradeQuote/hooks/useTradeQuotePolling.test.tsx +++ b/apps/cowswap-frontend/src/modules/tradeQuote/hooks/useTradeQuotePolling.test.tsx @@ -1,40 +1,27 @@ import { ReactNode } from 'react' +import { COW, ZERO_ADDRESS } from '@cowprotocol/common-const' +import { WETH_GOERLI } from '@cowprotocol/common-const' +import { WalletInfo, walletInfoAtom } from '@cowprotocol/wallet' import { CurrencyAmount } from '@uniswap/sdk-core' import { renderHook } from '@testing-library/react-hooks' +import { orderBookApi } from 'cowSdk' import { JotaiTestProvider, WithMockedWeb3 } from 'test-utils' -import { COW } from 'legacy/constants/tokens' -import { WETH_GOERLI } from 'legacy/utils/goerli/constants' - import { LimitOrdersDerivedState, limitOrdersDerivedStateAtom } from 'modules/limitOrders/state/limitOrdersRawStateAtom' -import { useEnoughBalanceAndAllowance } from 'modules/tokens' +import * as tokensModule from 'modules/tokens' import { DEFAULT_TRADE_DERIVED_STATE } from 'modules/trade' -import { WalletInfo } from 'modules/wallet' - -import { getQuote } from 'api/gnosisProtocol/api' import { useTradeQuotePolling } from './useTradeQuotePolling' -import { walletInfoAtom } from '../../wallet/api/state' import { tradeQuoteParamsAtom } from '../state/tradeQuoteParamsAtom' jest.mock('common/hooks/useShouldZeroApprove/useShouldZeroApprove') -jest.mock('legacy/components/analytics/hooks/useGetMarketDimension') - -jest.mock('api/gnosisProtocol/api', () => ({ - ...jest.requireActual('api/gnosisProtocol/api'), - getQuote: jest.fn(), -})) +jest.mock('common/hooks/useGetMarketDimension') -jest.mock('modules/tokens', () => ({ - ...jest.requireActual('modules/tokens'), - useEnoughBalanceAndAllowance: jest.fn(), -})) - -const getQuoteMock = jest.mocked(getQuote) -const useEnoughBalanceAndAllowanceMock = jest.mocked(useEnoughBalanceAndAllowance) +const getQuoteMock = jest.spyOn(orderBookApi, 'getQuote') +const useEnoughBalanceAndAllowanceMock = jest.spyOn(tokensModule, 'useEnoughBalanceAndAllowance') const inputCurrencyAmount = CurrencyAmount.fromRawAmount(WETH_GOERLI, 10_000_000) const outputCurrencyAmount = CurrencyAmount.fromRawAmount(COW[5], 2_000_000) @@ -44,6 +31,7 @@ const walletInfoMock: WalletInfo = { account: '0x333333f332a06ecb5d20d35da44ba07986d6e203', active: true, } + const limitOrdersDerivedStateMock: LimitOrdersDerivedState = { ...DEFAULT_TRADE_DERIVED_STATE, inputCurrency: inputCurrencyAmount.currency, @@ -71,7 +59,7 @@ describe('useTradeQuotePolling()', () => { beforeEach(() => { jest.clearAllMocks() - getQuoteMock.mockReturnValue(new Promise(() => void 0)) + getQuoteMock.mockImplementation(() => new Promise(() => void 0)) useEnoughBalanceAndAllowanceMock.mockReturnValue(true) }) @@ -86,14 +74,14 @@ describe('useTradeQuotePolling()', () => { // Assert const callParams = getQuoteMock.mock.calls[0][0] - expect(callParams.userAddress).toBe(walletInfoMock.account) // useAddress field value + expect(callParams.from).toBe(walletInfoMock.account) // useAddress field value expect(getQuoteMock).toHaveBeenCalledTimes(1) expect(callParams).toMatchSnapshot() }) }) describe('When wallet is NOT connected', () => { - it('Then the "useAddress" field in the quote request should be 0x000...0000', () => { + it('Then the "useAddress" field in the quote request should be 0x000...0000', () => { // Arrange const mocks = [...jotaiMock, [walletInfoAtom, { ...walletInfoMock, account: undefined }]] @@ -103,7 +91,7 @@ describe('useTradeQuotePolling()', () => { // Assert const callParams = getQuoteMock.mock.calls[0][0] - expect(callParams.userAddress).toBe(undefined) // useAddress field value + expect(callParams.from).toBe(ZERO_ADDRESS) // useAddress field value expect(getQuoteMock).toHaveBeenCalledTimes(1) expect(callParams).toMatchSnapshot() }) diff --git a/apps/cowswap-frontend/src/modules/tradeQuote/hooks/useTradeQuotePolling.ts b/apps/cowswap-frontend/src/modules/tradeQuote/hooks/useTradeQuotePolling.ts index 93bceec339..baf4ce96e2 100644 --- a/apps/cowswap-frontend/src/modules/tradeQuote/hooks/useTradeQuotePolling.ts +++ b/apps/cowswap-frontend/src/modules/tradeQuote/hooks/useTradeQuotePolling.ts @@ -1,13 +1,13 @@ import { useAtomValue, useSetAtom } from 'jotai' import { useLayoutEffect, useMemo } from 'react' +import { useDebounce } from '@cowprotocol/common-hooks' +import { onlyResolvesLast } from '@cowprotocol/common-utils' import { OrderQuoteResponse } from '@cowprotocol/cow-sdk' import ms from 'ms.macro' -import useDebounce from 'legacy/hooks/useDebounce' import { useIsUnsupportedTokens } from 'legacy/state/lists/hooks' -import { onlyResolvesLast } from 'legacy/utils/async' import { useUpdateCurrencyAmount } from 'modules/trade/hooks/useUpdateCurrencyAmount' import { updateTradeQuoteAtom } from 'modules/tradeQuote/state/tradeQuoteAtom' diff --git a/apps/cowswap-frontend/src/modules/twap/const.ts b/apps/cowswap-frontend/src/modules/twap/const.ts index 0acd222869..6689eba082 100644 --- a/apps/cowswap-frontend/src/modules/twap/const.ts +++ b/apps/cowswap-frontend/src/modules/twap/const.ts @@ -1,10 +1,9 @@ +import { USDC } from '@cowprotocol/common-const' import { SupportedChainId } from '@cowprotocol/cow-sdk' import { Currency, CurrencyAmount, Percent } from '@uniswap/sdk-core' import ms from 'ms.macro' -import { USDC } from 'legacy/constants/tokens' - import { TwapOrderExecutionInfo, TwapOrderStatus } from './types' export const DEFAULT_TWAP_SLIPPAGE = new Percent(10, 100) // 10% diff --git a/apps/cowswap-frontend/src/modules/twap/containers/ActionButtons/index.tsx b/apps/cowswap-frontend/src/modules/twap/containers/ActionButtons/index.tsx index ee126bb1cc..7dce3c832c 100644 --- a/apps/cowswap-frontend/src/modules/twap/containers/ActionButtons/index.tsx +++ b/apps/cowswap-frontend/src/modules/twap/containers/ActionButtons/index.tsx @@ -1,6 +1,6 @@ import React from 'react' -import { twapConversionAnalytics } from 'legacy/components/analytics/events/twapEvents' +import { twapConversionAnalytics } from '@cowprotocol/analytics' import { useTradeConfirmActions } from 'modules/trade' import { TradeFormButtons, TradeFormValidation } from 'modules/tradeFormValidation' diff --git a/apps/cowswap-frontend/src/modules/twap/containers/TwapConfirmModal/TwapConfirmDetails.tsx b/apps/cowswap-frontend/src/modules/twap/containers/TwapConfirmModal/TwapConfirmDetails.tsx index bb8c04f232..85d0bc2f78 100644 --- a/apps/cowswap-frontend/src/modules/twap/containers/TwapConfirmModal/TwapConfirmDetails.tsx +++ b/apps/cowswap-frontend/src/modules/twap/containers/TwapConfirmModal/TwapConfirmDetails.tsx @@ -1,14 +1,14 @@ import React from 'react' +import { shortenAddress } from '@cowprotocol/common-utils' +import { useWalletInfo } from '@cowprotocol/wallet' + import { isAddress } from 'ethers/lib/utils' import styled from 'styled-components/macro' -import { shortenAddress } from 'legacy/utils' - import { useAdvancedOrdersDerivedState } from 'modules/advancedOrders' import { ConfirmDetailsItem } from 'modules/trade/pure/ConfirmDetailsItem' import { ReviewOrderModalAmountRow } from 'modules/trade/pure/ReviewOrderModalAmountRow' -import { useWalletInfo } from 'modules/wallet' import { PartsState } from '../../state/partsStateAtom' import { deadlinePartsDisplay } from '../../utils/deadlinePartsDisplay' diff --git a/apps/cowswap-frontend/src/modules/twap/containers/TwapFormWarnings/index.tsx b/apps/cowswap-frontend/src/modules/twap/containers/TwapFormWarnings/index.tsx index ac50ad1191..a9b4df69c7 100644 --- a/apps/cowswap-frontend/src/modules/twap/containers/TwapFormWarnings/index.tsx +++ b/apps/cowswap-frontend/src/modules/twap/containers/TwapFormWarnings/index.tsx @@ -1,16 +1,19 @@ -import { useAtomValue } from 'jotai' -import { useSetAtom } from 'jotai' +import { useAtomValue, useSetAtom } from 'jotai' import { useCallback } from 'react' -import { modifySafeHandlerAnalytics } from 'legacy/components/analytics/events/twapEvents' +import { modifySafeHandlerAnalytics } from '@cowprotocol/analytics' +import { useIsSafeViaWc, useWalletInfo } from '@cowprotocol/wallet' import { useTradeRouteContext } from 'modules/trade/hooks/useTradeRouteContext' import { NoImpactWarning } from 'modules/trade/pure/NoImpactWarning' import { useTradeQuoteFeeFiatAmount } from 'modules/tradeQuote' -import { useIsSafeViaWc, useWalletInfo } from 'modules/wallet' import { useShouldZeroApprove } from 'common/hooks/useShouldZeroApprove' -import { BundleTxApprovalBanner } from 'common/pure/InlineBanner/banners' +import { + BannerOrientation, + BundleTxApprovalBanner, + CustomRecipientWarningBanner, +} from 'common/pure/InlineBanner/banners' import { ZeroApprovalWarning } from 'common/pure/ZeroApprovalWarning' import { @@ -79,6 +82,10 @@ export function TwapFormWarnings({ localFormValidation, isConfirmationModal }: T updateTwapOrdersSettings({ isPriceImpactAccepted: !isPriceImpactAccepted }) }, [updateTwapOrdersSettings, isPriceImpactAccepted]) + const { account } = useWalletInfo() + + const showRecipientWarning = isConfirmationModal && twapOrder?.receiver && twapOrder.receiver !== account + // Don't display any warnings while a wallet is not connected if (walletIsNotConnected) return null @@ -103,6 +110,8 @@ export function TwapFormWarnings({ localFormValidation, isConfirmationModal }: T /> )} + {showRecipientWarning && } + {(() => { if (localFormValidation === TwapFormState.NOT_SAFE) { return diff --git a/apps/cowswap-frontend/src/modules/twap/containers/TwapFormWarnings/warnings/FallbackHandlerWarning.tsx b/apps/cowswap-frontend/src/modules/twap/containers/TwapFormWarnings/warnings/FallbackHandlerWarning.tsx index 3c1f277f4e..76be392d47 100644 --- a/apps/cowswap-frontend/src/modules/twap/containers/TwapFormWarnings/warnings/FallbackHandlerWarning.tsx +++ b/apps/cowswap-frontend/src/modules/twap/containers/TwapFormWarnings/warnings/FallbackHandlerWarning.tsx @@ -1,6 +1,6 @@ -import styled from 'styled-components/macro' +import { ExternalLink } from '@cowprotocol/ui' -import { ExternalLink } from 'legacy/theme' +import styled from 'styled-components/macro' import { UNSUPPORTED_SAFE_LINK } from 'modules/twap/const' @@ -74,7 +74,7 @@ export function FallbackHandlerWarning({ if (isFallbackHandlerSetupAccepted) { return ( - + {fallbackHandlerCheckbox} @@ -82,7 +82,7 @@ export function FallbackHandlerWarning({ } else { return ( - + Unsupported Safe detected

Connected Safe lacks required fallback handler. Switch to a compatible Safe or modify fallback handler for diff --git a/apps/cowswap-frontend/src/modules/twap/containers/TwapFormWarnings/warnings/SmallPartVolumeWarning.tsx b/apps/cowswap-frontend/src/modules/twap/containers/TwapFormWarnings/warnings/SmallPartVolumeWarning.tsx index 1d6483ef9f..a72afcfb3b 100644 --- a/apps/cowswap-frontend/src/modules/twap/containers/TwapFormWarnings/warnings/SmallPartVolumeWarning.tsx +++ b/apps/cowswap-frontend/src/modules/twap/containers/TwapFormWarnings/warnings/SmallPartVolumeWarning.tsx @@ -1,7 +1,7 @@ import { SupportedChainId } from '@cowprotocol/cow-sdk' +import { TokenAmount } from '@cowprotocol/ui' import { InlineBanner } from 'common/pure/InlineBanner' -import { TokenAmount } from 'common/pure/TokenAmount' import { MINIMUM_PART_SELL_AMOUNT_FIAT } from '../../../const' diff --git a/apps/cowswap-frontend/src/modules/twap/containers/TwapFormWarnings/warnings/SwapPriceDifferenceWarning.tsx b/apps/cowswap-frontend/src/modules/twap/containers/TwapFormWarnings/warnings/SwapPriceDifferenceWarning.tsx index 22887727a2..5500199b33 100644 --- a/apps/cowswap-frontend/src/modules/twap/containers/TwapFormWarnings/warnings/SwapPriceDifferenceWarning.tsx +++ b/apps/cowswap-frontend/src/modules/twap/containers/TwapFormWarnings/warnings/SwapPriceDifferenceWarning.tsx @@ -1,3 +1,4 @@ +import { FiatAmount, TokenAmount } from '@cowprotocol/ui' import { CurrencyAmount, Token } from '@uniswap/sdk-core' import { NavLink } from 'react-router-dom' @@ -7,9 +8,7 @@ import { TradeUrlParams } from 'modules/trade/types/TradeRawState' import { parameterizeTradeRoute } from 'modules/trade/utils/parameterizeTradeRoute' import { Routes } from 'common/constants/routes' -import { FiatAmount } from 'common/pure/FiatAmount' import { InlineBanner } from 'common/pure/InlineBanner' -import { TokenAmount } from 'common/pure/TokenAmount' import { SwapAmountDifference } from '../../../state/swapAmountDifferenceAtom' @@ -48,7 +47,7 @@ export function SwapPriceDifferenceWarning({ const swapOrderLink = SWAP order return ( - + {isTwapBetter ? ( <> Maximizing Your Gains! {/**/} diff --git a/apps/cowswap-frontend/src/modules/twap/containers/TwapFormWarnings/warnings/UnsupportedWalletWarning.tsx b/apps/cowswap-frontend/src/modules/twap/containers/TwapFormWarnings/warnings/UnsupportedWalletWarning.tsx index 98bcc29203..8f3198794c 100644 --- a/apps/cowswap-frontend/src/modules/twap/containers/TwapFormWarnings/warnings/UnsupportedWalletWarning.tsx +++ b/apps/cowswap-frontend/src/modules/twap/containers/TwapFormWarnings/warnings/UnsupportedWalletWarning.tsx @@ -1,4 +1,4 @@ -import { ExternalLink } from 'legacy/theme' +import { ExternalLink } from '@cowprotocol/ui' import { UNSUPPORTED_WALLET_LINK } from 'modules/twap/const' @@ -8,7 +8,7 @@ import { InlineBanner } from 'common/pure/InlineBanner' export function UnsupportedWalletWarning({ isSafeViaWc }: { isSafeViaWc: boolean }) { if (isSafeViaWc) { return ( - + Use Safe web app

Use the Safe web app for advanced trading.
@@ -19,7 +19,7 @@ export function UnsupportedWalletWarning({ isSafeViaWc }: { isSafeViaWc: boolean } return ( - + Unsupported wallet detected

TWAP orders currently require a Safe with a special fallback handler. Have one? Switch to it! Need setup?{' '} diff --git a/apps/cowswap-frontend/src/modules/twap/containers/TwapFormWidget/index.tsx b/apps/cowswap-frontend/src/modules/twap/containers/TwapFormWidget/index.tsx index 7dbd251409..bfbca0f4ea 100644 --- a/apps/cowswap-frontend/src/modules/twap/containers/TwapFormWidget/index.tsx +++ b/apps/cowswap-frontend/src/modules/twap/containers/TwapFormWidget/index.tsx @@ -1,11 +1,9 @@ import { useAtomValue, useSetAtom } from 'jotai' import { useEffect, useState } from 'react' -import { - openAdvancedOrdersTabAnalytics, - twapWalletCompatibilityAnalytics, -} from 'legacy/components/analytics/events/twapEvents' -import { renderTooltip } from 'legacy/components/Tooltip' +import { openAdvancedOrdersTabAnalytics, twapWalletCompatibilityAnalytics } from '@cowprotocol/analytics' +import { renderTooltip } from '@cowprotocol/ui' +import { useWalletInfo } from '@cowprotocol/wallet' import { useAdvancedOrdersDerivedState, useAdvancedOrdersRawState } from 'modules/advancedOrders' import { useIsWrapOrUnwrap } from 'modules/trade/hooks/useIsWrapOrUnwrap' @@ -14,7 +12,6 @@ import { TradeNumberInput } from 'modules/trade/pure/TradeNumberInput' import { TradeTextBox } from 'modules/trade/pure/TradeTextBox' import { useGetTradeFormValidation } from 'modules/tradeFormValidation' import { TwapFormState } from 'modules/twap/pure/PrimaryActionButton/getTwapFormState' -import { useWalletInfo } from 'modules/wallet' import { usePrice } from 'common/hooks/usePrice' import { useRateInfoParams } from 'common/hooks/useRateInfoParams' diff --git a/apps/cowswap-frontend/src/modules/twap/containers/TwapFormWidget/tooltips.tsx b/apps/cowswap-frontend/src/modules/twap/containers/TwapFormWidget/tooltips.tsx index 6b5aa4f0a5..2568b2652f 100644 --- a/apps/cowswap-frontend/src/modules/twap/containers/TwapFormWidget/tooltips.tsx +++ b/apps/cowswap-frontend/src/modules/twap/containers/TwapFormWidget/tooltips.tsx @@ -1,10 +1,12 @@ +import ShieldImage from '@cowprotocol/assets/cow-swap/protection.svg' + import SVG from 'react-inlinesvg' import styled from 'styled-components/macro' -import ShieldImage from 'legacy/assets/cow-swap/protection.svg' - import { deadlinePartsDisplay } from 'modules/twap/utils/deadlinePartsDisplay' +import { UI } from 'common/constants/theme' + const IconImage = styled.div` display: flex; align-items: center; @@ -12,7 +14,7 @@ const IconImage = styled.div` > svg { opacity: 0.5; - fill: ${({ theme }) => theme.text1}; + fill: var(${UI.COLOR_TEXT1}); margin: 0 3px 0 0; } ` diff --git a/apps/cowswap-frontend/src/modules/twap/hooks/useAllEmulatedOrders.ts b/apps/cowswap-frontend/src/modules/twap/hooks/useAllEmulatedOrders.ts index f8401d28e8..b02315f559 100644 --- a/apps/cowswap-frontend/src/modules/twap/hooks/useAllEmulatedOrders.ts +++ b/apps/cowswap-frontend/src/modules/twap/hooks/useAllEmulatedOrders.ts @@ -1,12 +1,11 @@ import { useMemo } from 'react' import { OrderClass } from '@cowprotocol/cow-sdk' +import { useIsSafeApp, useWalletInfo } from '@cowprotocol/wallet' import { Order } from 'legacy/state/orders/actions' import { useOrders } from 'legacy/state/orders/hooks' -import { useIsSafeApp, useWalletInfo } from 'modules/wallet' - import { useEmulatedPartOrders } from './useEmulatedPartOrders' import { useEmulatedTwapOrders } from './useEmulatedTwapOrders' import { useTwapOrdersTokens } from './useTwapOrdersTokens' diff --git a/apps/cowswap-frontend/src/modules/twap/hooks/useCancelTwapOrder.ts b/apps/cowswap-frontend/src/modules/twap/hooks/useCancelTwapOrder.ts index a9ff3801e8..155f6288b0 100644 --- a/apps/cowswap-frontend/src/modules/twap/hooks/useCancelTwapOrder.ts +++ b/apps/cowswap-frontend/src/modules/twap/hooks/useCancelTwapOrder.ts @@ -1,11 +1,12 @@ import { useAtomValue, useSetAtom } from 'jotai' import { useCallback } from 'react' -import { useGP2SettlementContract } from 'legacy/hooks/useContract' +import { useGP2SettlementContract } from '@cowprotocol/common-hooks' +import { useSafeAppsSdk } from '@cowprotocol/wallet' + import { Order } from 'legacy/state/orders/actions' import { useComposableCowContract } from 'modules/advancedOrders/hooks/useComposableCowContract' -import { useSafeAppsSdk } from 'modules/wallet/web3-react/hooks/useSafeAppsSdk' import type { OnChainCancellation } from 'common/hooks/useCancelOrder/onChainCancellation' diff --git a/apps/cowswap-frontend/src/modules/twap/hooks/useCreateTwapOrder.ts b/apps/cowswap-frontend/src/modules/twap/hooks/useCreateTwapOrder.ts index 28ee879221..72eb4716fb 100644 --- a/apps/cowswap-frontend/src/modules/twap/hooks/useCreateTwapOrder.ts +++ b/apps/cowswap-frontend/src/modules/twap/hooks/useCreateTwapOrder.ts @@ -2,23 +2,22 @@ import { useAtomValue } from 'jotai' import { useSetAtom } from 'jotai' import { useCallback } from 'react' +import { twapConversionAnalytics } from '@cowprotocol/analytics' +import { getCowSoundSend } from '@cowprotocol/common-utils' import { OrderClass, OrderKind } from '@cowprotocol/cow-sdk' +import { useWalletInfo, useSafeAppsSdk } from '@cowprotocol/wallet' import { CurrencyAmount, Token } from '@uniswap/sdk-core' import { Nullish } from 'types' -import { twapConversionAnalytics } from 'legacy/components/analytics/events/twapEvents' -import store from 'legacy/state' +import { cowSwapStore } from 'legacy/state' import { dispatchPresignedOrderPosted } from 'legacy/state/orders/middleware/updateOrderPopup' -import { getCowSoundSend } from 'legacy/utils/sound' import { getOrderSubmitSummary } from 'legacy/utils/trade' import { updateAdvancedOrdersAtom, useAdvancedOrdersDerivedState } from 'modules/advancedOrders' import { useAppData, useUploadAppData } from 'modules/appData' import { useTradeConfirmActions, useTradePriceImpact } from 'modules/trade' import { SwapFlowAnalyticsContext, tradeFlowAnalytics } from 'modules/trade/utils/analytics' -import { useWalletInfo } from 'modules/wallet' -import { useSafeAppsSdk } from 'modules/wallet/web3-react/hooks/useSafeAppsSdk' import { useConfirmPriceImpactWithoutFee } from 'common/hooks/useConfirmPriceImpactWithoutFee' @@ -125,7 +124,7 @@ export function useCreateTwapOrder() { feeAmount: undefined, }) getCowSoundSend().play() - dispatchPresignedOrderPosted(store, safeTxHash, summary, OrderClass.LIMIT, 'composable-order') + dispatchPresignedOrderPosted(cowSwapStore, safeTxHash, summary, OrderClass.LIMIT, 'composable-order') uploadAppData({ chainId, orderId, appData: appDataInfo }) updateAdvancedOrdersState({ recipient: null, recipientAddress: null }) diff --git a/apps/cowswap-frontend/src/modules/twap/hooks/useEmulatedPartOrders.ts b/apps/cowswap-frontend/src/modules/twap/hooks/useEmulatedPartOrders.ts index 9b905e89bb..a8736ee5f8 100644 --- a/apps/cowswap-frontend/src/modules/twap/hooks/useEmulatedPartOrders.ts +++ b/apps/cowswap-frontend/src/modules/twap/hooks/useEmulatedPartOrders.ts @@ -1,9 +1,10 @@ import { useAtomValue } from 'jotai' import { useMemo } from 'react' +import { useMachineTimeMs } from '@cowprotocol/common-hooks' + import ms from 'ms.macro' -import useMachineTimeMs from 'legacy/hooks/useMachineTime' import { Order } from 'legacy/state/orders/actions' import { TokensByAddress } from 'modules/tokensList/state/tokensListAtom' diff --git a/apps/cowswap-frontend/src/modules/twap/hooks/useEmulatedTwapOrders.ts b/apps/cowswap-frontend/src/modules/twap/hooks/useEmulatedTwapOrders.ts index 5227eb682d..17dc8e82f9 100644 --- a/apps/cowswap-frontend/src/modules/twap/hooks/useEmulatedTwapOrders.ts +++ b/apps/cowswap-frontend/src/modules/twap/hooks/useEmulatedTwapOrders.ts @@ -1,13 +1,14 @@ import { useAtomValue } from 'jotai' import { useMemo } from 'react' +import { useMachineTimeMs } from '@cowprotocol/common-hooks' +import { useWalletInfo } from '@cowprotocol/wallet' + import ms from 'ms.macro' -import useMachineTimeMs from 'legacy/hooks/useMachineTime' import { Order } from 'legacy/state/orders/actions' import { TokensByAddress } from 'modules/tokensList/state/tokensListAtom' -import { useWalletInfo } from 'modules/wallet' import { twapOrdersListAtom } from '../state/twapOrdersListAtom' import { mapTwapOrderToStoreOrder } from '../utils/mapTwapOrderToStoreOrder' @@ -27,10 +28,13 @@ export function useEmulatedTwapOrders(tokensByAddress: TokensByAddress | undefin if (!refresher) return [] if (!tokensByAddress) return [] - return allTwapOrders - .filter((order) => order.chainId === chainId && order.safeAddress.toLowerCase() === accountLowerCase) - .map((order) => { - return mapTwapOrderToStoreOrder(order, tokensByAddress) - }) + return allTwapOrders.reduce((acc, order) => { + if (order.chainId !== chainId || order.safeAddress.toLowerCase() !== accountLowerCase) { + return acc + } + + acc.push(mapTwapOrderToStoreOrder(order, tokensByAddress)) + return acc + }, []) }, [allTwapOrders, accountLowerCase, chainId, tokensByAddress, refresher]) } diff --git a/apps/cowswap-frontend/src/modules/twap/hooks/useExtensibleFallbackContext.ts b/apps/cowswap-frontend/src/modules/twap/hooks/useExtensibleFallbackContext.ts index e4891ad27b..1d5fccb200 100644 --- a/apps/cowswap-frontend/src/modules/twap/hooks/useExtensibleFallbackContext.ts +++ b/apps/cowswap-frontend/src/modules/twap/hooks/useExtensibleFallbackContext.ts @@ -1,12 +1,10 @@ +import { GPv2Settlement } from '@cowprotocol/abis' +import { useGP2SettlementContract } from '@cowprotocol/common-hooks' import { SupportedChainId } from '@cowprotocol/cow-sdk' -import { GPv2Settlement } from '@cowswap/abis' +import { useWalletInfo } from '@cowprotocol/wallet' import { Web3Provider } from '@ethersproject/providers' import { useWeb3React } from '@web3-react/core' -import { useGP2SettlementContract } from 'legacy/hooks/useContract' - -import { useWalletInfo } from 'modules/wallet' - export interface ExtensibleFallbackContext { safeAddress: string chainId: SupportedChainId diff --git a/apps/cowswap-frontend/src/modules/twap/hooks/useFallbackHandlerVerification.ts b/apps/cowswap-frontend/src/modules/twap/hooks/useFallbackHandlerVerification.ts index 6c4ab260e4..a849e84a1c 100644 --- a/apps/cowswap-frontend/src/modules/twap/hooks/useFallbackHandlerVerification.ts +++ b/apps/cowswap-frontend/src/modules/twap/hooks/useFallbackHandlerVerification.ts @@ -1,6 +1,6 @@ import { useAtomValue } from 'jotai' -import { useWalletInfo } from 'modules/wallet' +import { useWalletInfo } from '@cowprotocol/wallet' import { ExtensibleFallbackVerification } from '../services/verifyExtensibleFallback' import { fallbackHandlerVerificationAtom } from '../state/fallbackHandlerVerificationAtom' diff --git a/apps/cowswap-frontend/src/modules/twap/hooks/useFetchTwapOrdersFromSafe.ts b/apps/cowswap-frontend/src/modules/twap/hooks/useFetchTwapOrdersFromSafe.ts index 7903898d73..e003d79c2b 100644 --- a/apps/cowswap-frontend/src/modules/twap/hooks/useFetchTwapOrdersFromSafe.ts +++ b/apps/cowswap-frontend/src/modules/twap/hooks/useFetchTwapOrdersFromSafe.ts @@ -1,10 +1,10 @@ import { useEffect, useState } from 'react' -import { ComposableCoW } from '@cowswap/abis' +import { ComposableCoW } from '@cowprotocol/abis' import ms from 'ms.macro' -import { useSafeApiKit } from 'api/gnosisSafe/hooks/useSafeApiKit' +import { useSafeApiKit } from 'common/hooks/useSafeApiKit' import { fetchTwapOrdersFromSafe } from '../services/fetchTwapOrdersFromSafe' import { TwapOrdersSafeData } from '../types' diff --git a/apps/cowswap-frontend/src/modules/twap/hooks/useSetupTwapAmountsFromUrls.ts b/apps/cowswap-frontend/src/modules/twap/hooks/useSetupTwapAmountsFromUrls.ts index 5b4d408c4a..613568ffc4 100644 --- a/apps/cowswap-frontend/src/modules/twap/hooks/useSetupTwapAmountsFromUrls.ts +++ b/apps/cowswap-frontend/src/modules/twap/hooks/useSetupTwapAmountsFromUrls.ts @@ -1,13 +1,13 @@ import { useCallback, useLayoutEffect, useMemo } from 'react' +import { getIntOrFloat } from '@cowprotocol/common-utils' + import { useLocation, useNavigate } from 'react-router-dom' -import { Field } from 'legacy/state/swap/actions' +import { Field } from 'legacy/state/types' import { TRADE_URL_BUY_AMOUNT_KEY, TRADE_URL_SELL_AMOUNT_KEY } from 'modules/trade/const/tradeUrl' -import { getIntOrFloat } from 'utils/getIntOrFloat' - import { useAdvancedOrdersActions } from '../../advancedOrders/hooks/useAdvancedOrdersActions' // TODO: unify into a single thing for all forms diff --git a/apps/cowswap-frontend/src/modules/twap/hooks/useTwapFormState.ts b/apps/cowswap-frontend/src/modules/twap/hooks/useTwapFormState.ts index 360378d170..f6a693c42c 100644 --- a/apps/cowswap-frontend/src/modules/twap/hooks/useTwapFormState.ts +++ b/apps/cowswap-frontend/src/modules/twap/hooks/useTwapFormState.ts @@ -1,7 +1,7 @@ import { useAtomValue } from 'jotai' import { useMemo } from 'react' -import { useIsSafeApp, useWalletInfo } from 'modules/wallet' +import { useIsSafeApp, useWalletInfo } from '@cowprotocol/wallet' import { useFallbackHandlerVerification } from './useFallbackHandlerVerification' diff --git a/apps/cowswap-frontend/src/modules/twap/hooks/useTwapOrderCreationContext.ts b/apps/cowswap-frontend/src/modules/twap/hooks/useTwapOrderCreationContext.ts index d23df78b79..377502dac3 100644 --- a/apps/cowswap-frontend/src/modules/twap/hooks/useTwapOrderCreationContext.ts +++ b/apps/cowswap-frontend/src/modules/twap/hooks/useTwapOrderCreationContext.ts @@ -1,13 +1,12 @@ -import { ComposableCoW, Erc20 } from '@cowswap/abis' +import { ComposableCoW, Erc20 } from '@cowprotocol/abis' +import { useTokenContract } from '@cowprotocol/common-hooks' +import { useWalletInfo } from '@cowprotocol/wallet' import { CurrencyAmount, Token } from '@uniswap/sdk-core' import { Nullish } from 'types' -import { useTokenContract } from 'legacy/hooks/useContract' - import { CURRENT_BLOCK_FACTORY_ADDRESS } from 'modules/advancedOrders' import { useComposableCowContract } from 'modules/advancedOrders/hooks/useComposableCowContract' -import { useWalletInfo } from 'modules/wallet' import { useNeedsApproval } from 'common/hooks/useNeedsApproval' import { useNeedsZeroApproval } from 'common/hooks/useNeedsZeroApproval' diff --git a/apps/cowswap-frontend/src/modules/twap/hooks/useTwapOrdersAuthMulticall.ts b/apps/cowswap-frontend/src/modules/twap/hooks/useTwapOrdersAuthMulticall.ts index 508d091c98..4f39c7570a 100644 --- a/apps/cowswap-frontend/src/modules/twap/hooks/useTwapOrdersAuthMulticall.ts +++ b/apps/cowswap-frontend/src/modules/twap/hooks/useTwapOrdersAuthMulticall.ts @@ -1,6 +1,6 @@ import { useMemo } from 'react' -import { ComposableCoW } from '@cowswap/abis' +import { ComposableCoW } from '@cowprotocol/abis' import { ListenerOptionsWithGas } from '@uniswap/redux-multicall' import { useSingleContractMultipleData } from 'lib/hooks/multicall' diff --git a/apps/cowswap-frontend/src/modules/twap/hooks/useTwapOrdersExecutions.ts b/apps/cowswap-frontend/src/modules/twap/hooks/useTwapOrdersExecutions.ts index 5792ce6dd6..f258eb030f 100644 --- a/apps/cowswap-frontend/src/modules/twap/hooks/useTwapOrdersExecutions.ts +++ b/apps/cowswap-frontend/src/modules/twap/hooks/useTwapOrdersExecutions.ts @@ -1,11 +1,11 @@ import { useAtomValue } from 'jotai' import { useMemo } from 'react' +import { useWalletInfo } from '@cowprotocol/wallet' + import { Order, OrderInfoApi } from 'legacy/state/orders/actions' import { useOrdersById } from 'legacy/state/orders/hooks' -import { useWalletInfo } from 'modules/wallet' - import { getIsFinalizedOrder } from 'utils/orderUtils/getIsFinalizedOrder' import { DEFAULT_TWAP_EXECUTION_INFO } from '../const' diff --git a/apps/cowswap-frontend/src/modules/twap/hooks/useTwapOrdersTradeableMulticall.ts b/apps/cowswap-frontend/src/modules/twap/hooks/useTwapOrdersTradeableMulticall.ts index 0b759dc5fa..458b109c44 100644 --- a/apps/cowswap-frontend/src/modules/twap/hooks/useTwapOrdersTradeableMulticall.ts +++ b/apps/cowswap-frontend/src/modules/twap/hooks/useTwapOrdersTradeableMulticall.ts @@ -1,6 +1,6 @@ import { useMemo } from 'react' -import { ComposableCoW, GPv2Order } from '@cowswap/abis' +import { ComposableCoW, GPv2Order } from '@cowprotocol/abis' import { ListenerOptionsWithGas } from '@uniswap/redux-multicall' import { useSingleContractMultipleData } from 'lib/hooks/multicall' diff --git a/apps/cowswap-frontend/src/modules/twap/hooks/useTwapWarningsContext.ts b/apps/cowswap-frontend/src/modules/twap/hooks/useTwapWarningsContext.ts index 6b1d38ac00..b02275864d 100644 --- a/apps/cowswap-frontend/src/modules/twap/hooks/useTwapWarningsContext.ts +++ b/apps/cowswap-frontend/src/modules/twap/hooks/useTwapWarningsContext.ts @@ -1,8 +1,9 @@ import { useMemo } from 'react' +import { useWalletInfo } from '@cowprotocol/wallet' + import { useTradePriceImpact } from 'modules/trade' import { TradeFormValidation, useGetTradeFormValidation } from 'modules/tradeFormValidation' -import { useWalletInfo } from 'modules/wallet' const NOT_BLOCKING_VALIDATIONS = [ TradeFormValidation.ExpertApproveAndSwap, diff --git a/apps/cowswap-frontend/src/modules/twap/pure/AmountParts/index.tsx b/apps/cowswap-frontend/src/modules/twap/pure/AmountParts/index.tsx index 0a779625b8..282d52ed9c 100644 --- a/apps/cowswap-frontend/src/modules/twap/pure/AmountParts/index.tsx +++ b/apps/cowswap-frontend/src/modules/twap/pure/AmountParts/index.tsx @@ -1,12 +1,12 @@ import React, { ReactNode } from 'react' +import { renderTooltip } from '@cowprotocol/ui' import { Currency, CurrencyAmount } from '@uniswap/sdk-core' import { Trans } from '@lingui/macro' import { Nullish } from 'types' import QuestionHelper from 'legacy/components/QuestionHelper' -import { renderTooltip } from 'legacy/components/Tooltip' import { LabelTooltipItems } from 'modules/twap' diff --git a/apps/cowswap-frontend/src/modules/twap/pure/AmountParts/styled.tsx b/apps/cowswap-frontend/src/modules/twap/pure/AmountParts/styled.tsx index e753097f32..f27a19a309 100644 --- a/apps/cowswap-frontend/src/modules/twap/pure/AmountParts/styled.tsx +++ b/apps/cowswap-frontend/src/modules/twap/pure/AmountParts/styled.tsx @@ -1,3 +1,5 @@ +import { FiatAmount, TokenAmount } from '@cowprotocol/ui' + import { transparentize } from 'polished' import styled from 'styled-components/macro' @@ -5,9 +7,6 @@ import { QuestionWrapper } from 'legacy/components/QuestionHelper' import { TradeWidgetFieldBox, TradeWidgetFieldLabel } from 'modules/trade/pure/TradeWidgetField/styled' -import { FiatAmount } from 'common/pure/FiatAmount' -import { TokenAmount } from 'common/pure/TokenAmount' - export const Wrapper = styled.div` display: flex; grid-gap: 8px; diff --git a/apps/cowswap-frontend/src/modules/twap/pure/CustomDeadlineSelector/index.tsx b/apps/cowswap-frontend/src/modules/twap/pure/CustomDeadlineSelector/index.tsx index dac48a0d12..244e0441c4 100644 --- a/apps/cowswap-frontend/src/modules/twap/pure/CustomDeadlineSelector/index.tsx +++ b/apps/cowswap-frontend/src/modules/twap/pure/CustomDeadlineSelector/index.tsx @@ -1,10 +1,10 @@ import { useCallback, useEffect, useState } from 'react' +import { ButtonPrimary } from '@cowprotocol/ui' + import { Trans } from '@lingui/macro' import ms from 'ms' -import { ButtonPrimary } from 'legacy/components/Button' - import { TradeNumberInput } from 'modules/trade/pure/TradeNumberInput' import { CowModal as Modal } from 'common/pure/Modal' diff --git a/apps/cowswap-frontend/src/modules/twap/pure/CustomDeadlineSelector/styled.tsx b/apps/cowswap-frontend/src/modules/twap/pure/CustomDeadlineSelector/styled.tsx index 7257c673ac..7579d35386 100644 --- a/apps/cowswap-frontend/src/modules/twap/pure/CustomDeadlineSelector/styled.tsx +++ b/apps/cowswap-frontend/src/modules/twap/pure/CustomDeadlineSelector/styled.tsx @@ -1,11 +1,13 @@ +import { ButtonSecondary } from '@cowprotocol/ui' + import { X } from 'react-feather' import styled from 'styled-components/macro' -import { ButtonSecondary } from 'legacy/components/Button' - import { NumericalInput } from 'modules/trade/pure/TradeNumberInput/styled' import { TradeWidgetFieldBox } from 'modules/trade/pure/TradeWidgetField/styled' +import { UI } from 'common/constants/theme' + export const ModalWrapper = styled.div` display: flex; flex-flow: column wrap; @@ -70,18 +72,18 @@ export const CloseIcon = styled(X)` } > line { - stroke: ${({ theme }) => theme.text1}; + stroke: var(${UI.COLOR_TEXT1}); } ` export const CancelButton = styled(ButtonSecondary)` background: transparent; - color: ${({ theme }) => theme.text1}; + color: var(${UI.COLOR_TEXT1}); border: 1px solid ${({ theme }) => theme.text1}; :hover { background: transparent; - color: ${({ theme }) => theme.text1}; + color: var(${UI.COLOR_TEXT1}); border: 1px solid ${({ theme }) => theme.text1}; } ` diff --git a/apps/cowswap-frontend/src/modules/twap/pure/DeadlineSelector/index.tsx b/apps/cowswap-frontend/src/modules/twap/pure/DeadlineSelector/index.tsx index 36260920b4..7ae76f2cf3 100644 --- a/apps/cowswap-frontend/src/modules/twap/pure/DeadlineSelector/index.tsx +++ b/apps/cowswap-frontend/src/modules/twap/pure/DeadlineSelector/index.tsx @@ -1,8 +1,8 @@ import React, { useCallback, useMemo, useState } from 'react' -import styled from 'styled-components/macro' +import { renderTooltip } from '@cowprotocol/ui' -import { renderTooltip } from 'legacy/components/Tooltip' +import styled from 'styled-components/macro' import { TradeSelect, TradeSelectItem } from 'modules/trade/pure/TradeSelect' import { Content } from 'modules/trade/pure/TradeWidgetField/styled' diff --git a/apps/cowswap-frontend/src/modules/twap/pure/PrimaryActionButton/getTwapFormState.test.ts b/apps/cowswap-frontend/src/modules/twap/pure/PrimaryActionButton/getTwapFormState.test.ts index 64747a4f5e..18a51eb043 100644 --- a/apps/cowswap-frontend/src/modules/twap/pure/PrimaryActionButton/getTwapFormState.test.ts +++ b/apps/cowswap-frontend/src/modules/twap/pure/PrimaryActionButton/getTwapFormState.test.ts @@ -1,8 +1,7 @@ +import { COW } from '@cowprotocol/common-const' +import { WETH_GOERLI } from '@cowprotocol/common-const' import { CurrencyAmount } from '@uniswap/sdk-core' -import { COW } from 'legacy/constants/tokens' -import { WETH_GOERLI } from 'legacy/utils/goerli/constants' - import { getTwapFormState, TwapFormState } from './getTwapFormState' import { ExtensibleFallbackVerification } from '../../services/verifyExtensibleFallback' diff --git a/apps/cowswap-frontend/src/modules/twap/pure/PrimaryActionButton/getTwapFormState.tsx b/apps/cowswap-frontend/src/modules/twap/pure/PrimaryActionButton/getTwapFormState.tsx index 99e058b2ab..0d3e73c5b7 100644 --- a/apps/cowswap-frontend/src/modules/twap/pure/PrimaryActionButton/getTwapFormState.tsx +++ b/apps/cowswap-frontend/src/modules/twap/pure/PrimaryActionButton/getTwapFormState.tsx @@ -1,10 +1,9 @@ +import { isFractionFalsy } from '@cowprotocol/common-utils' import { SupportedChainId } from '@cowprotocol/cow-sdk' import { Currency, CurrencyAmount } from '@uniswap/sdk-core' import { Nullish } from 'types' -import { isFractionFalsy } from 'utils/isFractionFalsy' - import { ExtensibleFallbackVerification } from '../../services/verifyExtensibleFallback' import { TWAPOrder } from '../../types' import { isPartTimeIntervalTooShort } from '../../utils/isPartTimeIntervalTooShort' diff --git a/apps/cowswap-frontend/src/modules/twap/pure/PrimaryActionButton/index.tsx b/apps/cowswap-frontend/src/modules/twap/pure/PrimaryActionButton/index.tsx index f7072b0064..1be765d11e 100644 --- a/apps/cowswap-frontend/src/modules/twap/pure/PrimaryActionButton/index.tsx +++ b/apps/cowswap-frontend/src/modules/twap/pure/PrimaryActionButton/index.tsx @@ -1,7 +1,6 @@ import React from 'react' -import { ButtonPrimary } from 'legacy/components/Button' -import { ButtonSize } from 'legacy/theme/enum' +import { ButtonSize, ButtonPrimary } from '@cowprotocol/ui' import { TwapFormState } from './getTwapFormState' diff --git a/apps/cowswap-frontend/src/modules/twap/services/cancelTwapOrderTxs.ts b/apps/cowswap-frontend/src/modules/twap/services/cancelTwapOrderTxs.ts index a0ce440609..b7ae0ca152 100644 --- a/apps/cowswap-frontend/src/modules/twap/services/cancelTwapOrderTxs.ts +++ b/apps/cowswap-frontend/src/modules/twap/services/cancelTwapOrderTxs.ts @@ -1,4 +1,4 @@ -import { ComposableCoW, GPv2Settlement } from '@cowswap/abis' +import { ComposableCoW, GPv2Settlement } from '@cowprotocol/abis' import { BigNumber } from '@ethersproject/bignumber' import { MetaTransactionData } from '@safe-global/safe-core-sdk-types' diff --git a/apps/cowswap-frontend/src/modules/twap/services/createTwapOrderTxs.test.ts b/apps/cowswap-frontend/src/modules/twap/services/createTwapOrderTxs.test.ts index 24c24db14b..950ee1da98 100644 --- a/apps/cowswap-frontend/src/modules/twap/services/createTwapOrderTxs.test.ts +++ b/apps/cowswap-frontend/src/modules/twap/services/createTwapOrderTxs.test.ts @@ -1,9 +1,7 @@ +import { COW, WETH_GOERLI } from '@cowprotocol/common-const' import { SupportedChainId } from '@cowprotocol/cow-sdk' import { CurrencyAmount } from '@uniswap/sdk-core' -import { COW } from 'legacy/constants/tokens' -import { WETH_GOERLI } from 'legacy/utils/goerli/constants' - import { COMPOSABLE_COW_ADDRESS, CURRENT_BLOCK_FACTORY_ADDRESS } from 'modules/advancedOrders' import { getAppData } from 'modules/appData' @@ -13,6 +11,8 @@ import { TwapOrderCreationContext } from '../hooks/useTwapOrderCreationContext' import { TWAPOrder } from '../types' import { buildTwapOrderParamsStruct } from '../utils/buildTwapOrderParamsStruct' +jest.mock('modules/permit') + const APP_DATA_HASH = getAppData().appDataKeccak256 const chainId = SupportedChainId.GOERLI diff --git a/apps/cowswap-frontend/src/modules/twap/services/fetchTwapOrdersFromSafe.ts b/apps/cowswap-frontend/src/modules/twap/services/fetchTwapOrdersFromSafe.ts index b4e2b04805..17c721c6ba 100644 --- a/apps/cowswap-frontend/src/modules/twap/services/fetchTwapOrdersFromSafe.ts +++ b/apps/cowswap-frontend/src/modules/twap/services/fetchTwapOrdersFromSafe.ts @@ -1,12 +1,11 @@ -import { ComposableCoW } from '@cowswap/abis' +import { ComposableCoW } from '@cowprotocol/abis' +import { delay, isTruthy } from '@cowprotocol/common-utils' import type SafeApiKit from '@safe-global/api-kit' import type { AllTransactionsListResponse } from '@safe-global/api-kit' import type { SafeMultisigTransactionResponse } from '@safe-global/safe-core-sdk-types' import ms from 'ms.macro' -import { delay, isTruthy } from 'legacy/utils/misc' - import { SafeTransactionParams } from 'common/types' import { ConditionalOrderParams, TwapOrdersSafeData } from '../types' diff --git a/apps/cowswap-frontend/src/modules/twap/services/getSignatureVerifierContract.ts b/apps/cowswap-frontend/src/modules/twap/services/getSignatureVerifierContract.ts index a67d80ff0a..d75e61d9f9 100644 --- a/apps/cowswap-frontend/src/modules/twap/services/getSignatureVerifierContract.ts +++ b/apps/cowswap-frontend/src/modules/twap/services/getSignatureVerifierContract.ts @@ -1,4 +1,4 @@ -import { SignatureVerifierMuxerAbi, SignatureVerifierMuxer } from '@cowswap/abis' +import { SignatureVerifierMuxerAbi, SignatureVerifierMuxer } from '@cowprotocol/abis' import { Contract } from '@ethersproject/contracts' import { ExtensibleFallbackContext } from '../hooks/useExtensibleFallbackContext' diff --git a/apps/cowswap-frontend/src/legacy/state/orders/middleware/composableOrdersPopupMiddleware.ts b/apps/cowswap-frontend/src/modules/twap/state/composableOrdersPopupMiddleware.ts similarity index 64% rename from apps/cowswap-frontend/src/legacy/state/orders/middleware/composableOrdersPopupMiddleware.ts rename to apps/cowswap-frontend/src/modules/twap/state/composableOrdersPopupMiddleware.ts index 80e9f25e42..eb9c3673ea 100644 --- a/apps/cowswap-frontend/src/legacy/state/orders/middleware/composableOrdersPopupMiddleware.ts +++ b/apps/cowswap-frontend/src/modules/twap/state/composableOrdersPopupMiddleware.ts @@ -1,18 +1,18 @@ +import { isTruthy } from '@cowprotocol/common-utils' +import { jotaiStore } from '@cowprotocol/core' + import { isAnyOf } from '@reduxjs/toolkit' -import { jotaiStore } from 'jotaiStore' import { Middleware } from 'redux' -import { isTruthy } from 'legacy/utils/misc' - -import { tokensByAddressAtom } from 'modules/tokensList/state/tokensListAtom' -import { setTwapOrderStatusAtom, twapOrdersAtom } from 'modules/twap/state/twapOrdersListAtom' -import { TwapOrderStatus } from 'modules/twap/types' -import { mapTwapOrderToStoreOrder } from 'modules/twap/utils/mapTwapOrderToStoreOrder' +import { AppState } from 'legacy/state' +import { cancelOrdersBatch } from 'legacy/state/orders/actions' +import { batchCancelOrdersPopup } from 'legacy/state/orders/middleware/batchCancelOrdersPopup' -import { batchCancelOrdersPopup } from './batchCancelOrdersPopup' +import { setTwapOrderStatusAtom, twapOrdersAtom } from './twapOrdersListAtom' -import { AppState } from '../../index' -import { cancelOrdersBatch } from '../actions' +import { tokensByAddressAtom } from '../../tokensList/state/tokensListAtom' +import { TwapOrderStatus } from '../types' +import { mapTwapOrderToStoreOrder } from '../utils/mapTwapOrderToStoreOrder' const isCancelOrdersBatch = isAnyOf(cancelOrdersBatch) diff --git a/apps/cowswap-frontend/src/modules/twap/state/fallbackHandlerVerificationAtom.ts b/apps/cowswap-frontend/src/modules/twap/state/fallbackHandlerVerificationAtom.ts index eee1e16545..50733c8c1a 100644 --- a/apps/cowswap-frontend/src/modules/twap/state/fallbackHandlerVerificationAtom.ts +++ b/apps/cowswap-frontend/src/modules/twap/state/fallbackHandlerVerificationAtom.ts @@ -1,6 +1,6 @@ import { atomWithStorage } from 'jotai/utils' -import { atomWithPartialUpdate } from 'utils/jotai/atomWithPartialUpdate' +import { atomWithPartialUpdate } from '@cowprotocol/common-utils' import { ExtensibleFallbackVerification } from '../services/verifyExtensibleFallback' diff --git a/apps/cowswap-frontend/src/modules/twap/state/swapAmountDifferenceAtom.ts b/apps/cowswap-frontend/src/modules/twap/state/swapAmountDifferenceAtom.ts index ea71c92d27..29ef390c9a 100644 --- a/apps/cowswap-frontend/src/modules/twap/state/swapAmountDifferenceAtom.ts +++ b/apps/cowswap-frontend/src/modules/twap/state/swapAmountDifferenceAtom.ts @@ -1,9 +1,8 @@ import { atom } from 'jotai' +import { isFractionFalsy } from '@cowprotocol/common-utils' import { Currency, CurrencyAmount, Percent } from '@uniswap/sdk-core' -import { isFractionFalsy } from 'utils/isFractionFalsy' - import { fullAmountQuoteAtom } from './fullAmountQuoteAtom' import { partsStateAtom } from './partsStateAtom' diff --git a/apps/cowswap-frontend/src/modules/twap/state/twapOrderAtom.ts b/apps/cowswap-frontend/src/modules/twap/state/twapOrderAtom.ts index 490c60da70..5c8a389f26 100644 --- a/apps/cowswap-frontend/src/modules/twap/state/twapOrderAtom.ts +++ b/apps/cowswap-frontend/src/modules/twap/state/twapOrderAtom.ts @@ -1,11 +1,11 @@ import { atom } from 'jotai' +import { walletInfoAtom } from '@cowprotocol/wallet' import { CurrencyAmount, Token } from '@uniswap/sdk-core' import { advancedOrdersDerivedStateAtom } from 'modules/advancedOrders' import { getAppData } from 'modules/appData' import { appDataInfoAtom } from 'modules/appData/state/atoms' -import { walletInfoAtom } from 'modules/wallet/api/state' import { twapOrderSlippageAtom, twapOrdersSettingsAtom } from './twapOrdersSettingsAtom' diff --git a/apps/cowswap-frontend/src/modules/twap/state/twapOrdersListAtom.ts b/apps/cowswap-frontend/src/modules/twap/state/twapOrdersListAtom.ts index 76d7ae9e15..3899fa26bd 100644 --- a/apps/cowswap-frontend/src/modules/twap/state/twapOrdersListAtom.ts +++ b/apps/cowswap-frontend/src/modules/twap/state/twapOrdersListAtom.ts @@ -1,15 +1,13 @@ import { atom } from 'jotai' import { atomWithStorage } from 'jotai/utils' -import { getJotaiIsolatedStorage } from 'jotaiStore' +import { deepEqual } from '@cowprotocol/common-utils' +import { getJotaiIsolatedStorage } from '@cowprotocol/core' +import { walletInfoAtom } from '@cowprotocol/wallet' -import store from 'legacy/state' +import { cowSwapStore } from 'legacy/state' import { deleteOrders } from 'legacy/state/orders/actions' -import { walletInfoAtom } from 'modules/wallet/api/state' - -import { deepEqual } from 'utils/deepEqual' - import { TWAP_FINAL_STATUSES } from '../const' import { TwapOrderItem, TwapOrderStatus } from '../types' import { updateTwapOrdersList } from '../utils/updateTwapOrdersList' @@ -55,7 +53,7 @@ export const deleteTwapOrdersFromListAtom = atom(null, (get, set, ids: string[]) delete currentState[id] }) - store.dispatch(deleteOrders({ chainId, ids })) + cowSwapStore.dispatch(deleteOrders({ chainId, ids })) set(twapOrdersAtom, currentState) }) diff --git a/apps/cowswap-frontend/src/modules/twap/state/twapOrdersSettingsAtom.ts b/apps/cowswap-frontend/src/modules/twap/state/twapOrdersSettingsAtom.ts index 694c0e4042..faaecd4b8d 100644 --- a/apps/cowswap-frontend/src/modules/twap/state/twapOrdersSettingsAtom.ts +++ b/apps/cowswap-frontend/src/modules/twap/state/twapOrdersSettingsAtom.ts @@ -1,9 +1,9 @@ import { atom } from 'jotai' import { atomWithStorage } from 'jotai/utils' +import { getJotaiIsolatedStorage } from '@cowprotocol/core' import { Percent } from '@uniswap/sdk-core' -import { getJotaiIsolatedStorage } from 'jotaiStore' import { Milliseconds } from 'types' import { DEFAULT_NUM_OF_PARTS, DEFAULT_ORDER_DEADLINE, DEFAULT_TWAP_SLIPPAGE } from '../const' diff --git a/apps/cowswap-frontend/src/modules/twap/state/twapPartOrdersAtom.ts b/apps/cowswap-frontend/src/modules/twap/state/twapPartOrdersAtom.ts index 0e345fd116..d7423130c7 100644 --- a/apps/cowswap-frontend/src/modules/twap/state/twapPartOrdersAtom.ts +++ b/apps/cowswap-frontend/src/modules/twap/state/twapPartOrdersAtom.ts @@ -1,13 +1,10 @@ import { atom } from 'jotai' import { atomWithStorage } from 'jotai/utils' +import { deepEqual } from '@cowprotocol/common-utils' +import { getJotaiIsolatedStorage } from '@cowprotocol/core' import { OrderParameters, SupportedChainId } from '@cowprotocol/cow-sdk' - -import { getJotaiIsolatedStorage } from 'jotaiStore' - -import { walletInfoAtom } from 'modules/wallet/api/state' - -import { deepEqual } from 'utils/deepEqual' +import { walletInfoAtom } from '@cowprotocol/wallet' export interface TwapPartOrderItem { uid: string diff --git a/apps/cowswap-frontend/src/modules/twap/updaters/CreatedInOrderBookOrdersUpdater.tsx b/apps/cowswap-frontend/src/modules/twap/updaters/CreatedInOrderBookOrdersUpdater.tsx index b721894cbf..2317c59b22 100644 --- a/apps/cowswap-frontend/src/modules/twap/updaters/CreatedInOrderBookOrdersUpdater.tsx +++ b/apps/cowswap-frontend/src/modules/twap/updaters/CreatedInOrderBookOrdersUpdater.tsx @@ -3,13 +3,13 @@ import { useSetAtom } from 'jotai' import { useEffect, useMemo } from 'react' import { EnrichedOrder } from '@cowprotocol/cow-sdk' +import { useWalletInfo } from '@cowprotocol/wallet' import { useAsyncMemo } from 'use-async-memo' import { useAddOrUpdateOrders } from 'legacy/state/orders/hooks' import { useTokensForOrdersList, getTokensListFromOrders, useSWRProdOrders } from 'modules/orders' -import { useWalletInfo } from 'modules/wallet' import { twapOrdersAtom } from '../state/twapOrdersListAtom' import { TwapPartOrderItem, twapPartOrdersListAtom, updatePartOrdersAtom } from '../state/twapPartOrdersAtom' diff --git a/apps/cowswap-frontend/src/modules/twap/updaters/FallbackHandlerVerificationUpdater.tsx b/apps/cowswap-frontend/src/modules/twap/updaters/FallbackHandlerVerificationUpdater.tsx index a6fe2a9f09..8ec9e6244d 100644 --- a/apps/cowswap-frontend/src/modules/twap/updaters/FallbackHandlerVerificationUpdater.tsx +++ b/apps/cowswap-frontend/src/modules/twap/updaters/FallbackHandlerVerificationUpdater.tsx @@ -1,9 +1,9 @@ import { useSetAtom } from 'jotai' import { useEffect } from 'react' -import { useAsyncMemo } from 'use-async-memo' +import { useWalletInfo } from '@cowprotocol/wallet' -import { useWalletInfo } from 'modules/wallet' +import { useAsyncMemo } from 'use-async-memo' import { useExtensibleFallbackContext } from '../hooks/useExtensibleFallbackContext' import { useFallbackHandlerVerification } from '../hooks/useFallbackHandlerVerification' diff --git a/apps/cowswap-frontend/src/modules/twap/updaters/FullAmountQuoteUpdater.tsx b/apps/cowswap-frontend/src/modules/twap/updaters/FullAmountQuoteUpdater.tsx index 20f81b6f1c..361826f498 100644 --- a/apps/cowswap-frontend/src/modules/twap/updaters/FullAmountQuoteUpdater.tsx +++ b/apps/cowswap-frontend/src/modules/twap/updaters/FullAmountQuoteUpdater.tsx @@ -1,10 +1,9 @@ import { useSetAtom } from 'jotai' import { useEffect } from 'react' +import { onlyResolvesLast } from '@cowprotocol/common-utils' import { OrderQuoteResponse } from '@cowprotocol/cow-sdk' -import { onlyResolvesLast } from 'legacy/utils/async' - import { useAdvancedOrdersDerivedState } from 'modules/advancedOrders' import { useTradeQuote, useQuoteParams } from 'modules/tradeQuote' diff --git a/apps/cowswap-frontend/src/modules/twap/updaters/PartOrdersUpdater.tsx b/apps/cowswap-frontend/src/modules/twap/updaters/PartOrdersUpdater.tsx index 0e3ddbb3df..bf0baa2519 100644 --- a/apps/cowswap-frontend/src/modules/twap/updaters/PartOrdersUpdater.tsx +++ b/apps/cowswap-frontend/src/modules/twap/updaters/PartOrdersUpdater.tsx @@ -1,12 +1,10 @@ import { useAtomValue, useSetAtom } from 'jotai' import { useEffect } from 'react' +import { isTruthy } from '@cowprotocol/common-utils' import { Order } from '@cowprotocol/contracts' import { OrderParameters, SupportedChainId } from '@cowprotocol/cow-sdk' - -import { isTruthy } from 'legacy/utils/misc' - -import { useWalletInfo } from 'modules/wallet' +import { useWalletInfo } from '@cowprotocol/wallet' import { computeOrderUid } from 'utils/orderUtils/computeOrderUid' diff --git a/apps/cowswap-frontend/src/modules/twap/updaters/QuoteObserverUpdater.tsx b/apps/cowswap-frontend/src/modules/twap/updaters/QuoteObserverUpdater.tsx index 203c37c703..e7b395f051 100644 --- a/apps/cowswap-frontend/src/modules/twap/updaters/QuoteObserverUpdater.tsx +++ b/apps/cowswap-frontend/src/modules/twap/updaters/QuoteObserverUpdater.tsx @@ -1,10 +1,10 @@ import { useAtomValue } from 'jotai' import { useMemo } from 'react' +import { usePrevious } from '@cowprotocol/common-hooks' import { CurrencyAmount } from '@uniswap/sdk-core' -import usePrevious from 'legacy/hooks/usePrevious' -import { Field } from 'legacy/state/swap/actions' +import { Field } from 'legacy/state/types' import { useDerivedTradeState } from 'modules/trade/hooks/useDerivedTradeState' import { useUpdateCurrencyAmount } from 'modules/trade/hooks/useUpdateCurrencyAmount' diff --git a/apps/cowswap-frontend/src/modules/twap/updaters/TwapOrdersUpdater.tsx b/apps/cowswap-frontend/src/modules/twap/updaters/TwapOrdersUpdater.tsx index 8c1e6c9bd0..8e54615510 100644 --- a/apps/cowswap-frontend/src/modules/twap/updaters/TwapOrdersUpdater.tsx +++ b/apps/cowswap-frontend/src/modules/twap/updaters/TwapOrdersUpdater.tsx @@ -1,13 +1,12 @@ import { useAtomValue, useSetAtom } from 'jotai' import { useEffect, useMemo, useRef } from 'react' +import { ComposableCoW } from '@cowprotocol/abis' import { SupportedChainId } from '@cowprotocol/cow-sdk' -import { ComposableCoW } from '@cowswap/abis' +import { useGnosisSafeInfo } from '@cowprotocol/wallet' import ms from 'ms.macro' -import { useGnosisSafeInfo } from 'modules/wallet' - import { TWAP_PENDING_STATUSES } from '../const' import { useFetchTwapOrdersFromSafe } from '../hooks/useFetchTwapOrdersFromSafe' import { useTwapOrdersAuthMulticall } from '../hooks/useTwapOrdersAuthMulticall' diff --git a/apps/cowswap-frontend/src/modules/twap/updaters/index.tsx b/apps/cowswap-frontend/src/modules/twap/updaters/index.tsx index e9220f64e4..671048db15 100644 --- a/apps/cowswap-frontend/src/modules/twap/updaters/index.tsx +++ b/apps/cowswap-frontend/src/modules/twap/updaters/index.tsx @@ -1,8 +1,9 @@ import { useAtomValue } from 'jotai' +import { useIsSafeApp, useWalletInfo } from '@cowprotocol/wallet' + import { useComposableCowContract } from 'modules/advancedOrders/hooks/useComposableCowContract' import { AppDataUpdater } from 'modules/appData' -import { useIsSafeApp, useWalletInfo } from 'modules/wallet' import { CreatedInOrderBookOrdersUpdater } from './CreatedInOrderBookOrdersUpdater' import { FallbackHandlerVerificationUpdater } from './FallbackHandlerVerificationUpdater' diff --git a/apps/cowswap-frontend/src/modules/twap/utils/emulateTwapAsOrder.ts b/apps/cowswap-frontend/src/modules/twap/utils/emulateTwapAsOrder.ts index 73dffa195f..76a6de409d 100644 --- a/apps/cowswap-frontend/src/modules/twap/utils/emulateTwapAsOrder.ts +++ b/apps/cowswap-frontend/src/modules/twap/utils/emulateTwapAsOrder.ts @@ -22,7 +22,7 @@ export function emulateTwapAsOrder(item: TwapOrderItem): EnrichedOrder { const creationTime = new Date(item.executedDate || item.submissionDate) const expirationTime = new Date(creationTime.getTime() + t * n * 1000) - const { executedSellAmount, executedBuyAmount, executedFeeAmount } = executionInfo.info + const { executedSellAmount = '0', executedBuyAmount = '0', executedFeeAmount = '0' } = executionInfo?.info || {} return { signingScheme: SigningScheme.EIP1271, diff --git a/apps/cowswap-frontend/src/modules/twap/utils/mapPartOrderToStoreOrder.ts b/apps/cowswap-frontend/src/modules/twap/utils/mapPartOrderToStoreOrder.ts index 6c5902970e..3cfbea976b 100644 --- a/apps/cowswap-frontend/src/modules/twap/utils/mapPartOrderToStoreOrder.ts +++ b/apps/cowswap-frontend/src/modules/twap/utils/mapPartOrderToStoreOrder.ts @@ -1,11 +1,12 @@ import { EnrichedOrder } from '@cowprotocol/cow-sdk' import { Order } from 'legacy/state/orders/actions' -import { computeOrderSummary } from 'legacy/state/orders/updaters/utils' import { TokensByAddress } from 'modules/tokensList/state/tokensListAtom' import { getTokensByAddress } from 'modules/tokensList/utils/getTokensByAddress' +import { computeOrderSummary } from 'common/updaters/orders/utils' + import { getIsLastPartOrder } from './getIsLastPartOrder' import { getPartOrderStatus } from './getPartOrderStatus' diff --git a/apps/cowswap-frontend/src/modules/twap/utils/mapTwapOrderToStoreOrder.ts b/apps/cowswap-frontend/src/modules/twap/utils/mapTwapOrderToStoreOrder.ts index 8336dc2c94..76f943c32e 100644 --- a/apps/cowswap-frontend/src/modules/twap/utils/mapTwapOrderToStoreOrder.ts +++ b/apps/cowswap-frontend/src/modules/twap/utils/mapTwapOrderToStoreOrder.ts @@ -1,9 +1,10 @@ import { Order, OrderStatus } from 'legacy/state/orders/actions' -import { computeOrderSummary } from 'legacy/state/orders/updaters/utils' import { TokensByAddress } from 'modules/tokensList/state/tokensListAtom' import { getTokensByAddress } from 'modules/tokensList/utils/getTokensByAddress' +import { computeOrderSummary } from 'common/updaters/orders/utils' + import { emulateTwapAsOrder } from './emulateTwapAsOrder' import { TwapOrderItem, TwapOrderStatus } from '../types' diff --git a/apps/cowswap-frontend/src/modules/twap/utils/twapOrderToStruct.ts b/apps/cowswap-frontend/src/modules/twap/utils/twapOrderToStruct.ts index b9bf124d15..8e33c2ed95 100644 --- a/apps/cowswap-frontend/src/modules/twap/utils/twapOrderToStruct.ts +++ b/apps/cowswap-frontend/src/modules/twap/utils/twapOrderToStruct.ts @@ -1,4 +1,4 @@ -import { NATIVE_CURRENCY_BUY_ADDRESS } from 'legacy/constants' +import { NATIVE_CURRENCY_BUY_ADDRESS } from '@cowprotocol/common-const' import { TWAPOrder, TWAPOrderStruct } from '../types' diff --git a/apps/cowswap-frontend/src/modules/twap/utils/updateTwapOrdersList.ts b/apps/cowswap-frontend/src/modules/twap/utils/updateTwapOrdersList.ts index 825cffd8f7..6cd69a281c 100644 --- a/apps/cowswap-frontend/src/modules/twap/utils/updateTwapOrdersList.ts +++ b/apps/cowswap-frontend/src/modules/twap/utils/updateTwapOrdersList.ts @@ -1,4 +1,4 @@ -import { deepEqual } from 'utils/deepEqual' +import { deepEqual } from '@cowprotocol/common-utils' import { TWAP_FINAL_STATUSES } from '../const' import { TwapOrdersList } from '../state/twapOrdersListAtom' diff --git a/apps/cowswap-frontend/src/modules/usdAmount/apis/getCoingeckoUsdPrice.ts b/apps/cowswap-frontend/src/modules/usdAmount/apis/getCoingeckoUsdPrice.ts index bb9b98eae9..cb792c9aa1 100644 --- a/apps/cowswap-frontend/src/modules/usdAmount/apis/getCoingeckoUsdPrice.ts +++ b/apps/cowswap-frontend/src/modules/usdAmount/apis/getCoingeckoUsdPrice.ts @@ -1,10 +1,10 @@ +import { FractionUtils } from '@cowprotocol/common-utils' import { SupportedChainId } from '@cowprotocol/cow-sdk' import { Fraction, Token } from '@uniswap/sdk-core' import ms from 'ms.macro' import { fetchWithRateLimit } from 'common/utils/fetch' -import { FractionUtils } from 'utils/fractionUtils' export interface CoinGeckoUsdQuote { [address: string]: { diff --git a/apps/cowswap-frontend/src/modules/usdAmount/apis/getCowProtocolUsdPrice.ts b/apps/cowswap-frontend/src/modules/usdAmount/apis/getCowProtocolUsdPrice.ts index 881ecf61f2..f28c2ab114 100644 --- a/apps/cowswap-frontend/src/modules/usdAmount/apis/getCowProtocolUsdPrice.ts +++ b/apps/cowswap-frontend/src/modules/usdAmount/apis/getCowProtocolUsdPrice.ts @@ -1,10 +1,8 @@ +import { USDC } from '@cowprotocol/common-const' +import { FractionUtils } from '@cowprotocol/common-utils' import { SupportedChainId } from '@cowprotocol/cow-sdk' import { Fraction, Token } from '@uniswap/sdk-core' -import { USDC } from 'legacy/constants/tokens' - -import { FractionUtils } from 'utils/fractionUtils' - import { getCowProtocolNativePrice } from './getCowProtocolNativePrice' export async function getCowProtocolUsdPrice( diff --git a/apps/cowswap-frontend/src/modules/usdAmount/hooks/useTradeUsdAmounts.ts b/apps/cowswap-frontend/src/modules/usdAmount/hooks/useTradeUsdAmounts.ts index 14e20c7384..00e56dbf84 100644 --- a/apps/cowswap-frontend/src/modules/usdAmount/hooks/useTradeUsdAmounts.ts +++ b/apps/cowswap-frontend/src/modules/usdAmount/hooks/useTradeUsdAmounts.ts @@ -1,11 +1,10 @@ +import { isFractionFalsy } from '@cowprotocol/common-utils' import { Currency, CurrencyAmount } from '@uniswap/sdk-core' import { Nullish } from 'types' import { useIsWrapOrUnwrap } from 'modules/trade/hooks/useIsWrapOrUnwrap' -import { isFractionFalsy } from 'utils/isFractionFalsy' - import { UsdAmountInfo, useUsdAmount } from './useUsdAmount' export interface TradeUSDAmounts { diff --git a/apps/cowswap-frontend/src/modules/usdAmount/hooks/useUsdAmount.test.tsx b/apps/cowswap-frontend/src/modules/usdAmount/hooks/useUsdAmount.test.tsx index 1b72d18fbf..c8f6aaa188 100644 --- a/apps/cowswap-frontend/src/modules/usdAmount/hooks/useUsdAmount.test.tsx +++ b/apps/cowswap-frontend/src/modules/usdAmount/hooks/useUsdAmount.test.tsx @@ -1,13 +1,12 @@ import { createStore } from 'jotai/vanilla' import { ReactNode } from 'react' +import { WETH_GNOSIS_CHAIN } from '@cowprotocol/common-const' import { CurrencyAmount, Fraction } from '@uniswap/sdk-core' import { renderHook } from '@testing-library/react-hooks' import { JotaiTestProvider } from 'test-utils' -import { WETH_GNOSIS_CHAIN } from 'legacy/utils/gnosis_chain/constants' - import { useUsdAmount } from './useUsdAmount' import { usdRawPricesAtom, UsdRawPriceState } from '../state/usdRawPricesAtom' diff --git a/apps/cowswap-frontend/src/modules/usdAmount/hooks/useUsdAmount.ts b/apps/cowswap-frontend/src/modules/usdAmount/hooks/useUsdAmount.ts index b6a227bdd5..13a29fee0f 100644 --- a/apps/cowswap-frontend/src/modules/usdAmount/hooks/useUsdAmount.ts +++ b/apps/cowswap-frontend/src/modules/usdAmount/hooks/useUsdAmount.ts @@ -1,9 +1,9 @@ +import { currencyAmountToTokenAmount } from '@cowprotocol/common-utils' import { Currency, CurrencyAmount, Token } from '@uniswap/sdk-core' import { Nullish } from 'types' import { useSafeMemo } from 'common/hooks/useSafeMemo' -import { currencyAmountToTokenAmount } from 'utils/currencyAmountToTokenAmount' import { useUsdPrice } from './useUsdPrice' diff --git a/apps/cowswap-frontend/src/modules/usdAmount/state/usdRawPricesAtom.ts b/apps/cowswap-frontend/src/modules/usdAmount/state/usdRawPricesAtom.ts index 4c40b0dd76..af2afd8f02 100644 --- a/apps/cowswap-frontend/src/modules/usdAmount/state/usdRawPricesAtom.ts +++ b/apps/cowswap-frontend/src/modules/usdAmount/state/usdRawPricesAtom.ts @@ -1,9 +1,8 @@ import { atom } from 'jotai' +import { deepEqual } from '@cowprotocol/common-utils' import { Fraction, Token } from '@uniswap/sdk-core' -import { deepEqual } from 'utils/deepEqual' - export interface UsdRawPriceState { updatedAt?: number price: Fraction | null diff --git a/apps/cowswap-frontend/src/modules/usdAmount/state/usdTokenPricesAtom.ts b/apps/cowswap-frontend/src/modules/usdAmount/state/usdTokenPricesAtom.ts index bf63574d40..543eace08a 100644 --- a/apps/cowswap-frontend/src/modules/usdAmount/state/usdTokenPricesAtom.ts +++ b/apps/cowswap-frontend/src/modules/usdAmount/state/usdTokenPricesAtom.ts @@ -1,12 +1,10 @@ import { atom } from 'jotai' +import { USDC } from '@cowprotocol/common-const' +import { tryParseCurrencyAmount } from '@cowprotocol/common-utils' import { SupportedChainId } from '@cowprotocol/cow-sdk' import { Fraction, Price, Token } from '@uniswap/sdk-core' -import { USDC } from 'legacy/constants/tokens' - -import tryParseCurrencyAmount from 'lib/utils/tryParseCurrencyAmount' - import { usdRawPricesAtom, UsdRawPriceState } from './usdRawPricesAtom' export interface UsdPriceState extends Omit { diff --git a/apps/cowswap-frontend/src/modules/usdAmount/updaters/UsdPricesUpdater.test.tsx b/apps/cowswap-frontend/src/modules/usdAmount/updaters/UsdPricesUpdater.test.tsx index e299ec6e94..e1a2f188d4 100644 --- a/apps/cowswap-frontend/src/modules/usdAmount/updaters/UsdPricesUpdater.test.tsx +++ b/apps/cowswap-frontend/src/modules/usdAmount/updaters/UsdPricesUpdater.test.tsx @@ -1,6 +1,7 @@ import { createStore } from 'jotai/vanilla' import { ReactNode } from 'react' +import { COW as COWS, USDC_MAINNET } from '@cowprotocol/common-const' import { SupportedChainId } from '@cowprotocol/cow-sdk' import { Token } from '@uniswap/sdk-core' @@ -8,8 +9,6 @@ import { act, render, waitFor } from '@testing-library/react' import { SWRConfig } from 'swr' import { JotaiTestProvider } from 'test-utils' -import { COW as COWS, USDC_MAINNET } from 'legacy/constants/tokens' - import { UsdPricesUpdater } from './UsdPricesUpdater' import * as coingeckoApi from '../apis/getCoingeckoUsdPrice' diff --git a/apps/cowswap-frontend/src/modules/usdAmount/updaters/UsdPricesUpdater.ts b/apps/cowswap-frontend/src/modules/usdAmount/updaters/UsdPricesUpdater.ts index 8c0c04f046..52e4d2a657 100644 --- a/apps/cowswap-frontend/src/modules/usdAmount/updaters/UsdPricesUpdater.ts +++ b/apps/cowswap-frontend/src/modules/usdAmount/updaters/UsdPricesUpdater.ts @@ -1,19 +1,16 @@ import { useAtomValue, useSetAtom } from 'jotai' import { useEffect, useMemo } from 'react' +import { USDC } from '@cowprotocol/common-const' +import { useDebounce } from '@cowprotocol/common-hooks' +import { FractionUtils } from '@cowprotocol/common-utils' import { SupportedChainId } from '@cowprotocol/cow-sdk' +import { useWalletInfo } from '@cowprotocol/wallet' import { Fraction, Token } from '@uniswap/sdk-core' import ms from 'ms.macro' import useSWR, { SWRConfiguration } from 'swr' -import { USDC } from 'legacy/constants/tokens' -import useDebounce from 'legacy/hooks/useDebounce' - -import { useWalletInfo } from 'modules/wallet' - -import { FractionUtils } from 'utils/fractionUtils' - import { getCowProtocolNativePrice } from '../apis/getCowProtocolNativePrice' import { fetchCurrencyUsdPrice } from '../services/fetchCurrencyUsdPrice' import { diff --git a/apps/cowswap-frontend/src/modules/wallet/api/assets/formatic.png b/apps/cowswap-frontend/src/modules/wallet/api/assets/formatic.png deleted file mode 100644 index 414bab299b..0000000000 Binary files a/apps/cowswap-frontend/src/modules/wallet/api/assets/formatic.png and /dev/null differ diff --git a/apps/cowswap-frontend/src/modules/wallet/api/pure/ZengoBanner/index.tsx b/apps/cowswap-frontend/src/modules/wallet/api/pure/ZengoBanner/index.tsx deleted file mode 100644 index 2bf8e37418..0000000000 --- a/apps/cowswap-frontend/src/modules/wallet/api/pure/ZengoBanner/index.tsx +++ /dev/null @@ -1,41 +0,0 @@ -import { Trans } from '@lingui/macro' - -import { ExternalLink } from 'legacy/theme' - -import { default as ZengoImage } from 'modules/wallet/api/assets/zengo.svg' - -import * as styled from './styled' - -const GET_ZENGO_LINK = 'https://zengo.com/' -const HOW_TO_USE_ZENGO = 'https://help.zengo.com/en/collections/1646183-how-to-guides' - -export function ZengoBanner() { - return ( - - - - - - -

- Need a crypto wallet? -

-

- Download ZenGo: The most secure crypto wallet. -

- - - - - - Get ZenGo - - - - - How to use ZenGo - - - - ) -} diff --git a/apps/cowswap-frontend/src/modules/wallet/api/pure/ZengoBanner/styled.ts b/apps/cowswap-frontend/src/modules/wallet/api/pure/ZengoBanner/styled.ts deleted file mode 100644 index a77555abf1..0000000000 --- a/apps/cowswap-frontend/src/modules/wallet/api/pure/ZengoBanner/styled.ts +++ /dev/null @@ -1,70 +0,0 @@ -import styled from 'styled-components/macro' - -import { ButtonPrimary } from 'legacy/components/Button' -import { ExternalLink } from 'legacy/theme/components' - -export const Wrapper = styled.div` - display: flex; - align-items: center; - justify-content: space-between; - flex-wrap: wrap; - width: 100%; - ${({ theme }) => theme.mediaWidth.upToExtraSmall` - flex-direction: column; - justify-content: center; - `}; -` - -export const Icon = styled.div` - max-width: 50px; - img { - max-width: 100%; - } -` - -export const Content = styled.div` - flex: 1; - padding: 0 1rem; - color: ${({ theme }) => theme.text1}; - h4 { - margin-bottom: 5px; - font-size: 1.1rem; - } - p { - margin: 0; - font-size: 0.8rem; - } - ${({ theme }) => theme.mediaWidth.upToExtraSmall` - margin-top: 5px; - text-align: center; - `}; -` - -export const Actions = styled.div` - ${({ theme }) => theme.mediaWidth.upToExtraSmall` - margin-top: 10px; - display: flex; - justify-content: center; - flex-direction: column; - `}; -` - -export const GetZengoButton = styled(ButtonPrimary)` - font-size: 12px; - border-radius: 8px; - padding: 8px; - min-height: auto; - a { - color: ${({ theme }) => theme.white}; - &:hover { - text-decoration: none; - } - } -` - -export const HowToUse = styled(ExternalLink)` - font-size: 0.8rem; - margin-top: 5px; - color: ${({ theme }) => theme.text1}; - cursor: pointer; -` diff --git a/apps/cowswap-frontend/src/modules/wallet/web3-react/containers/AccountSelectorModal/index.tsx b/apps/cowswap-frontend/src/modules/wallet/containers/AccountSelectorModal/index.tsx similarity index 87% rename from apps/cowswap-frontend/src/modules/wallet/web3-react/containers/AccountSelectorModal/index.tsx rename to apps/cowswap-frontend/src/modules/wallet/containers/AccountSelectorModal/index.tsx index 8ac22e48b3..f344109ca0 100644 --- a/apps/cowswap-frontend/src/modules/wallet/web3-react/containers/AccountSelectorModal/index.tsx +++ b/apps/cowswap-frontend/src/modules/wallet/containers/AccountSelectorModal/index.tsx @@ -1,7 +1,16 @@ import { useAtom, useAtomValue, useSetAtom } from 'jotai' import React, { useCallback, useEffect, useMemo, useState } from 'react' -import { useAddSnackbar } from '@cowswap/snackbars' +import { useAddSnackbar } from '@cowprotocol/snackbars' +import { + accountsLoaders, + hwAccountIndexAtom, + getConnectionIcon, + getConnectionName, + AccountIndexSelect, + HardWareWallet, + getWeb3ReactConnection, +} from '@cowprotocol/wallet' import { useWeb3React } from '@web3-react/core' import { Trans } from '@lingui/macro' @@ -10,15 +19,9 @@ import { useNativeCurrencyBalances } from 'modules/tokens/hooks/useCurrencyBalan import { CowModal } from 'common/pure/Modal' -import { accountsLoaders } from './accountsLoaders' import { accountSelectorModalAtom, toggleAccountSelectorModalAtom } from './state' import * as styledEl from './styled' -import { hwAccountIndexAtom } from '../../../api/state' -import { getConnectionIcon, getConnectionName } from '../../../api/utils/connection' -import { getWeb3ReactConnection, HardWareWallet } from '../../connection' -import { AccountIndexSelect } from '../../pure/AccountIndexSelect' - export function AccountSelectorModal() { const { isOpen } = useAtomValue(accountSelectorModalAtom) const closeModal = useSetAtom(toggleAccountSelectorModalAtom) diff --git a/apps/cowswap-frontend/src/modules/wallet/web3-react/containers/AccountSelectorModal/state.ts b/apps/cowswap-frontend/src/modules/wallet/containers/AccountSelectorModal/state.ts similarity index 100% rename from apps/cowswap-frontend/src/modules/wallet/web3-react/containers/AccountSelectorModal/state.ts rename to apps/cowswap-frontend/src/modules/wallet/containers/AccountSelectorModal/state.ts diff --git a/apps/cowswap-frontend/src/modules/wallet/web3-react/containers/AccountSelectorModal/styled.tsx b/apps/cowswap-frontend/src/modules/wallet/containers/AccountSelectorModal/styled.tsx similarity index 77% rename from apps/cowswap-frontend/src/modules/wallet/web3-react/containers/AccountSelectorModal/styled.tsx rename to apps/cowswap-frontend/src/modules/wallet/containers/AccountSelectorModal/styled.tsx index d5502835d2..14af67bb69 100644 --- a/apps/cowswap-frontend/src/modules/wallet/web3-react/containers/AccountSelectorModal/styled.tsx +++ b/apps/cowswap-frontend/src/modules/wallet/containers/AccountSelectorModal/styled.tsx @@ -1,11 +1,13 @@ +import { ReactComponent as Close } from '@cowprotocol/assets/images/x.svg' + import styled from 'styled-components/macro' -import { ReactComponent as Close } from 'legacy/assets/images/x.svg' +import { UI } from 'common/constants/theme' export const CloseIcon = styled(Close)` opacity: 0.6; transition: opacity 0.3s ease-in-out; - stroke: ${({ theme }) => theme.text1}; + stroke: var(${UI.COLOR_TEXT1}); width: 24px; height: 24px; cursor: pointer; diff --git a/apps/cowswap-frontend/src/modules/wallet/web3-react/containers/AddToMetamask/index.tsx b/apps/cowswap-frontend/src/modules/wallet/containers/AddToMetamask/index.tsx similarity index 66% rename from apps/cowswap-frontend/src/modules/wallet/web3-react/containers/AddToMetamask/index.tsx rename to apps/cowswap-frontend/src/modules/wallet/containers/AddToMetamask/index.tsx index 0c543789d0..fc8aa550e9 100644 --- a/apps/cowswap-frontend/src/modules/wallet/web3-react/containers/AddToMetamask/index.tsx +++ b/apps/cowswap-frontend/src/modules/wallet/containers/AddToMetamask/index.tsx @@ -1,24 +1,22 @@ import React, { useCallback, useState } from 'react' +import { addTokenToMetamaskAnalytics } from '@cowprotocol/analytics' +import { getIsMetaMask } from '@cowprotocol/wallet' import { Currency } from '@uniswap/sdk-core' import { useWeb3React } from '@web3-react/core' -import { Nullish } from 'types' - -import { addTokenToMetamaskAnalytics } from 'legacy/components/analytics' - -import { AddToMetamask as AddToMetamaskPure } from 'modules/wallet/api/pure/AddToMetamask' -import { getIsMetaMask } from 'modules/wallet/api/utils/connection' - import useCurrencyLogoURIs from 'common/pure/CurrencyLogo/hooks/useCurrencyLogoURIs' +import { AddToMetamask as AddToMetamaskPure } from '../../pure/AddToMetamask' + export type AddToMetamaskProps = { - currency: Nullish + currency: Currency | null | undefined shortLabel?: boolean + className?: string } -export default function AddToMetamask(props: AddToMetamaskProps) { - const { currency, shortLabel } = props +export function AddToMetamask(props: AddToMetamaskProps) { + const { currency, shortLabel, className } = props const { connector } = useWeb3React() const isMetamask = getIsMetaMask() @@ -50,5 +48,13 @@ export default function AddToMetamask(props: AddToMetamaskProps) { return null } - return + return ( + + ) } diff --git a/apps/cowswap-frontend/src/modules/wallet/containers/ConnectWalletOptions.tsx b/apps/cowswap-frontend/src/modules/wallet/containers/ConnectWalletOptions.tsx new file mode 100644 index 0000000000..72218b1556 --- /dev/null +++ b/apps/cowswap-frontend/src/modules/wallet/containers/ConnectWalletOptions.tsx @@ -0,0 +1,94 @@ +import { useTheme } from '@cowprotocol/common-hooks' +import { isMobile } from '@cowprotocol/common-utils' +import { + AlphaOption, + AmbireOption, + CoinbaseWalletOption, + InjectedOption, + InstallMetaMaskOption, + MetaMaskOption, + OpenMetaMaskMobileOption, + InstallKeystoneOption, + KeystoneOption, + LedgerOption, + TrezorOption, + TrustWalletOption, + WalletConnectV2Option, + getIsCoinbaseWallet, + getIsInjected, + getIsMetaMask, +} from '@cowprotocol/wallet' +import { Connector } from '@web3-react/types' + +import { useSelectedWallet } from 'legacy/state/user/hooks' + +import { FeatureGuard } from 'common/containers/FeatureGuard' + +export type TryActivation = (connector: Connector) => void + +export function ConnectWalletOptions({ tryActivation }: { tryActivation: TryActivation }) { + const isInjected = getIsInjected() + const isMetaMask = getIsMetaMask() + const isCoinbaseWallet = getIsCoinbaseWallet() + const selectedWallet = useSelectedWallet() + const { darkMode } = useTheme() + + const isCoinbaseWalletBrowser = isMobile && isCoinbaseWallet + const isMetaMaskBrowser = isMobile && isMetaMask + const isInjectedMobileBrowser = isCoinbaseWalletBrowser || isMetaMaskBrowser + // const isChromeMobile = isMobile && isChrome + const showKeystone = !isInjectedMobileBrowser && !isMobile && window.ethereum?.isMetaMask + + const connectionProps = { darkMode, selectedWallet, tryActivation } + + // Show Tally option only in Chrome (includes Brave too), but not on mobile or as an injected browser + // const showTally = !isInjectedMobileBrowser && isChrome && !isChromeMobile + + let injectedOption + if (!isInjected) { + if (!isMobile) { + injectedOption = + } else { + injectedOption = + } + } else { + if (isMetaMask) { + injectedOption = + } else { + injectedOption = + } + } + + const coinbaseWalletOption = + + const walletConnectionV2Option = (!isInjectedMobileBrowser && ) ?? null + + // Wallet-connect based + // const zengoOption = (!isInjectedMobileBrowser && ) ?? null + const ambireOption = (!isInjectedMobileBrowser && ) ?? null + const alphaOption = (!isInjectedMobileBrowser && ) ?? null + const ledgerOption = (!isInjectedMobileBrowser && !isMobile && ) ?? null + const trezorOption = (!isInjectedMobileBrowser && !isMobile && ) ?? null + const keystoneOption = + (showKeystone && ) || (!isMobile && ) + + // Injected + // const tallyOption = (showTally && ) ?? null + const trustOption = (!isInjectedMobileBrowser && ) ?? null + + return ( + <> + {injectedOption} + {walletConnectionV2Option} + {coinbaseWalletOption} + {ledgerOption} + {trezorOption} + {/*{zengoOption}*/} + {ambireOption} + {alphaOption} + {/* {tallyOption} */} + {trustOption} + {keystoneOption} + + ) +} diff --git a/apps/cowswap-frontend/src/legacy/components/Popups/FollowPendingTxPopup/FollowPendingTxPopupUI.tsx b/apps/cowswap-frontend/src/modules/wallet/containers/FollowPendingTxPopup/FollowPendingTxPopupUI.tsx similarity index 97% rename from apps/cowswap-frontend/src/legacy/components/Popups/FollowPendingTxPopup/FollowPendingTxPopupUI.tsx rename to apps/cowswap-frontend/src/modules/wallet/containers/FollowPendingTxPopup/FollowPendingTxPopupUI.tsx index 8f5d1c36f6..54b6852023 100644 --- a/apps/cowswap-frontend/src/legacy/components/Popups/FollowPendingTxPopup/FollowPendingTxPopupUI.tsx +++ b/apps/cowswap-frontend/src/modules/wallet/containers/FollowPendingTxPopup/FollowPendingTxPopupUI.tsx @@ -1,11 +1,12 @@ import React from 'react' +import { Tooltip, TooltipProps } from '@cowprotocol/ui' + import { Text } from 'rebass' import styled from 'styled-components/macro' import { AutoColumn } from 'legacy/components/Column' import { StyledClose as IconClose } from 'legacy/components/Popups/styled' -import Tooltip, { TooltipProps } from 'legacy/components/Tooltip' interface PopupContentProps { onCheck: () => void diff --git a/apps/cowswap-frontend/src/legacy/components/Popups/FollowPendingTxPopup/index.tsx b/apps/cowswap-frontend/src/modules/wallet/containers/FollowPendingTxPopup/index.tsx similarity index 91% rename from apps/cowswap-frontend/src/legacy/components/Popups/FollowPendingTxPopup/index.tsx rename to apps/cowswap-frontend/src/modules/wallet/containers/FollowPendingTxPopup/index.tsx index 42666204ab..5f2270a7d9 100644 --- a/apps/cowswap-frontend/src/legacy/components/Popups/FollowPendingTxPopup/index.tsx +++ b/apps/cowswap-frontend/src/modules/wallet/containers/FollowPendingTxPopup/index.tsx @@ -3,19 +3,18 @@ import { selectAtom } from 'jotai/utils' import React, { useEffect, useMemo, useCallback, useRef, PropsWithChildren } from 'react' import { useRecentActivityLastPendingOrder } from 'legacy/hooks/useRecentActivity' +import { Order } from 'legacy/state/orders/actions' +import { useIsExpertMode } from 'legacy/state/user/hooks' + +import { FollowPendingTxPopupUI } from './FollowPendingTxPopupUI' + import { handleFollowPendingTxPopupAtom, handleHidePopupPermanentlyAtom, showFollowTxPopupAtom, followPendingTxPopupAtom, handleCloseOrderPopupAtom, -} from 'legacy/state/application/atoms' -import { Order } from 'legacy/state/orders/actions' -import { useIsExpertMode } from 'legacy/state/user/hooks' - -import { OrderID } from 'api/gnosisProtocol' - -import { FollowPendingTxPopupUI } from './FollowPendingTxPopupUI' +} from '../../state/followPendingTxPopupAtom' export function useLastPendingOrder(): { lastPendingOrder: Order | null; onClose: () => void } { const setShowFollowPendingTxPopup = useSetAtom(handleFollowPendingTxPopupAtom) @@ -45,7 +44,7 @@ export function useCloseFollowTxPopupIfNotPendingOrder() { }, [lastPendingOrder, onClose, showingPopup]) } -const useShowingPopupFirstTime = (orderId: OrderID | undefined) => { +const useShowingPopupFirstTime = (orderId: string | undefined) => { const showingPopup = useAtomValue(showFollowTxPopupAtom) const _firstTimePopupOrderAppears = useMemo( () => @@ -62,7 +61,7 @@ const useShowingPopupFirstTime = (orderId: OrderID | undefined) => { return { showPopup: firstTimePopupOrderAppears && showingPopup, firstTimePopupOrderAppears } } -const FollowPendingTxPopup: React.FC = ({ children }): JSX.Element => { +export const FollowPendingTxPopup: React.FC = ({ children }): JSX.Element => { const setShowFollowPendingTxPopup = useSetAtom(handleFollowPendingTxPopupAtom) const setHidePendingTxPopupPermanently = useSetAtom(handleHidePopupPermanentlyAtom) const isExpertMode = useIsExpertMode() @@ -87,5 +86,3 @@ const FollowPendingTxPopup: React.FC = ({ children }): JSX.El ) } - -export default FollowPendingTxPopup diff --git a/apps/cowswap-frontend/src/modules/wallet/web3-react/containers/WalletModal/index.tsx b/apps/cowswap-frontend/src/modules/wallet/containers/WalletModal/index.tsx similarity index 73% rename from apps/cowswap-frontend/src/modules/wallet/web3-react/containers/WalletModal/index.tsx rename to apps/cowswap-frontend/src/modules/wallet/containers/WalletModal/index.tsx index b70e80dfbf..daef27f9be 100644 --- a/apps/cowswap-frontend/src/modules/wallet/web3-react/containers/WalletModal/index.tsx +++ b/apps/cowswap-frontend/src/modules/wallet/containers/WalletModal/index.tsx @@ -1,22 +1,21 @@ import { useSetAtom } from 'jotai' import { useCallback, useEffect, useState } from 'react' +import { changeWalletAnalytics } from '@cowprotocol/analytics' +import { usePrevious } from '@cowprotocol/common-hooks' +import { getCurrentChainIdFromUrl } from '@cowprotocol/common-utils' +import { useWalletInfo, getIsHardWareWallet, getWeb3ReactConnection } from '@cowprotocol/wallet' import { useWeb3React } from '@web3-react/core' import { Connector } from '@web3-react/types' -import { changeWalletAnalytics } from 'legacy/components/analytics' -import usePrevious from 'legacy/hooks/usePrevious' import { useModalIsOpen, useToggleWalletModal } from 'legacy/state/application/hooks' import { ApplicationModal } from 'legacy/state/application/reducer' import { updateConnectionError } from 'legacy/state/connection/reducer' import { useAppDispatch, useAppSelector } from 'legacy/state/hooks' import { updateSelectedWallet } from 'legacy/state/user/reducer' -import { ConnectionType, toggleAccountSelectorModalAtom, useWalletInfo } from 'modules/wallet' -import { WalletModal as WalletModalPure, WalletModalView } from 'modules/wallet/api/pure/WalletModal' -import { getIsHardWareWallet, getWeb3ReactConnection } from 'modules/wallet/web3-react/connection' - -import { getCurrentChainIdFromUrl } from 'utils/getCurrentChainIdFromUrl' +import { WalletModal as WalletModalPure, WalletModalView } from '../../pure/WalletModal' +import { toggleAccountSelectorModalAtom } from '../AccountSelectorModal/state' export function WalletModal() { const dispatch = useAppDispatch() @@ -85,33 +84,12 @@ export function WalletModal() { changeWalletAnalytics('Todo: wallet name') try { - // Fortmatic opens it's own modal on activation to log in. This modal has a tabIndex - // collision into the WalletModal, so we special case by closing the modal. - if (connectionType === ConnectionType.FORTMATIC) { - toggleWalletModal() - } - setPendingConnector(connector) setWalletView('pending') dispatch(updateConnectionError({ connectionType, error: undefined })) await connector.activate(getCurrentChainIdFromUrl()) - const connection = getWeb3ReactConnection(connector) - - // Important for balances to load when connected to Gnosis-chain via WalletConnect - if (connection.type === ConnectionType.WALLET_CONNECT) { - const provider: any = connector.provider - - if (provider && provider.isWalletConnect) { - const { http, rpc, signer } = (connector as any).provider - const chainId = signer.connection.chainId - // don't default to SupportedChainId.Mainnet - throw instead - if (!chainId) throw new Error('[WalletModal::activation error: No chainId') - http.connection.url = rpc.custom[chainId] - } - } - dispatch(updateSelectedWallet({ wallet: connectionType })) if (isHardWareWallet) { @@ -131,7 +109,7 @@ export function WalletModal() { ) } }, - [chainId, dispatch, toggleWalletModal, toggleAccountSelectorModal] + [chainId, dispatch, toggleAccountSelectorModal] ) return ( diff --git a/apps/cowswap-frontend/src/modules/wallet/web3-react/containers/Web3Status/index.tsx b/apps/cowswap-frontend/src/modules/wallet/containers/Web3Status/index.tsx similarity index 59% rename from apps/cowswap-frontend/src/modules/wallet/web3-react/containers/Web3Status/index.tsx rename to apps/cowswap-frontend/src/modules/wallet/containers/Web3Status/index.tsx index 29915da1e3..98d9318854 100644 --- a/apps/cowswap-frontend/src/modules/wallet/web3-react/containers/Web3Status/index.tsx +++ b/apps/cowswap-frontend/src/modules/wallet/containers/Web3Status/index.tsx @@ -1,18 +1,17 @@ +import { STORAGE_KEY_LAST_PROVIDER } from '@cowprotocol/common-const' +import { useWalletDetails, useWalletInfo, getWeb3ReactConnection } from '@cowprotocol/wallet' import { useWeb3React } from '@web3-react/core' -import { useCloseFollowTxPopupIfNotPendingOrder } from 'legacy/components/Popups/FollowPendingTxPopup' -import { STORAGE_KEY_LAST_PROVIDER } from 'legacy/constants' import { useToggleWalletModal } from 'legacy/state/application/hooks' import { useAppSelector } from 'legacy/state/hooks' -import { useWalletDetails, useWalletInfo, WalletModal, AccountSelectorModal } from 'modules/wallet' -import { Web3StatusInner } from 'modules/wallet/api/pure/Web3StatusInner' -import { Wrapper } from 'modules/wallet/api/pure/Web3StatusInner/styled' -import { getWeb3ReactConnection } from 'modules/wallet/web3-react/connection' +import { Web3StatusInner } from '../../pure/Web3StatusInner' +import { Wrapper } from '../../pure/Web3StatusInner/styled' +import { AccountSelectorModal } from '../AccountSelectorModal' +import { useCloseFollowTxPopupIfNotPendingOrder } from '../FollowPendingTxPopup' +import { WalletModal } from '../WalletModal' -import { useCategorizeRecentActivity } from 'common/hooks/useCategorizeRecentActivity' - -export function Web3Status() { +export function Web3Status({ pendingActivities }: { pendingActivities: string[] }) { const { connector } = useWeb3React() const { account, active, chainId } = useWalletInfo() const { ensName } = useWalletDetails() @@ -27,8 +26,6 @@ export function Web3Status() { const latestProvider = localStorage.getItem(STORAGE_KEY_LAST_PROVIDER) - const { pendingActivity } = useCategorizeRecentActivity() - if (!active && !latestProvider) { return null } @@ -36,7 +33,7 @@ export function Web3Status() { return ( theme.border2}; - color: ${({ theme }) => theme.text1}; + color: var(--cow-color-text1); background: transparent; outline: 0; padding: 8px 16px; @@ -62,14 +58,15 @@ export type AddToMetamaskProps = { shortLabel?: boolean addToken: () => void success?: boolean + className?: string } export function AddToMetamask(props: AddToMetamaskProps) { - const { currency, shortLabel, addToken, success } = props + const { className, currency, shortLabel, addToken, success } = props const theme = useContext(ThemeContext) return ( - + {!success ? ( {' '} diff --git a/apps/cowswap-frontend/src/modules/wallet/api/pure/PendingView/index.tsx b/apps/cowswap-frontend/src/modules/wallet/pure/PendingView/index.tsx similarity index 96% rename from apps/cowswap-frontend/src/modules/wallet/api/pure/PendingView/index.tsx rename to apps/cowswap-frontend/src/modules/wallet/pure/PendingView/index.tsx index 17bd20276a..bcf5a9ec59 100644 --- a/apps/cowswap-frontend/src/modules/wallet/api/pure/PendingView/index.tsx +++ b/apps/cowswap-frontend/src/modules/wallet/pure/PendingView/index.tsx @@ -1,9 +1,9 @@ +import { ButtonEmpty, ButtonPrimary, Loader } from '@cowprotocol/ui' + import { Trans } from '@lingui/macro' import { transparentize } from 'polished' import styled from 'styled-components/macro' -import { ButtonEmpty, ButtonPrimary } from 'legacy/components/Button' -import Loader from 'legacy/components/Loader' import { ThemedText } from 'legacy/theme' const PendingSection = styled.div` diff --git a/apps/cowswap-frontend/src/modules/wallet/api/pure/StatusIcon/index.tsx b/apps/cowswap-frontend/src/modules/wallet/pure/StatusIcon/index.tsx similarity index 61% rename from apps/cowswap-frontend/src/modules/wallet/api/pure/StatusIcon/index.tsx rename to apps/cowswap-frontend/src/modules/wallet/pure/StatusIcon/index.tsx index e4976c9f50..8c9a9910ae 100644 --- a/apps/cowswap-frontend/src/modules/wallet/api/pure/StatusIcon/index.tsx +++ b/apps/cowswap-frontend/src/modules/wallet/pure/StatusIcon/index.tsx @@ -1,10 +1,7 @@ -import styled from 'styled-components/macro' +import { Identicon, ConnectionType } from '@cowprotocol/wallet' +import { CoinbaseWalletIcon, WalletConnectIcon } from '@cowprotocol/wallet' -import { ConnectionType } from 'modules/wallet' -import CoinbaseWalletIcon from 'modules/wallet/api/assets/coinbase.svg' -import FortmaticIcon from 'modules/wallet/api/assets/formatic.png' -import WalletConnectIcon from 'modules/wallet/api/assets/walletConnectIcon.svg' -import { Identicon } from 'modules/wallet/api/container/Identicon' +import styled from 'styled-components/macro' const IconWrapper = styled.div<{ size?: number }>` ${({ theme }) => theme.flexColumnNoWrap}; @@ -25,21 +22,18 @@ export interface StatusIconProps { connectionType: ConnectionType } -export default function StatusIcon({ connectionType }: StatusIconProps) { +export function StatusIcon({ connectionType }: StatusIconProps) { let image switch (connectionType) { case ConnectionType.INJECTED: image = break - case ConnectionType.WALLET_CONNECT: + case ConnectionType.WALLET_CONNECT_V2: image = WalletConnect break case ConnectionType.COINBASE_WALLET: image = Coinbase Wallet break - case ConnectionType.FORTMATIC: - image = Fortmatic - break } return {image} diff --git a/apps/cowswap-frontend/src/modules/wallet/api/pure/WalletModal/index.tsx b/apps/cowswap-frontend/src/modules/wallet/pure/WalletModal/index.tsx similarity index 93% rename from apps/cowswap-frontend/src/modules/wallet/api/pure/WalletModal/index.tsx rename to apps/cowswap-frontend/src/modules/wallet/pure/WalletModal/index.tsx index 98493699f0..ad4be408f5 100644 --- a/apps/cowswap-frontend/src/modules/wallet/api/pure/WalletModal/index.tsx +++ b/apps/cowswap-frontend/src/modules/wallet/pure/WalletModal/index.tsx @@ -1,21 +1,21 @@ +import { AutoRow } from '@cowprotocol/ui' import { Connector } from '@web3-react/types' import { Trans } from '@lingui/macro' import { LightCard } from 'legacy/components/Card' import { AutoColumn } from 'legacy/components/Column' -import { AutoRow } from 'legacy/components/Row' import { ThemedText } from 'legacy/theme' import { StyledInternalLink } from 'legacy/theme/components' -import { PendingView } from 'modules/wallet/api/pure/PendingView' -import { ConnectWalletOptions, TryActivation } from 'modules/wallet/web3-react/connection' - import { Routes } from 'common/constants/routes' import { CloseIcon, ContentWrapper, CowModal, HeaderRow, HoverText } from 'common/pure/Modal' import { CloseColor, OptionGrid, TermsWrapper, UpperSection, Wrapper } from './styled' +import { ConnectWalletOptions, TryActivation } from '../../containers/ConnectWalletOptions' +import { PendingView } from '../PendingView' + export type WalletModalView = 'options' | 'account' | 'pending' interface WalletModalProps { diff --git a/apps/cowswap-frontend/src/modules/wallet/api/pure/WalletModal/styled.tsx b/apps/cowswap-frontend/src/modules/wallet/pure/WalletModal/styled.tsx similarity index 85% rename from apps/cowswap-frontend/src/modules/wallet/api/pure/WalletModal/styled.tsx rename to apps/cowswap-frontend/src/modules/wallet/pure/WalletModal/styled.tsx index 81eff40a82..2c2de9c91e 100644 --- a/apps/cowswap-frontend/src/modules/wallet/api/pure/WalletModal/styled.tsx +++ b/apps/cowswap-frontend/src/modules/wallet/pure/WalletModal/styled.tsx @@ -1,10 +1,12 @@ +import { ReactComponent as Close } from '@cowprotocol/assets/images/x.svg' +import { ExternalLink } from '@cowprotocol/ui' + import styled from 'styled-components/macro' -import { ReactComponent as Close } from 'legacy/assets/images/x.svg' -import { ExternalLink } from 'legacy/theme' +import { UI } from 'common/constants/theme' export const TermsWrapper = styled.div` - color: ${({ theme }) => theme.text1}; + color: var(${UI.COLOR_TEXT1}); ` export const Blurb = styled.div` @@ -76,7 +78,7 @@ export const IconWrapper = styled.div` align-items: center; justify-content: center; background: transparent; - border: 1px solid var(--cow-color-border); + border: 1px solid var(${UI.COLOR_BORDER}); padding: 8px; margin: 0 12px 0 0; @@ -86,7 +88,7 @@ export const IconWrapper = styled.div` } > svg > path { - --color: var(--cow-color-text1); + --color: var(${UI.COLOR_TEXT1}); fill: var(--color); stroke: var(--color); } diff --git a/apps/cowswap-frontend/src/modules/wallet/api/pure/Web3StatusInner/index.tsx b/apps/cowswap-frontend/src/modules/wallet/pure/Web3StatusInner/index.tsx similarity index 82% rename from apps/cowswap-frontend/src/modules/wallet/api/pure/Web3StatusInner/index.tsx rename to apps/cowswap-frontend/src/modules/wallet/pure/Web3StatusInner/index.tsx index ba324b17c1..0a8a9affdc 100644 --- a/apps/cowswap-frontend/src/modules/wallet/api/pure/Web3StatusInner/index.tsx +++ b/apps/cowswap-frontend/src/modules/wallet/pure/Web3StatusInner/index.tsx @@ -1,15 +1,14 @@ -import { Trans } from '@lingui/macro' - -import Loader from 'legacy/components/Loader' -import FollowPendingTxPopup from 'legacy/components/Popups/FollowPendingTxPopup' -import { RowBetween } from 'legacy/components/Row' -import { shortenAddress } from 'legacy/utils' +import { shortenAddress } from '@cowprotocol/common-utils' +import { Loader, RowBetween } from '@cowprotocol/ui' +import { ConnectionType } from '@cowprotocol/wallet' -import StatusIcon from 'modules/wallet/api/pure/StatusIcon' -import { ConnectionType } from 'modules/wallet/api/types' +import { Trans } from '@lingui/macro' import { NetworkIcon, Text, Web3StatusConnect, Web3StatusConnected, Web3StatusError } from './styled' +import { FollowPendingTxPopup } from '../../containers/FollowPendingTxPopup' +import { StatusIcon } from '../StatusIcon' + export interface Web3StatusInnerProps { account?: string | null chainId?: number diff --git a/apps/cowswap-frontend/src/modules/wallet/api/pure/Web3StatusInner/styled.ts b/apps/cowswap-frontend/src/modules/wallet/pure/Web3StatusInner/styled.ts similarity index 88% rename from apps/cowswap-frontend/src/modules/wallet/api/pure/Web3StatusInner/styled.ts rename to apps/cowswap-frontend/src/modules/wallet/pure/Web3StatusInner/styled.ts index d82660de22..35738b87d3 100644 --- a/apps/cowswap-frontend/src/modules/wallet/api/pure/Web3StatusInner/styled.ts +++ b/apps/cowswap-frontend/src/modules/wallet/pure/Web3StatusInner/styled.ts @@ -1,8 +1,10 @@ +import { ButtonSecondary } from '@cowprotocol/ui' + import { darken } from 'polished' import { Activity } from 'react-feather' import styled, { css } from 'styled-components/macro' -import { ButtonSecondary } from 'legacy/components/Button' +import { UI } from 'common/constants/theme' export const Web3StatusGeneric = styled(ButtonSecondary)`` @@ -44,14 +46,14 @@ export const Web3StatusConnect = styled(Web3StatusGeneric)<{ faded?: boolean }>` ` export const Web3StatusConnected = styled(Web3StatusGeneric)<{ pending?: boolean; clickDisabled?: boolean }>` - background-color: ${({ theme }) => theme.grey1}; + background-color: var(${UI.COLOR_GREY}); border: 1px solid transparent; - color: ${({ theme }) => theme.text1}; + color: var(${UI.COLOR_TEXT1}); font-weight: 500; &:hover { - background-color: ${({ theme }) => theme.grey1}; - color: ${({ theme }) => theme.text1}; + background-color: var(${UI.COLOR_GREY}); + color: var(${UI.COLOR_TEXT1}); } ${({ clickDisabled }) => @@ -81,7 +83,7 @@ export const NetworkIcon = styled(Activity)` ` export const Wrapper = styled.div` - color: ${({ theme }) => theme.text1}; + color: var(${UI.COLOR_TEXT1}); height: 40px; width: 100%; display: flex; @@ -92,7 +94,7 @@ export const Wrapper = styled.div` ${({ theme }) => theme.mediaWidth.upToMedium` width: auto; height: 100%; - margin: 0 0 0 auto; + margin: 0 auto; `}; button { diff --git a/apps/cowswap-frontend/src/legacy/state/application/atoms.ts b/apps/cowswap-frontend/src/modules/wallet/state/followPendingTxPopupAtom.ts similarity index 96% rename from apps/cowswap-frontend/src/legacy/state/application/atoms.ts rename to apps/cowswap-frontend/src/modules/wallet/state/followPendingTxPopupAtom.ts index e64a6f5469..58be234eb6 100644 --- a/apps/cowswap-frontend/src/legacy/state/application/atoms.ts +++ b/apps/cowswap-frontend/src/modules/wallet/state/followPendingTxPopupAtom.ts @@ -5,7 +5,7 @@ import { OrderID } from 'api/gnosisProtocol' type FollowPendingTxPopup = { showPopup: boolean - lastOrderPopupClosed: OrderID | undefined + lastOrderPopupClosed: string | undefined hidePopupPermanently: boolean } diff --git a/apps/cowswap-frontend/src/modules/wallet/utils/PermitProviderConnector.ts b/apps/cowswap-frontend/src/modules/wallet/utils/PermitProviderConnector.ts new file mode 100644 index 0000000000..8a8f6c47c0 --- /dev/null +++ b/apps/cowswap-frontend/src/modules/wallet/utils/PermitProviderConnector.ts @@ -0,0 +1,73 @@ +import { getContract } from '@cowprotocol/common-utils' +import { defaultAbiCoder, ParamType } from '@ethersproject/abi' +import { TypedDataField } from '@ethersproject/abstract-signer' +import { BigNumber } from '@ethersproject/bignumber' +import type { Web3Provider } from '@ethersproject/providers' +import { Wallet } from '@ethersproject/wallet' + +import { AbiItem, EIP712TypedData, ProviderConnector } from '@1inch/permit-signed-approvals-utils' +import { AbiInput } from 'web3-utils' + +export class PermitProviderConnector implements ProviderConnector { + constructor(private provider: Web3Provider, private walletSigner?: Wallet | undefined) {} + + contractEncodeABI(abi: AbiItem[], address: string | null, methodName: string, methodParams: unknown[]): string { + const contract = getContract(address || '', abi, this.provider) + + return contract.interface.encodeFunctionData(methodName, methodParams) + } + + signTypedData(_walletAddress: string, typedData: EIP712TypedData, _typedDataHash: string): Promise { + // Removes `EIP712Domain` as it's already part of EIP712 (see https://ethereum.stackexchange.com/a/151930/55204) + // and EthersJS complains when a type is not needed (see https://github.com/ethers-io/ethers.js/discussions/4000) + const types = Object.keys(typedData.types).reduce>((acc, type) => { + if (type !== 'EIP712Domain') { + acc[type] = typedData.types[type] + } + return acc + }, {}) + + const signer = this.walletSigner || this.provider.getSigner() + + return signer._signTypedData(typedData.domain, types, typedData.message) + } + + ethCall(contractAddress: string, callData: string): Promise { + return this.provider.call({ + to: contractAddress, + data: callData, + }) + } + + decodeABIParameter(type: string, hex: string): T { + return defaultAbiCoder.decode([type], hex)[0] + } + decodeABIParameters(types: AbiInput[], hex: string): T { + const decodedValues = defaultAbiCoder.decode(types as unknown as (ParamType | string)[], hex) as T + + // Ethersjs decodes numbers as BigNumber instances + // However, 1inch utils do not deal with BigNumber instances, + // so we need this mess to convert them to hex strings, which 1inch understands + // TODO: Any way to make this typing mess any cleaner? + if (decodedValues && typeof decodedValues === 'object') { + const copy: Record = {} + + Object.keys(decodedValues).forEach((key) => { + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore + const value = decodedValues[key] + if (BigNumber.isBigNumber(value)) { + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore + copy[key] = value.toHexString() + } else { + copy[key] = value + } + }) + + return copy as T + } + + return decodedValues + } +} diff --git a/apps/cowswap-frontend/src/modules/wallet/web3-react/connection/asyncConnector.ts b/apps/cowswap-frontend/src/modules/wallet/web3-react/connection/asyncConnector.ts deleted file mode 100644 index dc2e46961e..0000000000 --- a/apps/cowswap-frontend/src/modules/wallet/web3-react/connection/asyncConnector.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { Actions, Connector } from '@web3-react/types' - -/** - * To avoid including external libs for wallet connection in the bundle - * We load them in runtime by demand - */ -export class AsyncConnector extends Connector { - constructor(private loader: () => Promise, actions: Actions, onError?: (error: Error) => void) { - super(actions, onError) - } - - activate(...args: unknown[]): Promise | void { - return this.loader().then((connector) => { - // There is a magic - we change async-connector prototype to the loaded connector - ;(this as any).__proto__ = connector - return connector.activate(...args) - }) - } - - async connectEagerly(...args: unknown[]) { - return this.loader().then((connector) => { - // There is a magic - we change async-connector prototype to the loaded connector - ;(this as any).__proto__ = connector - return connector.connectEagerly?.(...args) - }) - } -} diff --git a/apps/cowswap-frontend/src/modules/wallet/web3-react/connection/formatic.tsx b/apps/cowswap-frontend/src/modules/wallet/web3-react/connection/formatic.tsx deleted file mode 100644 index 704082274d..0000000000 --- a/apps/cowswap-frontend/src/modules/wallet/web3-react/connection/formatic.tsx +++ /dev/null @@ -1,50 +0,0 @@ -import { initializeConnector } from '@web3-react/core' - -import { useIsActiveWallet } from 'legacy/hooks/useIsActiveWallet' - -import { ConnectionType } from 'modules/wallet' -import { default as FormaticImage } from 'modules/wallet/api/assets/formatic.png' -import { ConnectWalletOption } from 'modules/wallet/api/pure/ConnectWalletOption' -import { getConnectionName } from 'modules/wallet/api/utils/connection' - -import { AsyncConnector } from './asyncConnector' - -import { Web3ReactConnection } from '../types' - -import { TryActivation } from '.' - -const [web3Fortmatic, web3FortmaticHooks] = initializeConnector( - (actions) => - new AsyncConnector( - () => - Promise.all([import('@web3-react/eip1193'), import('fortmatic')]).then(([{ EIP1193 }, m]) => { - const Fortmatic = m.default - return new EIP1193({ actions, provider: new Fortmatic(process.env.REACT_APP_FORTMATIC_KEY).getProvider() }) - }), - actions - ) -) -export const fortmaticConnection: Web3ReactConnection = { - connector: web3Fortmatic, - hooks: web3FortmaticHooks, - type: ConnectionType.FORTMATIC, -} - -export const formaticOption = { - color: '#6748FF', - icon: FormaticImage, - id: 'fortmatic', -} - -export function FortmaticOption({ tryActivation }: { tryActivation: TryActivation }) { - const isActive = useIsActiveWallet(fortmaticConnection) - - return ( - tryActivation(fortmaticConnection.connector)} - header={getConnectionName(ConnectionType.FORTMATIC)} - /> - ) -} diff --git a/apps/cowswap-frontend/src/modules/wallet/web3-react/connection/index.tsx b/apps/cowswap-frontend/src/modules/wallet/web3-react/connection/index.tsx deleted file mode 100644 index ddd5c5c003..0000000000 --- a/apps/cowswap-frontend/src/modules/wallet/web3-react/connection/index.tsx +++ /dev/null @@ -1,174 +0,0 @@ -import { SupportedChainId } from '@cowprotocol/cow-sdk' -import { Connector } from '@web3-react/types' - -import { ALL_SUPPORTED_CHAIN_IDS } from 'legacy/constants/chains' -import { isMobile } from 'legacy/utils/userAgent' - -import { getIsCoinbaseWallet, getIsInjected, getIsMetaMask } from 'modules/wallet/api/utils/connection' - -import { FeatureGuard } from 'common/containers/FeatureGuard' - -import { AlphaOption } from './alpha' -import { AmbireOption } from './ambire' -import { coinbaseWalletConnection, CoinbaseWalletOption } from './coinbase' -import { fortmaticConnection } from './formatic' -import { - injectedConnection, - InjectedOption, - InstallMetaMaskOption, - MetaMaskOption, - OpenMetaMaskMobileOption, -} from './injected' -import { injectedWidgetConnection } from './injectedWidget' -import { InstallKeystoneOption, keystoneConnection, KeystoneOption } from './keystone' -import { ledgerConnection, LedgerOption } from './ledger' -import { networkConnection } from './network' -import { gnosisSafeConnection } from './safe' -import { tallyWalletConnection } from './tally' -import { trezorConnection, TrezorOption } from './trezor' -import { trustWalletConnection, TrustWalletOption } from './trust' -import { walletConnectConnection, WalletConnectOption } from './walletConnect' -import { walletConnectConnectionV2, WalletConnectV2Option } from './walletConnectV2' - -import { ConnectionType } from '../../api/types' -import { Web3ReactConnection } from '../types' - -const allowedChainsByWallet: Record = { - [ConnectionType.FORTMATIC]: [SupportedChainId.MAINNET], - [ConnectionType.INJECTED]: ALL_SUPPORTED_CHAIN_IDS, - [ConnectionType.INJECTED_WIDGET]: ALL_SUPPORTED_CHAIN_IDS, - [ConnectionType.COINBASE_WALLET]: ALL_SUPPORTED_CHAIN_IDS, - [ConnectionType.WALLET_CONNECT]: ALL_SUPPORTED_CHAIN_IDS, - [ConnectionType.WALLET_CONNECT_V2]: ALL_SUPPORTED_CHAIN_IDS, - [ConnectionType.NETWORK]: ALL_SUPPORTED_CHAIN_IDS, - [ConnectionType.GNOSIS_SAFE]: ALL_SUPPORTED_CHAIN_IDS, - [ConnectionType.TALLY]: ALL_SUPPORTED_CHAIN_IDS, - [ConnectionType.TRUST]: ALL_SUPPORTED_CHAIN_IDS, - [ConnectionType.LEDGER]: ALL_SUPPORTED_CHAIN_IDS, - [ConnectionType.TREZOR]: ALL_SUPPORTED_CHAIN_IDS, - [ConnectionType.KEYSTONE]: ALL_SUPPORTED_CHAIN_IDS, - [ConnectionType.ALPHA]: [], - [ConnectionType.AMBIRE]: [], - [ConnectionType.ZENGO]: [], -} - -export function isChainAllowed(connector: Connector, chainId: number): boolean { - const connection = getWeb3ReactConnection(connector) - - return allowedChainsByWallet[connection.type].includes(chainId) -} - -const connectionTypeToConnection: Record = { - [ConnectionType.INJECTED]: injectedConnection, - [ConnectionType.COINBASE_WALLET]: coinbaseWalletConnection, - [ConnectionType.WALLET_CONNECT]: walletConnectConnection, - [ConnectionType.WALLET_CONNECT_V2]: walletConnectConnectionV2, - [ConnectionType.ZENGO]: walletConnectConnection, - [ConnectionType.FORTMATIC]: fortmaticConnection, - [ConnectionType.NETWORK]: networkConnection, - [ConnectionType.GNOSIS_SAFE]: gnosisSafeConnection, - [ConnectionType.AMBIRE]: walletConnectConnection, - [ConnectionType.ALPHA]: walletConnectConnection, - [ConnectionType.TALLY]: tallyWalletConnection, - [ConnectionType.TRUST]: trustWalletConnection, - [ConnectionType.LEDGER]: ledgerConnection, - [ConnectionType.KEYSTONE]: keystoneConnection, - [ConnectionType.INJECTED_WIDGET]: injectedWidgetConnection, - [ConnectionType.TREZOR]: trezorConnection, -} - -const CONNECTIONS: Web3ReactConnection[] = Object.values(connectionTypeToConnection) - -// TODO: add others -export const HARDWARE_WALLETS = [ConnectionType.TREZOR] as const - -export type HardWareWallet = (typeof HARDWARE_WALLETS)[number] - -export const getIsHardWareWallet = (connectionType: ConnectionType) => - HARDWARE_WALLETS.includes(connectionType as HardWareWallet) - -export function getWeb3ReactConnection(c: Connector | ConnectionType): Web3ReactConnection { - if (c instanceof Connector) { - const connection = CONNECTIONS.find((connection) => connection.connector === c) - if (!connection) { - throw Error('unsupported connector') - } - return connection - } - - return connectionTypeToConnection[c] -} - -export type TryActivation = (connector: Connector) => void - -export function ConnectWalletOptions({ tryActivation }: { tryActivation: TryActivation }) { - const isInjected = getIsInjected() - const isMetaMask = getIsMetaMask() - const isCoinbaseWallet = getIsCoinbaseWallet() - - const isCoinbaseWalletBrowser = isMobile && isCoinbaseWallet - const isMetaMaskBrowser = isMobile && isMetaMask - const isInjectedMobileBrowser = isCoinbaseWalletBrowser || isMetaMaskBrowser - // const isChromeMobile = isMobile && isChrome - const showKeystone = !isInjectedMobileBrowser && !isMobile && window.ethereum?.isMetaMask - - // Show Tally option only in Chrome (includes Brave too), but not on mobile or as an injected browser - // const showTally = !isInjectedMobileBrowser && isChrome && !isChromeMobile - - let injectedOption - if (!isInjected) { - if (!isMobile) { - injectedOption = - } else { - injectedOption = - } - } else { - if (isMetaMask) { - injectedOption = - } else { - injectedOption = - } - } - - const coinbaseWalletOption = - - const walletConnectionOption = - (!isInjectedMobileBrowser && ) ?? null - - const walletConnectionV2Option = - (!isInjectedMobileBrowser && ) ?? null - - // Wallet-connect based - // const zengoOption = (!isInjectedMobileBrowser && ) ?? null - const ambireOption = (!isInjectedMobileBrowser && ) ?? null - const alphaOption = (!isInjectedMobileBrowser && ) ?? null - const ledgerOption = (!isInjectedMobileBrowser && !isMobile && ) ?? null - const trezorOption = (!isInjectedMobileBrowser && !isMobile && ) ?? null - const keystoneOption = - (showKeystone && ) || (!isMobile && ) - - // Injected - // const tallyOption = (showTally && ) ?? null - const trustOption = (!isInjectedMobileBrowser && ) ?? null - - return ( - <> - {injectedOption} - {walletConnectionOption} - {walletConnectionV2Option} - {coinbaseWalletOption} - {ledgerOption} - {trezorOption} - {/*{zengoOption}*/} - {ambireOption} - {alphaOption} - {/* {tallyOption} */} - {trustOption} - {keystoneOption} - - ) -} - -export function onError(error: Error) { - console.debug(`[web3-react] Error: ${error}`) -} diff --git a/apps/cowswap-frontend/src/modules/wallet/web3-react/connection/walletConnect.tsx b/apps/cowswap-frontend/src/modules/wallet/web3-react/connection/walletConnect.tsx deleted file mode 100644 index d6bc8bd9d0..0000000000 --- a/apps/cowswap-frontend/src/modules/wallet/web3-react/connection/walletConnect.tsx +++ /dev/null @@ -1,90 +0,0 @@ -import { useMemo } from 'react' - -import { initializeConnector } from '@web3-react/core' -import { WalletConnect } from '@web3-react/walletconnect' - -import { RPC_URLS } from 'legacy/constants/networks' -import { useIsActiveWallet } from 'legacy/hooks/useIsActiveWallet' - -import { ConnectionType, useWalletMetaData } from 'modules/wallet' -import { default as WalletConnectImage } from 'modules/wallet/api/assets/walletConnectIcon.svg' -import { ConnectWalletOption } from 'modules/wallet/api/pure/ConnectWalletOption' -import { - getConnectionName, - getIsAlphaWallet, - getIsAmbireWallet, - getIsTrustWallet, - getIsZengoWallet, -} from 'modules/wallet/api/utils/connection' -import { WC_DISABLED_TEXT } from 'modules/wallet/constants' - -import { useFeatureFlags } from 'common/hooks/featureFlags/useFeatureFlags' - -import { Web3ReactConnection } from '../types' - -import { onError, TryActivation } from '.' - -const WC_SUNSET_LINK = - 'https://medium.com/walletconnect/weve-reset-the-clock-on-the-walletconnect-v1-0-shutdown-now-scheduled-for-june-28-2023-ead2d953b595' -const WC_SUNSET_TEXT = - 'The WalletConnect v1.0 protocol has been shut down on June 28, 2023 at 2pm (UTC). Click to read more.' - -export const walletConnectOption = { - color: '#4196FC', - icon: WalletConnectImage, - id: 'wallet-connect', -} - -const [web3WalletConnect, web3WalletConnectHooks] = initializeConnector( - (actions) => - new WalletConnect({ - actions, - options: { - rpc: RPC_URLS, - qrcode: true, - bridge: process.env.REACT_APP_WALLET_CONNECT_V1_BRIDGE || 'https://safe-walletconnect.safe.global', - }, - onError, - }) -) -export const walletConnectConnection: Web3ReactConnection = { - connector: web3WalletConnect, - hooks: web3WalletConnectHooks, - type: ConnectionType.WALLET_CONNECT, -} - -export function WalletConnectOption({ tryActivation }: { tryActivation: TryActivation }) { - const { walletName } = useWalletMetaData() - const { walletConnectV1Deprecated: isDeprecated } = useFeatureFlags() - - const isWalletConnect = useIsActiveWallet(walletConnectConnection) - const isActive = - isWalletConnect && - !getIsZengoWallet(walletName) && - !getIsAmbireWallet(walletName) && - !getIsAlphaWallet(walletName) && - !getIsTrustWallet(walletName) - - const tooltipText = useMemo(() => { - if (isDeprecated) { - return WC_SUNSET_TEXT - } - - return !isActive && isWalletConnect ? WC_DISABLED_TEXT : null - }, [isActive, isWalletConnect, isDeprecated]) - - const link = isDeprecated ? WC_SUNSET_LINK : null - - return ( - (!isDeprecated ? tryActivation(walletConnectConnection.connector) : null)} - header={getConnectionName(ConnectionType.WALLET_CONNECT)} - /> - ) -} diff --git a/apps/cowswap-frontend/src/pages/About/index.tsx b/apps/cowswap-frontend/src/pages/About/index.tsx index 0cca13a89f..91712a3f34 100644 --- a/apps/cowswap-frontend/src/pages/About/index.tsx +++ b/apps/cowswap-frontend/src/pages/About/index.tsx @@ -1,15 +1,12 @@ -// Assets +import diagramIMG from '@cowprotocol/assets/cow-swap/cowswap-diagram.png' +import gaslessIMG from '@cowprotocol/assets/cow-swap/gasless.png' +import mevIMG from '@cowprotocol/assets/cow-swap/mev.png' +import { MEV_TOTAL, FLASHBOTS_LINK } from '@cowprotocol/common-const' +import { ExternalLink as ExternalLinkTheme } from '@cowprotocol/ui' + import { Link } from 'react-router-dom' import styled from 'styled-components/macro' -import diagramIMG from 'legacy/assets/cow-swap/cowswap-diagram.png' -import gaslessIMG from 'legacy/assets/cow-swap/gasless.png' -import mevIMG from 'legacy/assets/cow-swap/mev.png' -import { PageName } from 'legacy/components/AmplitudeAnalytics/constants' -import { Trace } from 'legacy/components/AmplitudeAnalytics/Trace' -import { MEV_TOTAL, FLASHBOTS_LINK } from 'legacy/constants' -import { ExternalLink as ExternalLinkTheme } from 'legacy/theme' - import { PageTitle } from 'modules/application/containers/PageTitle' import { Page, Title, Content, GdocsListStyle } from 'modules/application/pure/Page' @@ -32,7 +29,7 @@ const Wrapper = styled(Page)` export default function About() { return ( - + <> About @@ -115,6 +112,6 @@ export default function About() {

-
+ ) } diff --git a/apps/cowswap-frontend/src/pages/Account/Balances.tsx b/apps/cowswap-frontend/src/pages/Account/Balances.tsx index d889b18846..63b4991a21 100644 --- a/apps/cowswap-frontend/src/pages/Account/Balances.tsx +++ b/apps/cowswap-frontend/src/pages/Account/Balances.tsx @@ -1,5 +1,15 @@ import { useCallback, useEffect, useMemo, useState } from 'react' +import ArrowIcon from '@cowprotocol/assets/cow-swap/arrow.svg' +import CowImage from '@cowprotocol/assets/cow-swap/cow_v2.svg' +import vCOWImage from '@cowprotocol/assets/cow-swap/vCOW.png' +import { COW, COW_CONTRACT_ADDRESS, V_COW, V_COW_CONTRACT_ADDRESS } from '@cowprotocol/common-const' +import { usePrevious } from '@cowprotocol/common-hooks' +import { useBlockNumber } from '@cowprotocol/common-hooks' +import { getBlockExplorerUrl, getProviderErrorMessage } from '@cowprotocol/common-utils' +import { TokenAmount, ButtonPrimary } from '@cowprotocol/ui' +import { MouseoverTooltipContent } from '@cowprotocol/ui' +import { useWalletInfo } from '@cowprotocol/wallet' import { CurrencyAmount } from '@uniswap/sdk-core' import { useWeb3React } from '@web3-react/core' import { MetaMask } from '@web3-react/metamask' @@ -8,31 +18,17 @@ import { Trans } from '@lingui/macro' import SVG from 'react-inlinesvg' import { Link } from 'react-router-dom' -import ArrowIcon from 'legacy/assets/cow-swap/arrow.svg' -import CowImage from 'legacy/assets/cow-swap/cow_v2.svg' -import vCOWImage from 'legacy/assets/cow-swap/vCOW.png' -import { ButtonPrimary } from 'legacy/components/Button' import CopyHelper from 'legacy/components/Copy' -import { MouseoverTooltipContent } from 'legacy/components/Tooltip' -import { ConfirmOperationType } from 'legacy/components/TransactionConfirmationModal' -import { V_COW_CONTRACT_ADDRESS, COW_CONTRACT_ADDRESS } from 'legacy/constants' -import { COW, V_COW } from 'legacy/constants/tokens' import { useErrorModal } from 'legacy/hooks/useErrorMessageAndModal' -import usePrevious from 'legacy/hooks/usePrevious' import useTransactionConfirmationModal from 'legacy/hooks/useTransactionConfirmationModal' import { SwapVCowStatus } from 'legacy/state/cowToken/actions' import { useVCowData, useSwapVCowCallback, useSetSwapVCowStatus, useSwapVCowStatus } from 'legacy/state/cowToken/hooks' -import { getBlockExplorerUrl } from 'legacy/utils' -import { getProviderErrorMessage } from 'legacy/utils/misc' +import { ConfirmOperationType } from 'legacy/state/types' import { useTokenBalance } from 'modules/tokens/hooks/useCurrencyBalance' -import { useWalletInfo } from 'modules/wallet' -import AddToMetamask from 'modules/wallet/web3-react/containers/AddToMetamask' import { useIsProviderNetworkUnsupported } from 'common/hooks/useIsProviderNetworkUnsupported' import { HelpCircle } from 'common/pure/HelpCircle' -import { TokenAmount } from 'common/pure/TokenAmount' -import useBlockNumber from 'lib/hooks/useBlockNumber' import { useCowFromLockedGnoBalances } from 'pages/Account/LockedGnoVesting/hooks' import { ExtLink, @@ -43,6 +39,7 @@ import { VestingBreakdown, CardsLoader, CardsSpinner, + StyledAddToMetamask, } from 'pages/Account/styled' import LockedGnoVesting from './LockedGnoVesting' @@ -285,7 +282,7 @@ export default function Profile() { View contract ↗ - {isMetaMask && !isProviderNetworkUnsupported && } + {isMetaMask && !isProviderNetworkUnsupported && } {!isMetaMask && ( diff --git a/apps/cowswap-frontend/src/pages/Account/Governance.tsx b/apps/cowswap-frontend/src/pages/Account/Governance.tsx index 5ea6b8832f..5d20432fe4 100644 --- a/apps/cowswap-frontend/src/pages/Account/Governance.tsx +++ b/apps/cowswap-frontend/src/pages/Account/Governance.tsx @@ -1,4 +1,4 @@ -import CowProtocolImage from 'legacy/assets/cow-swap/cowprotocol.svg' +import CowProtocolImage from '@cowprotocol/assets/cow-swap/cowprotocol.svg' import { ExtLink, BannerCard, BannerCardContent, BannerCardSvg, CardActions } from './styled' diff --git a/apps/cowswap-frontend/src/pages/Account/LockedGnoVesting/hooks.ts b/apps/cowswap-frontend/src/pages/Account/LockedGnoVesting/hooks.ts index 84438a7dae..c0810359fb 100644 --- a/apps/cowswap-frontend/src/pages/Account/LockedGnoVesting/hooks.ts +++ b/apps/cowswap-frontend/src/pages/Account/LockedGnoVesting/hooks.ts @@ -1,32 +1,35 @@ import { useCallback, useEffect, useMemo, useRef, useState } from 'react' +import { MerkleDrop, TokenDistro, MerkleDropAbi, TokenDistroAbi } from '@cowprotocol/abis' +import { + COW, + LOCKED_GNO_VESTING_DURATION, + LOCKED_GNO_VESTING_START_TIME, + MERKLE_DROP_CONTRACT_ADDRESSES, + TOKEN_DISTRO_CONTRACT_ADDRESSES, +} from '@cowprotocol/common-const' +import { useContract } from '@cowprotocol/common-hooks' import { SupportedChainId } from '@cowprotocol/cow-sdk' -import { MerkleDrop, TokenDistro, MerkleDropAbi, TokenDistroAbi } from '@cowswap/abis' +import { useWalletInfo } from '@cowprotocol/wallet' import { ContractTransaction } from '@ethersproject/contracts' import { CurrencyAmount, Token } from '@uniswap/sdk-core' -import { ConfirmOperationType } from 'legacy/components/TransactionConfirmationModal' -import { LOCKED_GNO_VESTING_START_TIME, LOCKED_GNO_VESTING_DURATION } from 'legacy/constants' -import { COW as COW_TOKENS } from 'legacy/constants/tokens' -import { MERKLE_DROP_CONTRACT_ADDRESSES, TOKEN_DISTRO_CONTRACT_ADDRESSES } from 'legacy/constants/tokens' -import { useContract } from 'legacy/hooks/useContract' import { useTransactionAdder } from 'legacy/state/enhancedTransactions/hooks' - -import { useWalletInfo } from 'modules/wallet' +import { ConfirmOperationType } from 'legacy/state/types' import { useSingleCallResult } from 'lib/hooks/multicall' import { fetchClaim } from './claimData' // We just generally use the mainnet version. We don't read from the contract anyways so the address doesn't matter -const COW = COW_TOKENS[SupportedChainId.MAINNET] +const _COW = COW[SupportedChainId.MAINNET] const useMerkleDropContract = () => useContract(MERKLE_DROP_CONTRACT_ADDRESSES, MerkleDropAbi, true) const useTokenDistroContract = () => useContract(TOKEN_DISTRO_CONTRACT_ADDRESSES, TokenDistroAbi, true) export const useAllocation = (): CurrencyAmount => { const { chainId, account } = useWalletInfo() - const initialAllocation = useRef(CurrencyAmount.fromRawAmount(COW, 0)) + const initialAllocation = useRef(CurrencyAmount.fromRawAmount(_COW, 0)) const [allocation, setAllocation] = useState(initialAllocation.current) useEffect(() => { @@ -34,7 +37,7 @@ export const useAllocation = (): CurrencyAmount => { if (account && chainId) { fetchClaim(account, chainId).then((claim) => { if (!canceled) { - setAllocation(CurrencyAmount.fromRawAmount(COW, claim?.amount ?? 0)) + setAllocation(CurrencyAmount.fromRawAmount(_COW, claim?.amount ?? 0)) } }) } else { @@ -59,7 +62,7 @@ export const useCowFromLockedGnoBalances = () => { const { result, loading } = useSingleCallResult(allocated.greaterThan(0) ? tokenDistro : null, 'balances', [ account ?? undefined, ]) - const claimed = useMemo(() => CurrencyAmount.fromRawAmount(COW, result ? result.claimed.toString() : 0), [result]) + const claimed = useMemo(() => CurrencyAmount.fromRawAmount(_COW, result ? result.claimed.toString() : 0), [result]) return { allocated, diff --git a/apps/cowswap-frontend/src/pages/Account/LockedGnoVesting/index.tsx b/apps/cowswap-frontend/src/pages/Account/LockedGnoVesting/index.tsx index bcd3ad354f..372e71f18f 100644 --- a/apps/cowswap-frontend/src/pages/Account/LockedGnoVesting/index.tsx +++ b/apps/cowswap-frontend/src/pages/Account/LockedGnoVesting/index.tsx @@ -1,32 +1,35 @@ import { useCallback, useState, useEffect } from 'react' +import { claimAnalytics } from '@cowprotocol/analytics' +import ArrowIcon from '@cowprotocol/assets/cow-swap/arrow.svg' +import cowImage from '@cowprotocol/assets/cow-swap/cow_v2.svg' +import { + LOCKED_GNO_VESTING_START_DATE, + MERKLE_DROP_CONTRACT_ADDRESSES, + TOKEN_DISTRO_CONTRACT_ADDRESSES, +} from '@cowprotocol/common-const' +import { usePrevious } from '@cowprotocol/common-hooks' +import { + formatDateWithTimezone, + getBlockExplorerUrl, + getProviderErrorMessage, + isRejectRequestProviderError, +} from '@cowprotocol/common-utils' import { SupportedChainId as ChainId } from '@cowprotocol/cow-sdk' +import { ButtonSize, TokenAmount, ButtonPrimary } from '@cowprotocol/ui' +import { MouseoverTooltipContent } from '@cowprotocol/ui' +import { useWalletInfo } from '@cowprotocol/wallet' import { CurrencyAmount, Currency } from '@uniswap/sdk-core' import { Trans } from '@lingui/macro' import SVG from 'react-inlinesvg' -import ArrowIcon from 'legacy/assets/cow-swap/arrow.svg' -import cowImage from 'legacy/assets/cow-swap/cow_v2.svg' -import { claimAnalytics } from 'legacy/components/analytics' -import { ButtonPrimary } from 'legacy/components/Button' import CopyHelper from 'legacy/components/Copy' -import { MouseoverTooltipContent } from 'legacy/components/Tooltip' -import { ConfirmOperationType } from 'legacy/components/TransactionConfirmationModal' -import { LOCKED_GNO_VESTING_START_DATE } from 'legacy/constants' -import { MERKLE_DROP_CONTRACT_ADDRESSES, TOKEN_DISTRO_CONTRACT_ADDRESSES } from 'legacy/constants/tokens' import { useErrorModal } from 'legacy/hooks/useErrorMessageAndModal' -import usePrevious from 'legacy/hooks/usePrevious' -import { ButtonSize } from 'legacy/theme/enum' -import { getBlockExplorerUrl } from 'legacy/utils' -import { getProviderErrorMessage, isRejectRequestProviderError } from 'legacy/utils/misc' - -import { useWalletInfo } from 'modules/wallet' +import { ConfirmOperationType } from 'legacy/state/types' import { HelpCircle } from 'common/pure/HelpCircle' -import { TokenAmount } from 'common/pure/TokenAmount' import { Card, BalanceDisplay, ConvertWrapper, VestingBreakdown, CardActions, ExtLink } from 'pages/Account/styled' -import { formatDateWithTimezone } from 'utils/time' import { useClaimCowFromLockedGnoCallback } from './hooks' diff --git a/apps/cowswap-frontend/src/pages/Account/Menu.tsx b/apps/cowswap-frontend/src/pages/Account/Menu.tsx index c38569b496..c358e6f6f4 100644 --- a/apps/cowswap-frontend/src/pages/Account/Menu.tsx +++ b/apps/cowswap-frontend/src/pages/Account/Menu.tsx @@ -1,7 +1,8 @@ +import { ACCOUNT_MENU_LINKS } from '@cowprotocol/common-const' + import { NavLink } from 'react-router-dom' import { SideMenu } from 'legacy/components/SideMenu' -import { ACCOUNT_MENU_LINKS } from 'legacy/constants' export function AccountMenu() { return ( diff --git a/apps/cowswap-frontend/src/pages/Account/Tokens/TokensOverview.tsx b/apps/cowswap-frontend/src/pages/Account/Tokens/TokensOverview.tsx index e68d39aa4e..cdcfa8efb1 100644 --- a/apps/cowswap-frontend/src/pages/Account/Tokens/TokensOverview.tsx +++ b/apps/cowswap-frontend/src/pages/Account/Tokens/TokensOverview.tsx @@ -1,29 +1,22 @@ import { useEffect, useMemo, useState, useCallback, useRef, ChangeEventHandler } from 'react' +import { useDebounce, useOnClickOutside, usePrevious, useTheme } from '@cowprotocol/common-hooks' +import { isAddress, isTruthy } from '@cowprotocol/common-utils' +import { useWalletInfo } from '@cowprotocol/wallet' import { Token } from '@uniswap/sdk-core' import { useWeb3React } from '@web3-react/core' import { Trans, t } from '@lingui/macro' import { Check } from 'react-feather' -import { PageName } from 'legacy/components/AmplitudeAnalytics/constants' -import { Trace } from 'legacy/components/AmplitudeAnalytics/Trace' import { ContentWrapper as SearchInputFormatter } from 'legacy/components/SearchModal/CurrencySearch' import { TokenSearchInput } from 'legacy/components/Tokens/styled' import TokensTable from 'legacy/components/Tokens/TokensTable' -import { useAllTokens } from 'legacy/hooks/Tokens' -import useDebounce from 'legacy/hooks/useDebounce' -import { useOnClickOutside } from 'legacy/hooks/useOnClickOutside' -import usePrevious from 'legacy/hooks/usePrevious' -import useTheme from 'legacy/hooks/useTheme' -import { useAllTokenBalances } from 'legacy/state/connection/hooks' +import { useAllTokenBalances, useAllTokens } from 'legacy/hooks/Tokens' import { useFavouriteTokens, useRemoveAllFavouriteTokens, useInitFavouriteTokens } from 'legacy/state/user/hooks' import { CloseIcon } from 'legacy/theme' -import { isAddress } from 'legacy/utils' -import { isTruthy } from 'legacy/utils/misc' import { PageTitle } from 'modules/application/containers/PageTitle' -import { useWalletInfo } from 'modules/wallet' import { useIsProviderNetworkUnsupported } from 'common/hooks/useIsProviderNetworkUnsupported' @@ -156,7 +149,7 @@ export default function TokensOverview() { }, [account, chainId, prevAccount, prevChainId, prevSelectedView, selectedView]) return ( - + <> {!isProviderNetworkUnsupported && ( @@ -214,6 +207,6 @@ export default function TokensOverview() { {isProviderNetworkUnsupported ? 'Unsupported network' : renderTableContent()} - + ) } diff --git a/apps/cowswap-frontend/src/pages/Account/Tokens/styled.ts b/apps/cowswap-frontend/src/pages/Account/Tokens/styled.ts index dfd53aa438..d4f614d7b0 100644 --- a/apps/cowswap-frontend/src/pages/Account/Tokens/styled.ts +++ b/apps/cowswap-frontend/src/pages/Account/Tokens/styled.ts @@ -4,6 +4,7 @@ import styled from 'styled-components/macro' import { ThemedText } from 'legacy/theme' +import { UI } from 'common/constants/theme' import { Card } from 'pages/Account/styled' export const MenuWrapper = styled.div` @@ -15,8 +16,8 @@ export const MenuButton = styled.button` outline: none; border: none; cursor: pointer; - color: ${({ theme }) => theme.text1}; - background: ${({ theme }) => theme.bg1}; + color: var(${UI.COLOR_TEXT1}); + background: var(${UI.COLOR_CONTAINER_BG_01}); height: 44px; border-radius: 21px; padding: 0 16px; @@ -86,7 +87,7 @@ export const AccountPageWrapper = styled.div` ` export const MainText = styled(ThemedText.Main)` - color: ${({ theme }) => theme.text1}; + color: var(${UI.COLOR_TEXT1}); font-size: 14px; ` @@ -130,7 +131,7 @@ export const ClearSearchInput = styled.div` ` export const Overview = styled.div` - background: ${({ theme }) => theme.bg1}; + background: var(${UI.COLOR_CONTAINER_BG_01}); border-radius: 16px; gap: 16px; margin: 0; diff --git a/apps/cowswap-frontend/src/pages/Account/index.tsx b/apps/cowswap-frontend/src/pages/Account/index.tsx index 645d6d2c90..9a80bfb7f1 100644 --- a/apps/cowswap-frontend/src/pages/Account/index.tsx +++ b/apps/cowswap-frontend/src/pages/Account/index.tsx @@ -2,8 +2,6 @@ import { lazy, Suspense } from 'react' import { useLocation, Outlet } from 'react-router-dom' -import { PageName } from 'legacy/components/AmplitudeAnalytics/constants' -import { Trace } from 'legacy/components/AmplitudeAnalytics/Trace' import { Loading } from 'legacy/components/FlashingLoading' import { PageTitle } from 'modules/application/containers/PageTitle' @@ -35,7 +33,7 @@ function _getPropsFromRoute(route: string) { // Note: As we build these single pages, we will remove this component in the future export const AccountOverview = () => { return ( - + <> @@ -43,7 +41,7 @@ export const AccountOverview = () => { - + ) } diff --git a/apps/cowswap-frontend/src/pages/Account/styled.tsx b/apps/cowswap-frontend/src/pages/Account/styled.tsx index 590b6e245a..ab2e53a4d2 100644 --- a/apps/cowswap-frontend/src/pages/Account/styled.tsx +++ b/apps/cowswap-frontend/src/pages/Account/styled.tsx @@ -1,15 +1,14 @@ -import * as CSS from 'csstype' +import { Loader as SpinnerLoader, ButtonPrimary } from '@cowprotocol/ui' +import { ExternalLink } from '@cowprotocol/ui' + import { transparentize } from 'polished' import SVG from 'react-inlinesvg' import styled, { css } from 'styled-components/macro' -import { ButtonPrimary } from 'legacy/components/Button' import { CopyIcon as ClickToCopy } from 'legacy/components/Copy' -import SpinnerLoader from 'legacy/components/Loader' -import { ExternalLink } from 'legacy/theme' import { Page, GdocsListStyle } from 'modules/application/pure/Page' -import { ButtonCustom as AddToMetaMask } from 'modules/wallet/api/pure/AddToMetamask' +import { AddToMetamask } from 'modules/wallet/containers/AddToMetamask' import { BannerExplainer } from 'pages/Claim/styled' @@ -55,138 +54,59 @@ export const ExtLink = styled(ExternalLink)` } ` -export const ChildWrapper = styled.div` +const linkMixin = css` + font-size: 13px; + height: 100%; + font-weight: 500; + border-radius: 0; + min-height: initial; + margin: 0; + padding: 0; + line-height: 1; + color: ${({ theme }) => transparentize(0.3, theme.text1)}; display: flex; - flex-direction: column; align-items: center; - flex-grow: 1; - justify-content: center; - border-radius: 21px; - padding: 20px; - background-color: ${({ theme }) => theme.grey1}; + text-decoration: underline; + text-decoration-color: transparent; + transition: text-decoration-color 0.2s ease-in-out, color 0.2s ease-in-out; - ${({ theme }) => theme.mediaWidth.upToSmall` - grid-column-start: 1; - grid-column-end: 2; - width: 100%; - padding: 14px; - `} + ${({ theme }) => theme.mediaWidth.upToMedium` + font-size: 15px; + margin: 0 auto; + `}; - > .item { - width: 100%; + &:hover { + text-decoration-color: ${({ theme }) => theme.text1}; + color: ${({ theme }) => theme.text1}; } ` -export const GridWrap = styled.div>` - display: grid; - grid-column-gap: 22px; - grid-row-gap: 22px; - grid-template-columns: ${(props) => (props.horizontal ? '1fr 1fr' : '1fr')}; +export const StyledAddToMetamask = styled(AddToMetamask)` + border: 0; + min-height: initial; + border-radius: initial; - ${({ theme }) => theme.mediaWidth.upToSmall` - grid-template-columns: 1fr; - grid-column-gap: 0; - > :first-child, - > :nth-child(2) { - grid-column-start: 1; - grid-column-end: 2; - } - `} + &:hover { + background: transparent; - @supports (-webkit-touch-callout: none) { - /* CSS specific to iOS devices */ - display: flex; - flex-direction: column; + > div { + text-decoration: underline; + } } -` - -export const CardHead = styled.div` - display: flex; - flex-grow: 1; - flex-direction: column; -` -export const StyledTime = styled.p` - margin: 0; -` - -export const ItemTitle = styled.h3` - display: flex; - align-items: center; - margin: 0 0 16px 0; - font-size: 18px; - line-height: 1.21; - color: ${({ theme }) => theme.text1}; - gap: 4px; - - ${({ theme }) => theme.mediaWidth.upToSmall` - margin: 0 0 10px 0; - font-size: 16px; - `} -` - -export const FlexWrap = styled.div` - display: flex; - flex-grow: 1; - align-items: center; - flex-direction: row; - justify-content: center; - - > div { + > div > img, + > div > svg { + height: 13px; width: auto; + object-fit: contain; + margin: 0 6px 0 0; } - button { - max-width: 180px; - } - - ${({ theme }) => theme.mediaWidth.upToSmall` - flex-wrap: wrap; - > div { - width: 50%; - } - button { - max-width: 100%; - } - `} + ${linkMixin} ` -export const StyledContainer = styled.div` - display: flex; - flex: 1; - align-items: center; - justify-content: space-between; - - ${({ theme }) => theme.mediaWidth.upToSmall` - flex-wrap: wrap; - flex-direction: column; - `} -` - -export const FlexCol = styled.div` - display: flex; - flex-grow: 1; - align-items: center; - flex-direction: column; - justify-content: center; - - strong { - font-size: 21px; - margin-top: 6px; - - ${({ theme }) => theme.mediaWidth.upToSmall` - font-size: 14px; - `} - } - - span:not([role='img']) { - font-size: 14px; - color: ${({ theme }) => transparentize(0.3, theme.text1)}; - text-align: center; - display: flex; - align-items: center; - padding: 8px 0 0 0; - } +export const StyledTime = styled.p` + margin: 0; ` export const Loader = styled.div<{ isLoading: boolean }>` @@ -212,29 +132,6 @@ export const Loader = styled.div<{ isLoading: boolean }>` `} ` -export const ProfileGridWrap = styled(GridWrap)` - grid-template-columns: 1fr auto; - justify-content: space-between; - align-items: center; - - ${({ theme }) => theme.mediaWidth.upToSmall` - > :first-child, - > :nth-child(2) { - grid-column-start: auto; - grid-column-end: auto; - } - `}; - - ${({ theme }) => theme.mediaWidth.upToVerySmall` - > :first-child, - > :nth-child(2) { - grid-column-start: 1; - grid-column-end: 1; - } - grid-row-gap: 0px; - `}; -` - export const CardsWrapper = styled.div` display: flex; flex-flow: row wrap; @@ -455,53 +352,8 @@ export const CardActions = styled.div<{ justify?: string; content?: string }>` `}; > a, - ${AddToMetaMask}, > ${ClickToCopy} { - font-size: 13px; - height: 100%; - font-weight: 500; - border-radius: 0; - min-height: initial; - margin: 0; - padding: 0; - line-height: 1; - color: ${({ theme }) => transparentize(0.3, theme.text1)}; - display: flex; - align-items: center; - text-decoration: underline; - text-decoration-color: transparent; - transition: text-decoration-color 0.2s ease-in-out, color 0.2s ease-in-out; - - ${({ theme }) => theme.mediaWidth.upToMedium` - font-size: 15px; - margin: 0 auto; - `}; - - &:hover { - text-decoration-color: ${({ theme }) => theme.text1}; - color: ${({ theme }) => theme.text1}; - } - } - - ${AddToMetaMask} { - border: 0; - min-height: initial; - border-radius: initial; - - &:hover { - background: transparent; - - > div { - text-decoration: underline; - } - } - - > div > img, - > div > svg { - height: 13px; - width: auto; - object-fit: contain; - margin: 0 6px 0 0; - } + > ${ClickToCopy} { + ${linkMixin} } > ${ClickToCopy} svg { @@ -669,31 +521,3 @@ export const CardsSpinner = styled(SpinnerLoader)` stroke: ${({ theme }) => theme.text1}; } ` - -interface TimeProps { - date: string | undefined -} - -export const TimeFormatted = ({ date }: TimeProps) => { - if (!date) return null - - const months = [ - 'January', - 'February', - 'March', - 'April', - 'May', - 'June', - 'July', - 'August', - 'September', - 'October', - 'November', - 'December', - ] - const _date = new Date(date) - const monthName = months[_date.getMonth()] - const hours = _date.toLocaleString('en-US', { hour: 'numeric', minute: 'numeric', hour12: true }) - - return {`${_date.getDate()} ${monthName} ${_date.getFullYear()} - ${hours}`} -} diff --git a/apps/cowswap-frontend/src/pages/AdvancedOrders/index.tsx b/apps/cowswap-frontend/src/pages/AdvancedOrders/index.tsx index 876cbf5187..f41b65eb5b 100644 --- a/apps/cowswap-frontend/src/pages/AdvancedOrders/index.tsx +++ b/apps/cowswap-frontend/src/pages/AdvancedOrders/index.tsx @@ -1,24 +1,15 @@ import { useAtomValue } from 'jotai' -import { Navigate } from 'react-router-dom' - import { advancedOrdersAtom, AdvancedOrdersWidget, FillAdvancedOrdersDerivedStateUpdater } from 'modules/advancedOrders' import { OrdersTableWidget } from 'modules/ordersTable' import { TabOrderTypes } from 'modules/ordersTable/pure/OrdersTableContainer' -import { useTradeRouteContext } from 'modules/trade/hooks/useTradeRouteContext' import * as styledEl from 'modules/trade/pure/TradePageLayout' -import { parameterizeTradeRoute } from 'modules/trade/utils/parameterizeTradeRoute' import { TradeFormValidation, useGetTradeFormValidation } from 'modules/tradeFormValidation' import { TwapFormWidget, TwapUpdaters, useAllEmulatedOrders } from 'modules/twap' import { useTwapFormState } from 'modules/twap/hooks/useTwapFormState' import { TwapFormState } from 'modules/twap/pure/PrimaryActionButton/getTwapFormState' -import { Routes as RoutesEnum } from 'common/constants/routes' -import { useIsAdvancedOrdersEnabled } from 'common/hooks/useIsAdvancedOrdersEnabled' - export default function AdvancedOrdersPage() { - const isAdvancedOrdersEnabled = useIsAdvancedOrdersEnabled() - const tradeContext = useTradeRouteContext() const { isUnlocked } = useAtomValue(advancedOrdersAtom) const allEmulatedOrders = useAllEmulatedOrders() @@ -26,15 +17,6 @@ export default function AdvancedOrdersPage() { const primaryFormValidation = useGetTradeFormValidation() const twapFormValidation = useTwapFormState() - if (isAdvancedOrdersEnabled === undefined) { - return null - } - - if (!isAdvancedOrdersEnabled) { - // To prevent direct access when the flag is off - return - } - const disablePriceImpact = primaryFormValidation === TradeFormValidation.QuoteErrors || primaryFormValidation === TradeFormValidation.CurrencyNotSupported || diff --git a/apps/cowswap-frontend/src/pages/Claim/CanUserClaimMessage.tsx b/apps/cowswap-frontend/src/pages/Claim/CanUserClaimMessage.tsx index 09a1c14838..7605a44820 100644 --- a/apps/cowswap-frontend/src/pages/Claim/CanUserClaimMessage.tsx +++ b/apps/cowswap-frontend/src/pages/Claim/CanUserClaimMessage.tsx @@ -1,17 +1,17 @@ +import CowProtocolImage from '@cowprotocol/assets/cow-swap/cowprotocol.svg' +import { useNetworkName } from '@cowprotocol/common-hooks' +import { formatDateWithTimezone } from '@cowprotocol/common-utils' +import { ButtonSecondary } from '@cowprotocol/ui' +import { ExternalLink } from '@cowprotocol/ui' + import { Trans } from '@lingui/macro' import SVG from 'react-inlinesvg' -import CowProtocolImage from 'legacy/assets/cow-swap/cowprotocol.svg' -import { ButtonSecondary } from 'legacy/components/Button' -import useNetworkName from 'legacy/hooks/useNetworkName' import { ClaimStatus } from 'legacy/state/claim/actions' import { useClaimState, useClaimTimeInfo, useClaimLinks } from 'legacy/state/claim/hooks' -import { ExternalLink } from 'legacy/theme' - -import { formatDateWithTimezone } from 'utils/time' +import { ClaimCommonTypes } from 'legacy/state/claim/types' import { IntroDescription, BannerExplainer } from './styled' -import { ClaimCommonTypes } from './types' type ClaimIntroductionProps = Pick< ClaimCommonTypes, diff --git a/apps/cowswap-frontend/src/pages/Claim/ClaimAddress.tsx b/apps/cowswap-frontend/src/pages/Claim/ClaimAddress.tsx index cf029380e2..54401255a2 100644 --- a/apps/cowswap-frontend/src/pages/Claim/ClaimAddress.tsx +++ b/apps/cowswap-frontend/src/pages/Claim/ClaimAddress.tsx @@ -1,16 +1,17 @@ import { useMemo } from 'react' +import Circle from '@cowprotocol/assets/images/blue-loader.svg' +import { useENS } from '@cowprotocol/ens' +import { ButtonSecondary } from '@cowprotocol/ui' + import { Trans } from '@lingui/macro' -import Circle from 'legacy/assets/images/blue-loader.svg' -import { ButtonSecondary } from 'legacy/components/Button' -import useENS from 'legacy/hooks/useENS' import { ClaimStatus } from 'legacy/state/claim/actions' import { useClaimDispatchers, useClaimState } from 'legacy/state/claim/hooks' +import { ClaimCommonTypes } from 'legacy/state/claim/types' import { CustomLightSpinner, ThemedText } from 'legacy/theme' import { CheckAddress, InputField, InputFieldTitle, InputErrorText } from './styled' -import { ClaimCommonTypes } from './types' export type ClaimAddressProps = Pick & { toggleWalletModal: () => void diff --git a/apps/cowswap-frontend/src/pages/Claim/ClaimBanner.tsx b/apps/cowswap-frontend/src/pages/Claim/ClaimBanner.tsx index 5de79e8536..15aa79456e 100644 --- a/apps/cowswap-frontend/src/pages/Claim/ClaimBanner.tsx +++ b/apps/cowswap-frontend/src/pages/Claim/ClaimBanner.tsx @@ -1,12 +1,12 @@ +import CheckCircle from '@cowprotocol/assets/cow-swap/check.svg' +import { useNetworkName } from '@cowprotocol/common-hooks' + import { Trans } from '@lingui/macro' import SVG from 'react-inlinesvg' -import CheckCircle from 'legacy/assets/cow-swap/check.svg' -import useNetworkName from 'legacy/hooks/useNetworkName' import { ClaimStatus } from 'legacy/state/claim/actions' import { useClaimState } from 'legacy/state/claim/hooks' - -import { ClaimCommonTypes } from 'pages/Claim/types' +import { ClaimCommonTypes } from 'legacy/state/claim/types' import { ClaimBanner as ClaimBannerWrapper } from './styled' diff --git a/apps/cowswap-frontend/src/pages/Claim/ClaimNav.tsx b/apps/cowswap-frontend/src/pages/Claim/ClaimNav.tsx index 8079e2bdbc..356e317e2f 100644 --- a/apps/cowswap-frontend/src/pages/Claim/ClaimNav.tsx +++ b/apps/cowswap-frontend/src/pages/Claim/ClaimNav.tsx @@ -1,13 +1,13 @@ -import { ButtonSecondary } from 'legacy/components/Button' +import { shortenAddress } from '@cowprotocol/common-utils' +import { ButtonSecondary } from '@cowprotocol/ui' +import { Identicon } from '@cowprotocol/wallet' + import CopyHelper from 'legacy/components/Copy' import { ClaimStatus } from 'legacy/state/claim/actions' import { useClaimDispatchers, useClaimState } from 'legacy/state/claim/hooks' -import { shortenAddress } from 'legacy/utils' - -import { Identicon } from 'modules/wallet/api/container/Identicon' +import { ClaimCommonTypes } from 'legacy/state/claim/types' import { TopNav, ClaimAccount, ClaimAccountButtons } from './styled' -import { ClaimCommonTypes } from './types' type ClaimNavProps = Pick diff --git a/apps/cowswap-frontend/src/pages/Claim/ClaimSummary.tsx b/apps/cowswap-frontend/src/pages/Claim/ClaimSummary.tsx index b29f27c32b..e0590b6155 100644 --- a/apps/cowswap-frontend/src/pages/Claim/ClaimSummary.tsx +++ b/apps/cowswap-frontend/src/pages/Claim/ClaimSummary.tsx @@ -1,20 +1,19 @@ +import { V_COW } from '@cowprotocol/common-const' +import { TokenAmount } from '@cowprotocol/ui' +import { useWalletInfo } from '@cowprotocol/wallet' import { CurrencyAmount, Currency, Token } from '@uniswap/sdk-core' import { Trans } from '@lingui/macro' import JSBI from 'jsbi' import CowProtocolLogo from 'legacy/components/CowProtocolLogo' -import { V_COW } from 'legacy/constants/tokens' import { ClaimStatus } from 'legacy/state/claim/actions' import { useClaimState } from 'legacy/state/claim/hooks' +import { ClaimCommonTypes } from 'legacy/state/claim/types' import { useTokenBalance } from 'modules/tokens/hooks/useCurrencyBalance' -import { useWalletInfo } from 'modules/wallet' - -import { TokenAmount } from 'common/pure/TokenAmount' import { ClaimSummary as ClaimSummaryWrapper, ClaimSummaryTitle, ClaimTotal } from './styled' -import { ClaimCommonTypes } from './types' type ClaimSummaryProps = Pick & { unclaimedAmount: ClaimCommonTypes['tokenCurrencyAmount'] | undefined diff --git a/apps/cowswap-frontend/src/pages/Claim/ClaimingStatus.tsx b/apps/cowswap-frontend/src/pages/Claim/ClaimingStatus.tsx index 984f7dfcb3..35b1c9692a 100644 --- a/apps/cowswap-frontend/src/pages/Claim/ClaimingStatus.tsx +++ b/apps/cowswap-frontend/src/pages/Claim/ClaimingStatus.tsx @@ -1,31 +1,31 @@ import { useMemo } from 'react' +import CowProtocolIcon from '@cowprotocol/assets/cow-swap/cowprotocol.svg' +import discordImage from '@cowprotocol/assets/cow-swap/discord.svg' +import twitterImage from '@cowprotocol/assets/cow-swap/twitter.svg' +import { V_COW } from '@cowprotocol/common-const' +import { shortenAddress } from '@cowprotocol/common-utils' +import { TokenAmount, ButtonSecondary } from '@cowprotocol/ui' +import { ExternalLink } from '@cowprotocol/ui' +import { useWalletInfo } from '@cowprotocol/wallet' import { CurrencyAmount } from '@uniswap/sdk-core' import { Trans } from '@lingui/macro' import SVG from 'react-inlinesvg' import { Link } from 'react-router-dom' -import CowProtocolIcon from 'legacy/assets/cow-swap/cowprotocol.svg' -import discordImage from 'legacy/assets/cow-swap/discord.svg' -import twitterImage from 'legacy/assets/cow-swap/twitter.svg' -import { ButtonSecondary } from 'legacy/components/Button' import CopyHelper from 'legacy/components/Copy' import CowProtocolLogo from 'legacy/components/CowProtocolLogo' import { EnhancedTransactionLink } from 'legacy/components/EnhancedTransactionLink' import { ExplorerLink } from 'legacy/components/ExplorerLink' -import { V_COW } from 'legacy/constants/tokens' import { ClaimStatus } from 'legacy/state/claim/actions' import { useClaimDispatchers, useClaimState } from 'legacy/state/claim/hooks' +import { ClaimCommonTypes } from 'legacy/state/claim/types' import { useAllClaimingTransactions } from 'legacy/state/enhancedTransactions/hooks' -import { ExternalLink } from 'legacy/theme' -import { shortenAddress } from 'legacy/utils' -import { useWalletInfo } from 'modules/wallet' -import AddToMetamask from 'modules/wallet/web3-react/containers/AddToMetamask' +import { AddToMetamask } from 'modules/wallet/containers/AddToMetamask' import { Routes } from 'common/constants/routes' -import { TokenAmount } from 'common/pure/TokenAmount' import { ConfirmOrLoadingWrapper, ConfirmedIcon, @@ -35,8 +35,6 @@ import { SuccessBanner, } from 'pages/Claim/styled' -import { ClaimCommonTypes } from './types' - const COW_TWEET_TEMPLATE = 'I just joined the 🐮 CoWmunity @CoWSwap and claimed my first vCOW tokens! Join me at https://swap.cow.fi/' diff --git a/apps/cowswap-frontend/src/pages/Claim/ClaimsOnOtherChainsBanner.tsx b/apps/cowswap-frontend/src/pages/Claim/ClaimsOnOtherChainsBanner.tsx index a2dde0130d..db278cd3ae 100644 --- a/apps/cowswap-frontend/src/pages/Claim/ClaimsOnOtherChainsBanner.tsx +++ b/apps/cowswap-frontend/src/pages/Claim/ClaimsOnOtherChainsBanner.tsx @@ -1,6 +1,7 @@ import { useMemo } from 'react' import { SupportedChainId } from '@cowprotocol/cow-sdk' +import { useWalletInfo } from '@cowprotocol/wallet' import { AlertTriangle } from 'react-feather' import styled from 'styled-components/macro' @@ -9,8 +10,6 @@ import NotificationBanner from 'legacy/components/NotificationBanner' import { useClaimState } from 'legacy/state/claim/hooks' import { ClaimInfo } from 'legacy/state/claim/reducer' -import { useWalletInfo } from 'modules/wallet' - // const ChainSpan = styled.span`` const Wrapper = styled.div` display: flex; diff --git a/apps/cowswap-frontend/src/pages/Claim/ClaimsTable.tsx b/apps/cowswap-frontend/src/pages/Claim/ClaimsTable.tsx index 789dd7d340..3f0eba9c31 100644 --- a/apps/cowswap-frontend/src/pages/Claim/ClaimsTable.tsx +++ b/apps/cowswap-frontend/src/pages/Claim/ClaimsTable.tsx @@ -1,30 +1,25 @@ import { useEffect } from 'react' +import CowProtocolImage from '@cowprotocol/assets/cow-swap/cowprotocol.svg' +import Circle from '@cowprotocol/assets/images/blue-loader.svg' +import { TokenAmount } from '@cowprotocol/ui' +import { ExternalLink } from '@cowprotocol/ui' + import SVG from 'react-inlinesvg' import styled from 'styled-components/macro' -import CowProtocolImage from 'legacy/assets/cow-swap/cowprotocol.svg' -import Circle from 'legacy/assets/images/blue-loader.svg' import CowProtocolLogo from 'legacy/components/CowProtocolLogo' import { ClaimStatus } from 'legacy/state/claim/actions' -import { - ClaimType, - useClaimDispatchers, - useClaimState, - useClaimTimeInfo, - useClaimLinks, -} from 'legacy/state/claim/hooks' +import { useClaimDispatchers, useClaimState, useClaimTimeInfo, useClaimLinks } from 'legacy/state/claim/hooks' +import { ClaimType } from 'legacy/state/claim/hooks/types' import { getPaidClaims, getIndexes } from 'legacy/state/claim/hooks/utils' +import { ClaimCommonTypes, EnhancedUserClaimData } from 'legacy/state/claim/types' import { useAllClaimingTransactionIndices } from 'legacy/state/enhancedTransactions/hooks' import { CustomLightSpinner } from 'legacy/theme' -import { ExternalLink } from 'legacy/theme' -import { TokenAmount } from 'common/pure/TokenAmount' import { Countdown } from 'pages/Claim/Countdown' import { ClaimTable, ClaimBreakdown, TokenLogo, BannerExplainer } from 'pages/Claim/styled' -import { ClaimCommonTypes, EnhancedUserClaimData } from './types' - export type ClaimsTableProps = Pick // TODO: fix in other pr diff --git a/apps/cowswap-frontend/src/pages/Claim/FooterNavButtons.tsx b/apps/cowswap-frontend/src/pages/Claim/FooterNavButtons.tsx index 6cb6feb30a..2f679a05c7 100644 --- a/apps/cowswap-frontend/src/pages/Claim/FooterNavButtons.tsx +++ b/apps/cowswap-frontend/src/pages/Claim/FooterNavButtons.tsx @@ -1,10 +1,11 @@ import { ReactNode, useEffect, useRef } from 'react' +import { ButtonPrimary, ButtonSecondary } from '@cowprotocol/ui' +import { useWalletInfo } from '@cowprotocol/wallet' import { isAddress } from '@ethersproject/address' import { Trans } from '@lingui/macro' -import { ButtonPrimary, ButtonSecondary } from 'legacy/components/Button' import { ClaimStatus } from 'legacy/state/claim/actions' import { useClaimDispatchers, @@ -12,10 +13,7 @@ import { useHasClaimInvestmentFlowError, useHasZeroInvested, } from 'legacy/state/claim/hooks' - -import { useWalletInfo } from 'modules/wallet' - -import { ClaimCommonTypes } from 'pages/Claim/types' +import { ClaimCommonTypes } from 'legacy/state/claim/types' import { ClaimAddressProps } from './ClaimAddress' import { FooterNavButtons as FooterNavButtonsWrapper } from './styled' diff --git a/apps/cowswap-frontend/src/pages/Claim/InvestmentFlow/InvestOption.tsx b/apps/cowswap-frontend/src/pages/Claim/InvestmentFlow/InvestOption.tsx index 15ce851919..aba0b53bd0 100644 --- a/apps/cowswap-frontend/src/pages/Claim/InvestmentFlow/InvestOption.tsx +++ b/apps/cowswap-frontend/src/pages/Claim/InvestmentFlow/InvestOption.tsx @@ -1,40 +1,36 @@ import { useCallback, useEffect, useMemo, useState } from 'react' +import CheckCircle from '@cowprotocol/assets/cow-swap/check.svg' +import ImportantIcon from '@cowprotocol/assets/cow-swap/important.svg' +import { AVG_APPROVE_COST_GWEI, ONE_HUNDRED_PERCENT } from '@cowprotocol/common-const' +import { + calculateGasMargin, + getProviderErrorMessage, + tryParseCurrencyAmount, + formatTokenAmount, + formatSymbol, +} from '@cowprotocol/common-utils' +import { Loader, loadingOpacityMixin, ButtonSize, TokenAmount, ButtonConfirmed, Row } from '@cowprotocol/ui' +import { useWalletInfo } from '@cowprotocol/wallet' import { BigNumber } from '@ethersproject/bignumber' import { CurrencyAmount } from '@uniswap/sdk-core' import SVG from 'react-inlinesvg' import styled from 'styled-components/macro' -import CheckCircle from 'legacy/assets/cow-swap/check.svg' -import ImportantIcon from 'legacy/assets/cow-swap/important.svg' -import { ButtonConfirmed } from 'legacy/components/Button' import CowProtocolLogo from 'legacy/components/CowProtocolLogo' -import Loader from 'legacy/components/Loader' -import { loadingOpacityMixin } from 'legacy/components/Loader/styled' import { Input as NumericalInput } from 'legacy/components/NumericalInput' -import Row from 'legacy/components/Row' -import { ConfirmOperationType } from 'legacy/components/TransactionConfirmationModal' -import { AVG_APPROVE_COST_GWEI } from 'legacy/constants' -import { ONE_HUNDRED_PERCENT } from 'legacy/constants/misc' import { useApproveCallbackFromClaim } from 'legacy/hooks/useApproveCallback' +import { ApprovalState } from 'legacy/hooks/useApproveCallback/useApproveCallbackMod' import { useErrorModal } from 'legacy/hooks/useErrorMessageAndModal' import { useClaimDispatchers, useClaimState } from 'legacy/state/claim/hooks' import { calculateInvestmentAmounts, calculatePercentage } from 'legacy/state/claim/hooks/utils' +import { EnhancedUserClaimData } from 'legacy/state/claim/types' import { useGasPrices } from 'legacy/state/gas/hooks' -import { ButtonSize } from 'legacy/theme/enum' -import { calculateGasMargin } from 'legacy/utils/calculateGasMargin' -import { getProviderErrorMessage } from 'legacy/utils/misc' +import { ConfirmOperationType } from 'legacy/state/types' import useCurrencyBalance from 'modules/tokens/hooks/useCurrencyBalance' -import { useWalletInfo } from 'modules/wallet' -import { TokenAmount } from 'common/pure/TokenAmount' -import tryParseCurrencyAmount from 'lib/utils/tryParseCurrencyAmount' -import { formatTokenAmount } from 'utils/amountFormat' -import { formatSymbol } from 'utils/format' - -import { ApprovalState } from 'legacy/hooks/useApproveCallback/useApproveCallbackMod' import { IS_TESTING_ENV } from '../const' import { InvestAvailableBar, @@ -46,7 +42,6 @@ import { UserMessage, WarningWrapper, } from '../styled' -import { EnhancedUserClaimData } from '../types' import { InvestmentFlowProps } from '.' diff --git a/apps/cowswap-frontend/src/pages/Claim/InvestmentFlow/InvestSummaryRow.tsx b/apps/cowswap-frontend/src/pages/Claim/InvestmentFlow/InvestSummaryRow.tsx index 05f7a6dadb..1cc4743f68 100644 --- a/apps/cowswap-frontend/src/pages/Claim/InvestmentFlow/InvestSummaryRow.tsx +++ b/apps/cowswap-frontend/src/pages/Claim/InvestmentFlow/InvestSummaryRow.tsx @@ -1,14 +1,15 @@ +import ImportantIcon from '@cowprotocol/assets/cow-swap/important.svg' +import { ONE_HUNDRED_PERCENT } from '@cowprotocol/common-const' +import { TokenAmount } from '@cowprotocol/ui' + import SVG from 'react-inlinesvg' -import ImportantIcon from 'legacy/assets/cow-swap/important.svg' import CowProtocolLogo from 'legacy/components/CowProtocolLogo' -import { ONE_HUNDRED_PERCENT } from 'legacy/constants/misc' -import { ClaimType } from 'legacy/state/claim/hooks' +import { ClaimType } from 'legacy/state/claim/hooks/types' import { calculatePercentage } from 'legacy/state/claim/hooks/utils' +import { ClaimWithInvestmentData } from 'legacy/state/claim/types' -import { TokenAmount } from 'common/pure/TokenAmount' import { TokenLogo, InvestAvailableBar, UserMessage } from 'pages/Claim/styled' -import { ClaimWithInvestmentData } from 'pages/Claim/types' export type Props = { claim: ClaimWithInvestmentData } diff --git a/apps/cowswap-frontend/src/pages/Claim/InvestmentFlow/index.tsx b/apps/cowswap-frontend/src/pages/Claim/InvestmentFlow/index.tsx index ab5a2758f9..0b48baa463 100644 --- a/apps/cowswap-frontend/src/pages/Claim/InvestmentFlow/index.tsx +++ b/apps/cowswap-frontend/src/pages/Claim/InvestmentFlow/index.tsx @@ -1,18 +1,19 @@ import { useEffect, useMemo } from 'react' +import CowProtocolImage from '@cowprotocol/assets/cow-swap/cowprotocol.svg' +import ImportantIcon from '@cowprotocol/assets/cow-swap/important.svg' +import RoundArrow from '@cowprotocol/assets/cow-swap/round-arrow.svg' import { SupportedChainId } from '@cowprotocol/cow-sdk' +import { ExternalLink } from '@cowprotocol/ui' +import { useWalletInfo } from '@cowprotocol/wallet' import { CurrencyAmount } from '@uniswap/sdk-core' import SVG from 'react-inlinesvg' -import CowProtocolImage from 'legacy/assets/cow-swap/cowprotocol.svg' -import ImportantIcon from 'legacy/assets/cow-swap/important.svg' -import RoundArrow from 'legacy/assets/cow-swap/round-arrow.svg' import { BadgeVariant } from 'legacy/components/Badge' import { ExplorerLink } from 'legacy/components/ExplorerLink' import { FaqDrawer } from 'legacy/components/FaqDrawer' import { Stepper } from 'legacy/components/Stepper' -import { ConfirmOperationType } from 'legacy/components/TransactionConfirmationModal' import { ClaimStatus } from 'legacy/state/claim/actions' import { useClaimState, @@ -23,9 +24,8 @@ import { } from 'legacy/state/claim/hooks' import { calculateInvestmentAmounts } from 'legacy/state/claim/hooks/utils' import { InvestClaim } from 'legacy/state/claim/reducer' -import { ExternalLink } from 'legacy/theme' - -import { useWalletInfo } from 'modules/wallet' +import { ClaimCommonTypes, ClaimWithInvestmentData, EnhancedUserClaimData } from 'legacy/state/claim/types' +import { ConfirmOperationType } from 'legacy/state/types' import { ClaimSummaryView } from 'pages/Claim/ClaimSummary' import { InvestSummaryRow } from 'pages/Claim/InvestmentFlow/InvestSummaryRow' @@ -43,8 +43,6 @@ import { import InvestOption from './InvestOption' -import { ClaimCommonTypes, ClaimWithInvestmentData, EnhancedUserClaimData } from '../types' - const STEPS_DATA = [ { title: 'Start', diff --git a/apps/cowswap-frontend/src/pages/Claim/const.ts b/apps/cowswap-frontend/src/pages/Claim/const.ts index 071a062a96..d377de27ce 100644 --- a/apps/cowswap-frontend/src/pages/Claim/const.ts +++ b/apps/cowswap-frontend/src/pages/Claim/const.ts @@ -1,3 +1,3 @@ -import { isProd, isEns, isBarn } from 'legacy/utils/environments' +import { isProd, isEns, isBarn } from '@cowprotocol/common-utils' export const IS_TESTING_ENV = !isProd && !isEns && !isBarn diff --git a/apps/cowswap-frontend/src/pages/Claim/index.tsx b/apps/cowswap-frontend/src/pages/Claim/index.tsx index b2e71d4d4a..15d1b068fb 100644 --- a/apps/cowswap-frontend/src/pages/Claim/index.tsx +++ b/apps/cowswap-frontend/src/pages/Claim/index.tsx @@ -1,26 +1,22 @@ import { useCallback, useEffect, useMemo } from 'react' +import { usePrevious } from '@cowprotocol/common-hooks' +import { getProviderErrorMessage } from '@cowprotocol/common-utils' +import { useENS } from '@cowprotocol/ens' +import { Loader } from '@cowprotocol/ui' +import { useWalletInfo } from '@cowprotocol/wallet' + import Confetti from 'legacy/components/Confetti' -import Loader from 'legacy/components/Loader' -import { ConfirmOperationType } from 'legacy/components/TransactionConfirmationModal' -import useENS from 'legacy/hooks/useENS' import { useErrorModal } from 'legacy/hooks/useErrorMessageAndModal' -import usePrevious from 'legacy/hooks/usePrevious' import useTransactionConfirmationModal from 'legacy/hooks/useTransactionConfirmationModal' import { useToggleWalletModal } from 'legacy/state/application/hooks' import { ClaimStatus } from 'legacy/state/claim/actions' -import { - useUserEnhancedClaimData, - useUserUnclaimedAmount, - useClaimCallback, - ClaimInput, -} from 'legacy/state/claim/hooks' +import { useUserEnhancedClaimData, useUserUnclaimedAmount, useClaimCallback } from 'legacy/state/claim/hooks' import { useClaimDispatchers, useClaimState } from 'legacy/state/claim/hooks' +import { ClaimInput } from 'legacy/state/claim/hooks/types' import { getFreeClaims, hasPaidClaim, hasFreeClaim, prepareInvestClaims } from 'legacy/state/claim/hooks/utils' import ClaimsOnOtherChainsUpdater from 'legacy/state/claim/updater' -import { getProviderErrorMessage } from 'legacy/utils/misc' - -import { useWalletInfo } from 'modules/wallet' +import { ConfirmOperationType } from 'legacy/state/types' import { PageWrapper, InnerPageWrapper } from 'pages/Claim/styled' diff --git a/apps/cowswap-frontend/src/pages/Claim/styled.ts b/apps/cowswap-frontend/src/pages/Claim/styled.ts index 353417bf2b..78e2615587 100644 --- a/apps/cowswap-frontend/src/pages/Claim/styled.ts +++ b/apps/cowswap-frontend/src/pages/Claim/styled.ts @@ -1,17 +1,20 @@ +import LogoGNO from '@cowprotocol/assets/cow-swap/gno.png' +import LogoETH from '@cowprotocol/assets/cow-swap/network-mainnet-logo.svg' +import LogoUSDC from '@cowprotocol/assets/cow-swap/usdc.png' +import LogoXDAI from '@cowprotocol/assets/cow-swap/xdai.png' +import { ButtonPrimary, ButtonSecondary } from '@cowprotocol/ui' + import { transparentize, darken, lighten } from 'polished' import { CheckCircle, Frown } from 'react-feather' import styled from 'styled-components/macro' -import LogoGNO from 'legacy/assets/cow-swap/gno.png' -import LogoETH from 'legacy/assets/cow-swap/network-mainnet-logo.svg' -import LogoUSDC from 'legacy/assets/cow-swap/usdc.png' -import LogoXDAI from 'legacy/assets/cow-swap/xdai.png' import BadgeOriginal from 'legacy/components/Badge' -import { ButtonPrimary, ButtonSecondary } from 'legacy/components/Button' import { CopyIcon } from 'legacy/components/Copy' import { Icon } from 'legacy/components/CowProtocolLogo' import { Step } from 'legacy/components/Stepper' +import { UI } from 'common/constants/theme' + import ClaimsOnOtherChainsBanner from './ClaimsOnOtherChainsBanner' export const InnerPageWrapper = styled.div` @@ -19,11 +22,11 @@ export const InnerPageWrapper = styled.div` --border-radius-small: 16px; display: flex; flex-flow: column wrap; - color: ${({ theme }) => theme.text1}; + color: var(${UI.COLOR_TEXT1}); padding: 30px; border: none; box-shadow: ${({ theme }) => theme.boxShadow1}; - background: ${({ theme }) => theme.bg1}; + background: var(${UI.COLOR_CONTAINER_BG_01}); min-height: 450px; justify-content: center; align-items: center; @@ -161,7 +164,7 @@ export const ClaimSummary = styled.div` align-items: center; justify-content: flex-start; padding: 8px; - background: ${({ theme }) => theme.grey1}; + background: var(${UI.COLOR_GREY}); border: 0; border-radius: var(--border-radius); margin: 0 auto 24px; @@ -201,7 +204,7 @@ export const IntroDescription = styled.div<{ center?: boolean }>` } > p > i { - color: ${({ theme }) => theme.text1}; + color: var(${UI.COLOR_TEXT1}); font-weight: 600; font-style: normal; } @@ -431,7 +434,7 @@ export const ClaimTable = styled.div` text-align: left; font-weight: normal; font-size: 15px; - color: ${({ theme }) => theme.text1}; + color: var(${UI.COLOR_TEXT1}); position: relative; } @@ -442,7 +445,7 @@ export const ClaimTable = styled.div` td { display: flex; align-items: center; - color: ${({ theme }) => theme.text1}; + color: var(${UI.COLOR_TEXT1}); word-break: break-word; background: ${({ theme }) => theme.blueShade3}; } @@ -505,7 +508,7 @@ export const ClaimTable = styled.div` > span > b { font-weight: 500; - color: ${({ theme }) => theme.text1}; + color: var(${UI.COLOR_TEXT1}); } } @@ -548,7 +551,7 @@ export const UserMessage = styled.div<{ variant?: string }>` ? transparentize(0.9, theme.blue2) : transparentize(0.9, theme.attention)}; color: ${({ variant, theme }) => - variant === 'danger' ? theme.danger : variant === 'info' ? theme.blue2 : darken(0.1, theme.attention)}; + variant === 'danger' ? `var(${UI.COLOR_DANGER})` : variant === 'info' ? theme.blue2 : darken(0.1, theme.attention)}; margin: 0 auto; align-items: center; font-size: 15px; @@ -571,7 +574,11 @@ export const UserMessage = styled.div<{ variant?: string }>` > svg > path { fill: ${({ variant, theme }) => - variant === 'danger' ? theme.danger : variant === 'info' ? theme.blue2 : darken(0.1, theme.attention)}; + variant === 'danger' + ? `var(${UI.COLOR_DANGER})` + : variant === 'info' + ? theme.blue2 + : darken(0.1, theme.attention)}; } > span { @@ -652,7 +659,7 @@ export const ClaimTotal = styled.div` export const ConfirmOrLoadingWrapper = styled.div<{ activeBG: boolean }>` width: 100%; padding: 24px 24px 0; - color: ${({ theme }) => theme.text1}; + color: var(${UI.COLOR_TEXT1}); position: relative; display: flex; flex-direction: column; @@ -670,7 +677,7 @@ export const ConfirmOrLoadingWrapper = styled.div<{ activeBG: boolean }>` line-height: 1.2; text-align: center; margin: 0 0 12px; - color: ${({ theme }) => theme.text1}; + color: var(${UI.COLOR_TEXT1}); ${({ theme }) => theme.mediaWidth.upToSmall` font-size: 26px; @@ -751,8 +758,8 @@ export const ClaimBanner = styled.div<{ isClaimed: boolean }>` display: flex; justify-content: center; align-items: center; - background: ${({ theme, isClaimed }) => transparentize(0.9, !isClaimed ? theme.success : theme.blue2)}; - color: ${({ theme, isClaimed }) => (!isClaimed ? theme.success : theme.blue2)}; + background: ${({ theme, isClaimed }) => transparentize(0.9, !isClaimed ? `var(${UI.COLOR_SUCCESS})` : theme.blue2)}; + color: ${({ theme, isClaimed }) => (!isClaimed ? `var(${UI.COLOR_SUCCESS})` : theme.blue2)}; margin: 0 auto 16px; font-weight: 600; @@ -767,7 +774,7 @@ export const ClaimBanner = styled.div<{ isClaimed: boolean }>` height: 21px; > path { - fill: ${({ theme, isClaimed }) => (!isClaimed ? theme.success : theme.blue2)}; + fill: ${({ theme, isClaimed }) => (!isClaimed ? `var(${UI.COLOR_SUCCESS})` : theme.blue2)}; } ${({ theme }) => theme.mediaWidth.upToSmall` @@ -780,7 +787,7 @@ export const InputField = styled.div` padding: 18px 18px 18px 36px; border-radius: var(--border-radius); border: ${({ theme }) => theme.currencyInput?.border}; - color: ${({ theme }) => theme.text1}; + color: var(${UI.COLOR_TEXT1}); display: flex; flex-flow: row wrap; background: ${({ theme }) => theme.currencyInput?.background}; @@ -792,7 +799,7 @@ export const InputField = styled.div` border: 0; font-size: 24px; outline: 0; - color: ${({ theme }) => theme.text1}; + color: var(${UI.COLOR_TEXT1}); width: 100%; } @@ -839,7 +846,7 @@ export const InputField = styled.div` padding: 0; font-size: 22px; font-weight: 600; - color: ${({ theme }) => theme.text1}; + color: var(${UI.COLOR_TEXT1}); } > span { @@ -961,7 +968,7 @@ export const TopNav = styled.div` ${ButtonSecondary} { margin: 0; - color: ${({ theme }) => theme.text1}; + color: var(${UI.COLOR_TEXT1}); font-size: 15px; width: auto; } @@ -1198,7 +1205,7 @@ export const UnderlineButton = styled.button` } &:hover { - color: ${({ theme }) => theme.text1}; + color: var(${UI.COLOR_TEXT1}); } &:disabled { @@ -1258,7 +1265,7 @@ export const InvestInput = styled.span<{ disabled: boolean }>` bottom: 0; margin: auto; font-weight: normal; - color: ${({ theme }) => theme.text1}; + color: var(${UI.COLOR_TEXT1}); background: ${({ theme }) => theme.bg5}; border-radius: 12px; padding: 0 12px; @@ -1271,7 +1278,7 @@ export const InvestInput = styled.span<{ disabled: boolean }>` } > div > label > input { - color: ${({ theme }) => theme.text1}; + color: var(${UI.COLOR_TEXT1}); border: none; padding: 12px 70px 0 0; font-size: 26px; @@ -1353,7 +1360,7 @@ export const InvestAvailableBar = styled.div<{ percentage?: number }>` justify-content: flex-start; overflow: hidden; border-radius: 24px; - background: ${({ theme }) => theme.bg1}; + background: var(${UI.COLOR_CONTAINER_BG_01}); margin: 6px 0; padding: 0; @@ -1376,7 +1383,7 @@ export const InvestAvailableBar = styled.div<{ percentage?: number }>` content: ${({ percentage }) => (percentage ? `'${percentage}%'` : '0%')}; display: block; font-size: 12px; - color: ${({ theme }) => theme.text1}; + color: var(${UI.COLOR_TEXT1}); z-index: 1; height: 100%; width: ${({ percentage }) => (percentage ? `${percentage}%` : '0%')}; @@ -1425,7 +1432,7 @@ export const InvestSummary = styled.div` > span > b { font-weight: 600; - color: ${({ theme }) => theme.text1}; + color: var(${UI.COLOR_TEXT1}); } ` @@ -1519,7 +1526,7 @@ export const AccountClaimSummary = styled.div` border-radius: var(--iconSize); width: var(--iconSize); height: var(--iconSize); - background: ${({ theme }) => theme.bg1}; + background: var(${UI.COLOR_CONTAINER_BG_01}); ${({ theme }) => theme.mediaWidth.upToSmall` transform: rotate(90deg); @@ -1532,7 +1539,7 @@ export const AccountClaimSummary = styled.div` } > svg > path { - fill: ${({ theme }) => theme.text1}; + fill: var(${UI.COLOR_TEXT1}); } } ` @@ -1589,7 +1596,7 @@ export const CowSpinner = styled.div` height: 94%; width: 94%; padding: 0; - stroke: ${({ theme }) => theme.text1}; + stroke: var(${UI.COLOR_TEXT1}); border-radius: var(--circle-size); z-index: 1; } diff --git a/apps/cowswap-frontend/src/pages/CookiePolicy/index.tsx b/apps/cowswap-frontend/src/pages/CookiePolicy/index.tsx index 5df2fc89c1..d8f788d682 100644 --- a/apps/cowswap-frontend/src/pages/CookiePolicy/index.tsx +++ b/apps/cowswap-frontend/src/pages/CookiePolicy/index.tsx @@ -5,6 +5,8 @@ import { MarkdownPage } from 'legacy/components/Markdown' import { PageTitle } from 'modules/application/containers/PageTitle' import { GdocsListStyle } from 'modules/application/pure/Page' +import { UI } from 'common/constants/theme' + import contentFile from './CookiePolicy.md' const Wrapper = styled(MarkdownPage)` @@ -20,14 +22,14 @@ const Wrapper = styled(MarkdownPage)` width: 100%; min-width: 800px; border-spacing: 1px; - color: ${({ theme }) => theme.text1}; + color: var(${UI.COLOR_TEXT1}); > thead { background: ${({ theme }) => theme.bg3}; } > tbody > tr { - background: ${({ theme }) => theme.grey1}; + background: var(${UI.COLOR_GREY}); } > tbody > tr > td > span[role='img'] { diff --git a/apps/cowswap-frontend/src/pages/Faq/AffiliateFaq.tsx b/apps/cowswap-frontend/src/pages/Faq/AffiliateFaq.tsx index 0c16e79461..50e68d9a92 100644 --- a/apps/cowswap-frontend/src/pages/Faq/AffiliateFaq.tsx +++ b/apps/cowswap-frontend/src/pages/Faq/AffiliateFaq.tsx @@ -1,9 +1,8 @@ +import { BARN_URL, PRODUCTION_URL } from '@cowprotocol/common-const' + import { Link } from 'react-router-dom' -import { PageName } from 'legacy/components/AmplitudeAnalytics/constants' -import { Trace } from 'legacy/components/AmplitudeAnalytics/Trace' import { LinkScrollable } from 'legacy/components/Link' -import { BARN_URL, PRODUCTION_URL } from 'legacy/constants' import { PageTitle } from 'modules/application/containers/PageTitle' import { Page, Content } from 'modules/application/pure/Page' @@ -17,8 +16,6 @@ import ToC from './ToC' import { Footer } from '.' -// AmplitudeAnalytics - const PROD = `https://${PRODUCTION_URL}` const BARN = `https://${BARN_URL}` @@ -26,7 +23,7 @@ export default function AffiliateFaq() { const { toc, faqRef } = useToC() return ( - + <> @@ -203,6 +200,6 @@ export default function AffiliateFaq() { - + ) } diff --git a/apps/cowswap-frontend/src/pages/Faq/EthFlowFaq.tsx b/apps/cowswap-frontend/src/pages/Faq/EthFlowFaq.tsx index 8def34fb02..b839996389 100644 --- a/apps/cowswap-frontend/src/pages/Faq/EthFlowFaq.tsx +++ b/apps/cowswap-frontend/src/pages/Faq/EthFlowFaq.tsx @@ -1,6 +1,3 @@ -import { PageName } from 'legacy/components/AmplitudeAnalytics/constants' -import { Trace } from 'legacy/components/AmplitudeAnalytics/Trace' - import { PageTitle } from 'modules/application/containers/PageTitle' import { Page, Content } from 'modules/application/pure/Page' @@ -11,13 +8,11 @@ import ToC from './ToC' import { Footer } from '.' -// AmplitudeAnalytics - export default function EthFlowFAQ() { const { toc, faqRef } = useToC() return ( - + <> @@ -347,6 +342,6 @@ export default function EthFlowFAQ() { - + ) } diff --git a/apps/cowswap-frontend/src/pages/Faq/LimitOrdersFaq.tsx b/apps/cowswap-frontend/src/pages/Faq/LimitOrdersFaq.tsx index e1295bec70..6a76ce33c0 100644 --- a/apps/cowswap-frontend/src/pages/Faq/LimitOrdersFaq.tsx +++ b/apps/cowswap-frontend/src/pages/Faq/LimitOrdersFaq.tsx @@ -1,6 +1,3 @@ -import { PageName } from 'legacy/components/AmplitudeAnalytics/constants' -import { Trace } from 'legacy/components/AmplitudeAnalytics/Trace' - import { PageTitle } from 'modules/application/containers/PageTitle' import { Content, Page } from 'modules/application/pure/Page' @@ -15,7 +12,7 @@ export default function LimitOrderFAQ() { const { toc, faqRef } = useToC() return ( - + <> @@ -228,6 +225,6 @@ export default function LimitOrderFAQ() { - + ) } diff --git a/apps/cowswap-frontend/src/pages/Faq/Menu.tsx b/apps/cowswap-frontend/src/pages/Faq/Menu.tsx index c1bf435cc1..fdb72cff07 100644 --- a/apps/cowswap-frontend/src/pages/Faq/Menu.tsx +++ b/apps/cowswap-frontend/src/pages/Faq/Menu.tsx @@ -1,7 +1,8 @@ +import { FAQ_MENU_LINKS } from '@cowprotocol/common-const' + import { NavLink } from 'react-router-dom' import { SideMenu } from 'legacy/components/SideMenu' -import { FAQ_MENU_LINKS } from 'legacy/constants' export function FaqMenu() { return ( diff --git a/apps/cowswap-frontend/src/pages/Faq/ProtocolFaq.tsx b/apps/cowswap-frontend/src/pages/Faq/ProtocolFaq.tsx index cf17adf769..182a9731e3 100644 --- a/apps/cowswap-frontend/src/pages/Faq/ProtocolFaq.tsx +++ b/apps/cowswap-frontend/src/pages/Faq/ProtocolFaq.tsx @@ -1,5 +1,3 @@ -import { PageName } from 'legacy/components/AmplitudeAnalytics/constants' -import { Trace } from 'legacy/components/AmplitudeAnalytics/Trace' import { LinkScrollable } from 'legacy/components/Link' import { PageTitle } from 'modules/application/containers/PageTitle' @@ -12,13 +10,11 @@ import ToC from './ToC' import { Footer } from '.' -// AmplitudeAnalytics - export default function ProtocolFaq() { const { toc, faqRef } = useToC() return ( - + <> @@ -271,6 +267,6 @@ export default function ProtocolFaq() { - + ) } diff --git a/apps/cowswap-frontend/src/pages/Faq/TokenFaq.tsx b/apps/cowswap-frontend/src/pages/Faq/TokenFaq.tsx index 37158f0814..9119e8a239 100644 --- a/apps/cowswap-frontend/src/pages/Faq/TokenFaq.tsx +++ b/apps/cowswap-frontend/src/pages/Faq/TokenFaq.tsx @@ -1,8 +1,5 @@ import { Link } from 'react-router-dom' -import { PageName } from 'legacy/components/AmplitudeAnalytics/constants' -import { Trace } from 'legacy/components/AmplitudeAnalytics/Trace' - import { PageTitle } from 'modules/application/containers/PageTitle' import { Page, Content } from 'modules/application/pure/Page' @@ -19,7 +16,7 @@ export default function TokenFaq() { const { toc, faqRef } = useToC() return ( - + <> @@ -134,6 +131,6 @@ export default function TokenFaq() { - + ) } diff --git a/apps/cowswap-frontend/src/pages/Faq/TradingFaq.tsx b/apps/cowswap-frontend/src/pages/Faq/TradingFaq.tsx index f99625aa34..1a5b9c0ffa 100644 --- a/apps/cowswap-frontend/src/pages/Faq/TradingFaq.tsx +++ b/apps/cowswap-frontend/src/pages/Faq/TradingFaq.tsx @@ -1,5 +1,3 @@ -import { PageName } from 'legacy/components/AmplitudeAnalytics/constants' -import { Trace } from 'legacy/components/AmplitudeAnalytics/Trace' import { LinkScrollable } from 'legacy/components/Link' import { PageTitle } from 'modules/application/containers/PageTitle' @@ -12,13 +10,11 @@ import ToC from './ToC' import { Footer } from '.' -// AmplitudeAnalytics - export default function TokenFaq() { const { toc, faqRef } = useToC() return ( - + <> @@ -238,6 +234,6 @@ export default function TokenFaq() { - + ) } diff --git a/apps/cowswap-frontend/src/pages/Faq/index.tsx b/apps/cowswap-frontend/src/pages/Faq/index.tsx index 28636aeda1..378ba11468 100644 --- a/apps/cowswap-frontend/src/pages/Faq/index.tsx +++ b/apps/cowswap-frontend/src/pages/Faq/index.tsx @@ -1,7 +1,3 @@ -import { Link } from 'react-router-dom' - -import { PageName } from 'legacy/components/AmplitudeAnalytics/constants' -import { Trace } from 'legacy/components/AmplitudeAnalytics/Trace' import { GPAUDIT_LINK, COWWIKI_LINK, @@ -10,7 +6,10 @@ import { DISCORD_LINK, MEV_TOTAL, FLASHBOTS_LINK, -} from 'legacy/constants' +} from '@cowprotocol/common-const' + +import { Link } from 'react-router-dom' + import { StyledInternalLink } from 'legacy/theme' import { PageTitle } from 'modules/application/containers/PageTitle' @@ -58,7 +57,7 @@ export function Footer() { export default function Faq() { const { toc, faqRef } = useToC() return ( - + <> @@ -201,6 +200,6 @@ export default function Faq() { - + ) } diff --git a/apps/cowswap-frontend/src/pages/Faq/styled.tsx b/apps/cowswap-frontend/src/pages/Faq/styled.tsx index dc510880c2..33c972294e 100644 --- a/apps/cowswap-frontend/src/pages/Faq/styled.tsx +++ b/apps/cowswap-frontend/src/pages/Faq/styled.tsx @@ -1,11 +1,15 @@ +import { ButtonPrimary } from '@cowprotocol/ui' +import { ExternalLink as ExternalLinkTheme } from '@cowprotocol/ui' + import { transparentize } from 'polished' import styled from 'styled-components/macro' -import { ButtonPrimary } from 'legacy/components/Button' -import { ExternalLink as ExternalLinkTheme, StyledInternalLink } from 'legacy/theme' +import { StyledInternalLink } from 'legacy/theme' import { Content } from 'modules/application/pure/Page' +import { UI } from 'common/constants/theme' + export const ExternalLinkFaq = styled(ExternalLinkTheme)` text-decoration: underline; font-weight: normal; @@ -34,14 +38,14 @@ export const Wrapper = styled.div` > table { width: 100%; border-spacing: 1px; - color: ${({ theme }) => theme.text1}; + color: var(${UI.COLOR_TEXT1}); > thead { background: ${({ theme }) => theme.bg3}; } > tbody > tr { - background: ${({ theme }) => theme.grey1}; + background: var(${UI.COLOR_GREY}); } > tbody > tr > td > span[role='img'] { @@ -119,7 +123,7 @@ export const Menu = styled.div` font-weight: bold; line-height: 1; margin: 0 24px 0 0; - color: ${({ theme }) => theme.text1}; + color: var(${UI.COLOR_TEXT1}); height: max-content; position: sticky; top: 0; diff --git a/apps/cowswap-frontend/src/pages/KitchenSink/index.tsx b/apps/cowswap-frontend/src/pages/KitchenSink/index.tsx deleted file mode 100644 index c6a78abe46..0000000000 --- a/apps/cowswap-frontend/src/pages/KitchenSink/index.tsx +++ /dev/null @@ -1,40 +0,0 @@ -import { PinkTitle } from '@cowswap/ui' -import { CowSwapWidgetSettings } from '@cowswap/widget-lib' -import { CowSwapWidget, CowSwapWidgetParams } from '@cowswap/widget-react' - -import styled from 'styled-components/macro' - -import { Page, Title, Content } from 'modules/application/pure/Page' - -const Wrapper = styled(Page)`` - -export default function KitchenSink() { - const cowSwapWidgetParams: CowSwapWidgetParams = { - width: 600, - height: 700, - metaData: { - appKey: 'KitchenSink', - url: '/', - }, - } - - const cowSwapWidgetSettings: CowSwapWidgetSettings = { - urlParams: { - chainId: 1, - tradeType: 'swap', - env: 'local', - }, - appParams: {}, - } - - return ( - - Kitchen Sink - - pink title - - - - - ) -} diff --git a/apps/cowswap-frontend/src/pages/LimitOrders/index.tsx b/apps/cowswap-frontend/src/pages/LimitOrders/index.tsx index e0d3a54523..45fecd5aa4 100644 --- a/apps/cowswap-frontend/src/pages/LimitOrders/index.tsx +++ b/apps/cowswap-frontend/src/pages/LimitOrders/index.tsx @@ -2,6 +2,7 @@ import { useAtomValue } from 'jotai' import { useMemo } from 'react' import { OrderClass } from '@cowprotocol/cow-sdk' +import { useWalletInfo } from '@cowprotocol/wallet' import { useOrders } from 'legacy/state/orders/hooks' @@ -19,7 +20,6 @@ import { import { OrdersTableWidget } from 'modules/ordersTable' import { TabOrderTypes } from 'modules/ordersTable/pure/OrdersTableContainer' import * as styledEl from 'modules/trade/pure/TradePageLayout' -import { useWalletInfo } from 'modules/wallet' import { getIsNotComposableCowOrder } from 'utils/orderUtils/getIsNotComposableCowOrder' diff --git a/apps/cowswap-frontend/src/pages/Swap/index.tsx b/apps/cowswap-frontend/src/pages/Swap/index.tsx index f1a2a56abd..02bcef39c6 100644 --- a/apps/cowswap-frontend/src/pages/Swap/index.tsx +++ b/apps/cowswap-frontend/src/pages/Swap/index.tsx @@ -1,15 +1,15 @@ import React from 'react' -import { Navigate, useLocation, useParams } from 'react-router-dom' +import { WRAPPED_NATIVE_CURRENCY as WETH } from '@cowprotocol/common-const' +import { useWalletInfo } from '@cowprotocol/wallet' -import { WRAPPED_NATIVE_CURRENCY as WETH } from 'legacy/constants/tokens' +import { Navigate, useLocation, useParams } from 'react-router-dom' import { AppDataUpdater } from 'modules/appData' import { SwapWidget, SwapDerivedStateUpdater, SwapAmountsFromUrlUpdater } from 'modules/swap' import { useSwapSlippage } from 'modules/swap/hooks/useSwapSlippage' import { getDefaultTradeRawState } from 'modules/trade/types/TradeRawState' import { parameterizeTradeRoute } from 'modules/trade/utils/parameterizeTradeRoute' -import { useWalletInfo } from 'modules/wallet' import { Routes } from 'common/constants/routes' diff --git a/apps/cowswap-frontend/src/pages/error/AnySwapAffectedUsers/index.tsx b/apps/cowswap-frontend/src/pages/error/AnySwapAffectedUsers/index.tsx index 8c490424fb..d6c3ebc51d 100644 --- a/apps/cowswap-frontend/src/pages/error/AnySwapAffectedUsers/index.tsx +++ b/apps/cowswap-frontend/src/pages/error/AnySwapAffectedUsers/index.tsx @@ -1,8 +1,8 @@ -import styled from 'styled-components/macro' +import cow404IMG from '@cowprotocol/assets/cow-swap/cow-404.png' +import { ButtonPrimary } from '@cowprotocol/ui' +import { ExternalLink as ExternalLinkTheme } from '@cowprotocol/ui' -import cow404IMG from 'legacy/assets/cow-swap/cow-404.png' -import { ButtonPrimary } from 'legacy/components/Button' -import { ExternalLink as ExternalLinkTheme } from 'legacy/theme' +import styled from 'styled-components/macro' import { Page, Title, Content, GdocsListStyle } from 'modules/application/pure/Page' diff --git a/apps/cowswap-frontend/src/pages/error/AnySwapAffectedUsers/useIsAnySwapAffectedUser.ts b/apps/cowswap-frontend/src/pages/error/AnySwapAffectedUsers/useIsAnySwapAffectedUser.ts index 78e4192481..62a2618fc0 100644 --- a/apps/cowswap-frontend/src/pages/error/AnySwapAffectedUsers/useIsAnySwapAffectedUser.ts +++ b/apps/cowswap-frontend/src/pages/error/AnySwapAffectedUsers/useIsAnySwapAffectedUser.ts @@ -1,15 +1,13 @@ import { useMemo } from 'react' +import { Erc20Abi, Erc20Interface } from '@cowprotocol/abis' +import { ZERO_ADDRESS } from '@cowprotocol/common-const' +import { WRAPPED_NATIVE_CURRENCY as WETH } from '@cowprotocol/common-const' import { SupportedChainId as ChainId } from '@cowprotocol/cow-sdk' -import { Erc20Abi, Erc20Interface } from '@cowswap/abis' +import { useWalletInfo } from '@cowprotocol/wallet' import { Interface } from '@ethersproject/abi' import { BigNumber } from '@ethersproject/bignumber' -import { ZERO_ADDRESS } from 'legacy/constants/misc' -import { WRAPPED_NATIVE_CURRENCY as WETH } from 'legacy/constants/tokens' - -import { useWalletInfo } from 'modules/wallet' - import { useMultipleContractSingleData } from 'lib/hooks/multicall' const WETH_ADDRESS = WETH[ChainId.MAINNET].address diff --git a/apps/cowswap-frontend/src/pages/error/NotFound/index.tsx b/apps/cowswap-frontend/src/pages/error/NotFound/index.tsx index 401bd97461..b876efb624 100644 --- a/apps/cowswap-frontend/src/pages/error/NotFound/index.tsx +++ b/apps/cowswap-frontend/src/pages/error/NotFound/index.tsx @@ -1,9 +1,9 @@ +import cow404IMG from '@cowprotocol/assets/cow-swap/cow-404.png' +import { ButtonPrimary } from '@cowprotocol/ui' + import { Link } from 'react-router-dom' import styled from 'styled-components/macro' -import cow404IMG from 'legacy/assets/cow-swap/cow-404.png' -import { ButtonPrimary } from 'legacy/components/Button' - import { Page, Title, Content, GdocsListStyle } from 'modules/application/pure/Page' const Wrapper = styled(Page)` diff --git a/apps/cowswap-frontend/src/pages/games/CowRunner/index.tsx b/apps/cowswap-frontend/src/pages/games/CowRunner/index.tsx index 2e5eb2c843..ee7e5c0465 100644 --- a/apps/cowswap-frontend/src/pages/games/CowRunner/index.tsx +++ b/apps/cowswap-frontend/src/pages/games/CowRunner/index.tsx @@ -1,11 +1,10 @@ import { useEffect } from 'react' +import { gameAnalytics } from '@cowprotocol/analytics' import { CowGame } from '@cowprotocol/cow-runner-game' import styled from 'styled-components/macro' -import { gameAnalytics } from 'legacy/components/analytics' - import { PageTitle } from 'modules/application/containers/PageTitle' import { Page, Content } from 'modules/application/pure/Page' diff --git a/apps/cowswap-frontend/src/pages/games/MevSlicer/index.tsx b/apps/cowswap-frontend/src/pages/games/MevSlicer/index.tsx index e181fe114e..0cd932be19 100644 --- a/apps/cowswap-frontend/src/pages/games/MevSlicer/index.tsx +++ b/apps/cowswap-frontend/src/pages/games/MevSlicer/index.tsx @@ -1,8 +1,8 @@ -import styled from 'styled-components/macro' +import { gameAnalytics } from '@cowprotocol/analytics' +import ninjaCowImg from '@cowprotocol/assets/cow-swap/ninja-cow.png' +import { ButtonPrimary } from '@cowprotocol/ui' -import ninjaCowImg from 'legacy/assets/cow-swap/ninja-cow.png' -import { gameAnalytics } from 'legacy/components/analytics' -import { ButtonPrimary } from 'legacy/components/Button' +import styled from 'styled-components/macro' import { PageTitle } from 'modules/application/containers/PageTitle' import { Page, Content } from 'modules/application/pure/Page' diff --git a/apps/cowswap-frontend/src/react-app-env.d.ts b/apps/cowswap-frontend/src/react-app-env.d.ts index 8ffbf1ae56..b44e322480 100644 --- a/apps/cowswap-frontend/src/react-app-env.d.ts +++ b/apps/cowswap-frontend/src/react-app-env.d.ts @@ -6,8 +6,6 @@ declare module '@metamask/jazzicon' { export default function (diameter: number, seed: number): HTMLElement } -declare module 'fortmatic' - interface Window { console: Console & { force: Console } // walletLinkExtension is injected by the Coinbase Wallet extension diff --git a/apps/cowswap-frontend/src/test-utils.tsx b/apps/cowswap-frontend/src/test-utils.tsx index 38595a99bd..5ae90fdf46 100644 --- a/apps/cowswap-frontend/src/test-utils.tsx +++ b/apps/cowswap-frontend/src/test-utils.tsx @@ -15,7 +15,7 @@ import { MemoryRouter } from 'react-router-dom' import { ThemeProvider as StyledComponentsThemeProvider } from 'styled-components/macro' import Web3Provider from 'legacy/components/Web3Provider' -import store from 'legacy/state' +import { cowSwapStore } from 'legacy/state' import { useIsDarkMode } from 'legacy/state/user/hooks' import { theme } from 'legacy/theme' @@ -37,7 +37,7 @@ const WithProviders = ({ children }: { children?: ReactNode }) => { return ( - + {children} @@ -71,7 +71,7 @@ export function WithMockedWeb3({ children, location }: { children?: ReactNode; l return ( - + {children} diff --git a/apps/cowswap-frontend/src/types/index.ts b/apps/cowswap-frontend/src/types/index.ts index d5c2713020..dc466c7a62 100644 --- a/apps/cowswap-frontend/src/types/index.ts +++ b/apps/cowswap-frontend/src/types/index.ts @@ -23,7 +23,7 @@ declare global { } export type FractionLike = Fraction | Price | CurrencyAmount -// TODO: it's legacy from the old SDK version +// TODO: it'legacy from the old SDK version export interface PriceInformation { token: string amount: string | null diff --git a/apps/cowswap-frontend/src/utils/orderUtils/calculateAmountForRate.ts b/apps/cowswap-frontend/src/utils/orderUtils/calculateAmountForRate.ts index 3a7b9d94f2..f15c72799f 100644 --- a/apps/cowswap-frontend/src/utils/orderUtils/calculateAmountForRate.ts +++ b/apps/cowswap-frontend/src/utils/orderUtils/calculateAmountForRate.ts @@ -1,8 +1,7 @@ +import { FractionUtils } from '@cowprotocol/common-utils' import { Currency, Fraction } from '@uniswap/sdk-core' -import JSBI from 'jsbi' - -import { Field } from 'legacy/state/swap/actions' +import { Field } from 'legacy/state/types' export type RateCalculationParams = { amount: Fraction | null @@ -12,21 +11,6 @@ export type RateCalculationParams = { outputCurrency: Currency | null } -/** - * Adjust a fraction defined in units for both token to consider the decimals. - * For example, a fraction like 1.1/1 representing the price of USDC, DAI in units, will be turned into - * 1.1/1000000000000 in atoms - */ -export function adjustDecimalsAtoms(value: Fraction, decimalsA: number, decimalsB: number): Fraction { - if (decimalsA === decimalsB) { - return value - } - - const decimalsShift = JSBI.BigInt(JSBI.exponentiate(JSBI.BigInt(10), JSBI.BigInt(Math.abs(decimalsA - decimalsB)))) - - return decimalsA < decimalsB ? value.multiply(decimalsShift) : value.divide(decimalsShift) -} - export function calculateAmountForRate({ activeRate, amount, @@ -41,7 +25,7 @@ export function calculateAmountForRate({ const { decimals: inputDecimals } = inputCurrency const { decimals: outputDecimals } = outputCurrency - const parsedValue = adjustDecimalsAtoms( + const parsedValue = FractionUtils.adjustDecimalsAtoms( amount, field === Field.INPUT ? inputDecimals : outputDecimals, field === Field.INPUT ? outputDecimals : inputDecimals diff --git a/apps/cowswap-frontend/src/utils/orderUtils/calculateExecutionPrice.test.ts b/apps/cowswap-frontend/src/utils/orderUtils/calculateExecutionPrice.test.ts index 01474a1c8a..a65c715101 100644 --- a/apps/cowswap-frontend/src/utils/orderUtils/calculateExecutionPrice.test.ts +++ b/apps/cowswap-frontend/src/utils/orderUtils/calculateExecutionPrice.test.ts @@ -1,12 +1,10 @@ +import { USDC_GOERLI, WETH_GOERLI } from '@cowprotocol/common-const' +import { rawToTokenAmount } from '@cowprotocol/common-utils' import { OrderKind } from '@cowprotocol/contracts' import { CurrencyAmount, Fraction } from '@uniswap/sdk-core' -import { USDC_GOERLI, WETH_GOERLI } from 'legacy/utils/goerli/constants' - import { calculateExecutionPrice, convertAmountToCurrency } from './calculateExecutionPrice' -import { rawToTokenAmount } from '../rawToTokenAmount' - describe('calculateExecutionPrice', () => { describe('When market price is less than execution price', () => { const marketPrice = new Fraction(3, 7000) // 0 diff --git a/apps/cowswap-frontend/src/utils/orderUtils/calculateExecutionPrice.ts b/apps/cowswap-frontend/src/utils/orderUtils/calculateExecutionPrice.ts index 04762b4e94..77fa94c15c 100644 --- a/apps/cowswap-frontend/src/utils/orderUtils/calculateExecutionPrice.ts +++ b/apps/cowswap-frontend/src/utils/orderUtils/calculateExecutionPrice.ts @@ -1,10 +1,9 @@ +import { rawToTokenAmount } from '@cowprotocol/common-utils' import { OrderKind } from '@cowprotocol/contracts' import { Currency, CurrencyAmount, Fraction, Price } from '@uniswap/sdk-core' import JSBI from 'jsbi' -import { rawToTokenAmount } from 'utils/rawToTokenAmount' - export interface ExecutionPriceParams { inputCurrencyAmount: CurrencyAmount | null outputCurrencyAmount: CurrencyAmount | null diff --git a/apps/cowswap-frontend/src/utils/orderUtils/calculatePercentageInRelationToReference.ts b/apps/cowswap-frontend/src/utils/orderUtils/calculatePercentageInRelationToReference.ts index 6d72f305cd..0817b73a82 100644 --- a/apps/cowswap-frontend/src/utils/orderUtils/calculatePercentageInRelationToReference.ts +++ b/apps/cowswap-frontend/src/utils/orderUtils/calculatePercentageInRelationToReference.ts @@ -1,9 +1,8 @@ +import { ZERO_FRACTION } from '@cowprotocol/common-const' import { Percent } from '@uniswap/sdk-core' import { FractionLike, Nullish } from 'types' -import { ZERO_FRACTION } from 'legacy/constants' - export type CalculateAmountPercentDifferenceProps = { reference: Nullish value: Nullish diff --git a/apps/cowswap-frontend/src/utils/orderUtils/calculatePriceDifference.test.ts b/apps/cowswap-frontend/src/utils/orderUtils/calculatePriceDifference.test.ts index 52e1a9e985..271ba0b29f 100644 --- a/apps/cowswap-frontend/src/utils/orderUtils/calculatePriceDifference.test.ts +++ b/apps/cowswap-frontend/src/utils/orderUtils/calculatePriceDifference.test.ts @@ -1,13 +1,9 @@ +import { ZERO_FRACTION } from '@cowprotocol/common-const' +import { DAI_GOERLI, USDC_GOERLI } from '@cowprotocol/common-const' +import { buildPriceFromCurrencyAmounts, tryParseCurrencyAmount } from '@cowprotocol/common-utils' +import { FractionUtils } from '@cowprotocol/common-utils' import { Currency, Price } from '@uniswap/sdk-core' -import { ZERO_FRACTION } from 'legacy/constants' -import { DAI_GOERLI, USDC_GOERLI } from 'legacy/utils/goerli/constants' - -import { buildPriceFromCurrencyAmounts } from 'modules/utils/orderUtils/buildPriceFromCurrencyAmounts' - -import tryParseCurrencyAmount from 'lib/utils/tryParseCurrencyAmount' -import { FractionUtils } from 'utils/fractionUtils' - import { calculatePriceDifference, CalculatePriceDifferenceParams } from './calculatePriceDifference' function buildPrice(daiAmount: string, usdcAmount: string): Price { diff --git a/apps/cowswap-frontend/src/utils/orderUtils/calculatePriceDifference.ts b/apps/cowswap-frontend/src/utils/orderUtils/calculatePriceDifference.ts index d40019f8cc..0964d6ebec 100644 --- a/apps/cowswap-frontend/src/utils/orderUtils/calculatePriceDifference.ts +++ b/apps/cowswap-frontend/src/utils/orderUtils/calculatePriceDifference.ts @@ -1,14 +1,10 @@ +import { ZERO_FRACTION } from '@cowprotocol/common-const' +import { FractionUtils } from '@cowprotocol/common-utils' import { Currency, CurrencyAmount, Fraction, Percent, Price } from '@uniswap/sdk-core' +import invariant from 'tiny-invariant' import { Nullish } from 'types' -import { ZERO_FRACTION } from 'legacy/constants' - -import { assertSameMarket } from 'common/utils/markets' -import { FractionUtils } from 'utils/fractionUtils' - -import { adjustDecimalsAtoms } from './calculateAmountForRate' - const ONE = new Fraction(1) export type CalculatePriceDifferenceParams = { @@ -81,7 +77,7 @@ function calculatePriceDifferenceAux({ // Convert difference in token amount const differenceInUnits = FractionUtils.fromPrice(targetPrice).subtract(FractionUtils.fromPrice(referencePrice)) - const difference = adjustDecimalsAtoms(differenceInUnits, 0, referencePrice.quoteCurrency.decimals) + const difference = FractionUtils.adjustDecimalsAtoms(differenceInUnits, 0, referencePrice.quoteCurrency.decimals) const differenceInQuoteToken = CurrencyAmount.fromFractionalAmount( referencePrice.quoteCurrency, difference.numerator, @@ -98,3 +94,11 @@ function calculatePriceDifferenceAux({ return { percentage, amount: differenceInQuoteToken } } + +function assertSameMarket(price1: Price, price2: Price) { + // Assert I'm comparing apples with apples (prices should refer to market) + invariant( + price1.baseCurrency.equals(price2.baseCurrency) && price1.quoteCurrency.equals(price2.quoteCurrency), + 'Prices are not from the same market' + ) +} diff --git a/apps/cowswap-frontend/src/utils/orderUtils/getOrderFilledAmount.ts b/apps/cowswap-frontend/src/utils/orderUtils/getOrderFilledAmount.ts index 81aeba2aa7..8d1a92bb20 100644 --- a/apps/cowswap-frontend/src/utils/orderUtils/getOrderFilledAmount.ts +++ b/apps/cowswap-frontend/src/utils/orderUtils/getOrderFilledAmount.ts @@ -1,6 +1,7 @@ +import { ZERO_BIG_NUMBER } from '@cowprotocol/common-const' + import BigNumber from 'bignumber.js' -import { ZERO_BIG_NUMBER } from 'legacy/constants' import { Order } from 'legacy/state/orders/actions' /** diff --git a/apps/cowswap-frontend/src/utils/orderUtils/getOrderSurplus.ts b/apps/cowswap-frontend/src/utils/orderUtils/getOrderSurplus.ts index 77f6270ec5..6089b0ab4c 100644 --- a/apps/cowswap-frontend/src/utils/orderUtils/getOrderSurplus.ts +++ b/apps/cowswap-frontend/src/utils/orderUtils/getOrderSurplus.ts @@ -1,8 +1,9 @@ // Util functions that only pertain to/deal with operator API related stuff +import { ZERO_BIG_NUMBER } from '@cowprotocol/common-const' + import BigNumber from 'bignumber.js' import JSBI from 'jsbi' -import { ZERO_BIG_NUMBER } from 'legacy/constants' import { Order } from 'legacy/state/orders/actions' import { getOrderExecutedAmounts } from './getOrderExecutedAmounts' diff --git a/apps/cowswap-frontend/src/utils/orderUtils/getTokenFromMapping.ts b/apps/cowswap-frontend/src/utils/orderUtils/getTokenFromMapping.ts index 11fccd9a07..b0e3a4735c 100644 --- a/apps/cowswap-frontend/src/utils/orderUtils/getTokenFromMapping.ts +++ b/apps/cowswap-frontend/src/utils/orderUtils/getTokenFromMapping.ts @@ -1,11 +1,9 @@ +import { NATIVE_CURRENCY_BUY_TOKEN } from '@cowprotocol/common-const' +import { getIsNativeToken } from '@cowprotocol/common-utils' import { SupportedChainId } from '@cowprotocol/cow-sdk' import { getAddress } from '@ethersproject/address' import { Token } from '@uniswap/sdk-core' -import { NATIVE_CURRENCY_BUY_TOKEN } from 'legacy/constants' - -import { getIsNativeToken } from '../getIsNativeToken' - export function getTokenFromMapping( address: string, chainId: SupportedChainId, diff --git a/apps/cowswap-frontend/src/utils/orderUtils/parseOrder.ts b/apps/cowswap-frontend/src/utils/orderUtils/parseOrder.ts index a799edb648..a18121cfe9 100644 --- a/apps/cowswap-frontend/src/utils/orderUtils/parseOrder.ts +++ b/apps/cowswap-frontend/src/utils/orderUtils/parseOrder.ts @@ -33,6 +33,7 @@ export interface ParsedOrderExecutionData { export interface ParsedOrder { id: string + owner: string isCancelling: boolean | undefined receiver: string | undefined inputToken: Token @@ -47,6 +48,7 @@ export interface ParsedOrder { creationTime: Date expirationTime: Date composableCowInfo?: ComposableCowInfo + fullAppData: Order['fullAppData'] executionData: ParsedOrderExecutionData } @@ -94,6 +96,7 @@ export const parseOrder = (order: Order): ParsedOrder => { return { id: order.id, + owner: order.owner, isCancelling: order.isCancelling, inputToken: order.inputToken, outputToken: order.outputToken, @@ -108,6 +111,7 @@ export const parseOrder = (order: Order): ParsedOrder => { receiver: order.receiver || undefined, creationTime, expirationTime, + fullAppData: order.fullAppData, executionData, } } diff --git a/apps/cowswap-frontend/tsconfig.json b/apps/cowswap-frontend/tsconfig.json index 65e6c88429..fd5681c653 100644 --- a/apps/cowswap-frontend/tsconfig.json +++ b/apps/cowswap-frontend/tsconfig.json @@ -9,12 +9,20 @@ "types": ["node", "vite/client"], "baseUrl": "src", "paths": { - "@cowswap/abis": ["../../../libs/abis/src/index.ts"], - "@cowswap/ui": ["../../../libs/ui/src/index.ts"], - "@cowswap/ui-utils": ["../../../libs/ui-utils/src/index.ts"], - "@cowswap/widget-lib": ["../../../libs/widget-lib/src/index.ts"], - "@cowswap/widget-react": ["../../../libs/widget-react/src/index.ts"], - "@cowswap/snackbars": ["../../../libs/snackbars/src/index.ts"] + "@cowprotocol/abis": ["../../../libs/abis/src/index.ts"], + "@cowprotocol/ui": ["../../../libs/ui/src/index.ts"], + "@cowprotocol/ui-utils": ["../../../libs/ui-utils/src/index.ts"], + "@cowprotocol/widget-lib": ["../../../libs/widget-lib/src/index.ts"], + "@cowprotocol/widget-react": ["../../../libs/widget-react/src/index.ts"], + "@cowprotocol/snackbars": ["../../../libs/snackbars/src/index.ts"], + "@cowprotocol/wallet": ["../../../libs/wallet/src/index.ts"], + "@cowprotocol/assets/*": ["../../../libs/assets/src/*"], + "@cowprotocol/common-const": ["../../../libs/common-const/src/index.ts"], + "@cowprotocol/common-utils": ["../../../libs/common-utils/src/index.ts"], + "@cowprotocol/common-hooks": ["../../../libs/common-hooks/src/index.ts"], + "@cowprotocol/ens": ["../../../libs/ens/src/index.ts"], + "@cowprotocol/core": ["../../../libs/core/src/index.ts"], + "@cowprotocol/analytics": ["../../../libs/analytics/src/index.ts"] } }, "files": [], diff --git a/apps/cowswap-frontend/vite.config.ts b/apps/cowswap-frontend/vite.config.ts index 2c06ac89b6..ba713e5870 100644 --- a/apps/cowswap-frontend/vite.config.ts +++ b/apps/cowswap-frontend/vite.config.ts @@ -3,14 +3,14 @@ import { lingui } from '@lingui/vite-plugin' import react from '@vitejs/plugin-react-swc' import stdLibBrowser from 'node-stdlib-browser' import { visualizer } from 'rollup-plugin-visualizer' -import { defineConfig, loadEnv, PluginOption, searchForWorkspaceRoot } from 'vite' +import { defineConfig, PluginOption, searchForWorkspaceRoot } from 'vite' import macrosPlugin from 'vite-plugin-babel-macros' import { ModuleNameWithoutNodePrefix, nodePolyfills } from 'vite-plugin-node-polyfills' import { VitePWA } from 'vite-plugin-pwa' import svgr from 'vite-plugin-svgr' import viteTsConfigPaths from 'vite-tsconfig-paths' -import * as path from 'path' +import { getReactProcessEnv } from '../../tools/getReactProcessEnv' // eslint-disable-next-line no-restricted-imports import type { TemplateType } from 'rollup-plugin-visualizer/dist/plugin/template-types' @@ -24,16 +24,6 @@ const analyzeBundle = process.env.ANALYZE_BUNDLE === 'true' const analyzeBundleTemplate: TemplateType = (process.env.ANALYZE_BUNDLE_TEMPLATE as TemplateType) || 'treemap' // "sunburst" | "treemap" | "network" | "raw-data" | "list"; export default defineConfig(({ mode }) => { - const env = loadEnv(mode, process.cwd(), ['REACT_APP_']) - - // expose .env as process.env instead of import.meta since jest does not import meta yet - const envWithProcessPrefix = Object.entries(env).reduce((prev, [key, val]) => { - return { - ...prev, - ['process.env.' + key]: JSON.stringify(val), - } - }, {}) - const plugins = [ nodePolyfills({ exclude: allNodeDeps.filter((dep) => !nodeDepsToInclude.includes(dep)), @@ -81,7 +71,7 @@ export default defineConfig(({ mode }) => { return { define: { - ...envWithProcessPrefix, + ...getReactProcessEnv(mode), }, assetsInclude: ['**/*.md'], @@ -110,18 +100,6 @@ export default defineConfig(({ mode }) => { resolve: { alias: { 'node-fetch': 'isomorphic-fetch', - /** - * Temporary fix for walletconnect - * https://github.com/Uniswap/web3-react/issues/861 - */ - '@walletconnect/ethereum-provider': path.resolve( - __dirname, - '../../node_modules/@walletconnect/ethereum-provider/dist/umd/index.min.js' - ), - '@walletconnect/universal-provider': path.resolve( - __dirname, - '../../node_modules/@walletconnect/universal-provider/dist/index.cjs.js' - ), }, }, @@ -131,14 +109,9 @@ export default defineConfig(({ mode }) => { output: { manualChunks(id) { if (id.includes('@1inch')) return '@1inch' - if (id.includes('@amplitude')) return '@amplitude' - if (id.includes('@cowprotocol')) return '@cowprotocol' - if (id.includes('@ethersproject')) return '@ethersproject' - if (id.includes('@metamask') || id.includes('elliptic')) return '@metamask' if (id.includes('@safe-global') || id.includes('viem')) return '@safe-global' if (id.includes('@sentry')) return '@sentry' if (id.includes('@uniswap')) return '@uniswap' - if (id.includes('@walletconnect')) return '@walletconnect' if (id.includes('crypto-es/lib')) return 'crypto-es' if (id.includes('web3/dist')) return 'web3' }, diff --git a/apps/cowswap-frontend/yarn.lock b/apps/cowswap-frontend/yarn.lock new file mode 100644 index 0000000000..fb57ccd13a --- /dev/null +++ b/apps/cowswap-frontend/yarn.lock @@ -0,0 +1,4 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + diff --git a/jest.preset.js b/jest.preset.js index 8cd53f8e9b..9ba35593e5 100644 --- a/jest.preset.js +++ b/jest.preset.js @@ -1,3 +1,11 @@ const nxPreset = require('@nx/jest/preset').default -module.exports = { ...nxPreset } +module.exports = { + ...nxPreset, + moduleNameMapper: { + '\\.svg': '../../testing/svgrMock.js', + '\\.gif': '../../testing/imgMock.js', + '\\.webp': '../../testing/imgMock.js', + '\\.png': '../../testing/imgMock.js', + }, +} diff --git a/libs/abis/src/abis-legacy/erc20.json b/libs/abis/src/abis-legacy/erc20.json index dd7bf99d6e..58c0e583be 100644 --- a/libs/abis/src/abis-legacy/erc20.json +++ b/libs/abis/src/abis-legacy/erc20.json @@ -3,7 +3,12 @@ "constant": true, "inputs": [], "name": "name", - "outputs": [{ "name": "", "type": "string" }], + "outputs": [ + { + "name": "", + "type": "string" + } + ], "payable": false, "stateMutability": "view", "type": "function" @@ -11,11 +16,22 @@ { "constant": false, "inputs": [ - { "name": "_spender", "type": "address" }, - { "name": "_value", "type": "uint256" } + { + "name": "_spender", + "type": "address" + }, + { + "name": "_value", + "type": "uint256" + } ], "name": "approve", - "outputs": [{ "name": "", "type": "bool" }], + "outputs": [ + { + "name": "", + "type": "bool" + } + ], "payable": false, "stateMutability": "nonpayable", "type": "function" @@ -24,7 +40,12 @@ "constant": true, "inputs": [], "name": "totalSupply", - "outputs": [{ "name": "", "type": "uint256" }], + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], "payable": false, "stateMutability": "view", "type": "function" @@ -32,12 +53,26 @@ { "constant": false, "inputs": [ - { "name": "_from", "type": "address" }, - { "name": "_to", "type": "address" }, - { "name": "_value", "type": "uint256" } + { + "name": "_from", + "type": "address" + }, + { + "name": "_to", + "type": "address" + }, + { + "name": "_value", + "type": "uint256" + } ], "name": "transferFrom", - "outputs": [{ "name": "", "type": "bool" }], + "outputs": [ + { + "name": "", + "type": "bool" + } + ], "payable": false, "stateMutability": "nonpayable", "type": "function" @@ -46,16 +81,31 @@ "constant": true, "inputs": [], "name": "decimals", - "outputs": [{ "name": "", "type": "uint8" }], + "outputs": [ + { + "name": "", + "type": "uint8" + } + ], "payable": false, "stateMutability": "view", "type": "function" }, { "constant": true, - "inputs": [{ "name": "_owner", "type": "address" }], + "inputs": [ + { + "name": "_owner", + "type": "address" + } + ], "name": "balanceOf", - "outputs": [{ "name": "balance", "type": "uint256" }], + "outputs": [ + { + "name": "balance", + "type": "uint256" + } + ], "payable": false, "stateMutability": "view", "type": "function" @@ -64,7 +114,12 @@ "constant": true, "inputs": [], "name": "symbol", - "outputs": [{ "name": "", "type": "string" }], + "outputs": [ + { + "name": "", + "type": "string" + } + ], "payable": false, "stateMutability": "view", "type": "function" @@ -72,11 +127,22 @@ { "constant": false, "inputs": [ - { "name": "_to", "type": "address" }, - { "name": "_value", "type": "uint256" } + { + "name": "_to", + "type": "address" + }, + { + "name": "_value", + "type": "uint256" + } ], "name": "transfer", - "outputs": [{ "name": "", "type": "bool" }], + "outputs": [ + { + "name": "", + "type": "bool" + } + ], "payable": false, "stateMutability": "nonpayable", "type": "function" @@ -84,22 +150,49 @@ { "constant": true, "inputs": [ - { "name": "_owner", "type": "address" }, - { "name": "_spender", "type": "address" } + { + "name": "_owner", + "type": "address" + }, + { + "name": "_spender", + "type": "address" + } ], "name": "allowance", - "outputs": [{ "name": "", "type": "uint256" }], + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], "payable": false, "stateMutability": "view", "type": "function" }, - { "payable": true, "stateMutability": "payable", "type": "fallback" }, + { + "payable": true, + "stateMutability": "payable", + "type": "fallback" + }, { "anonymous": false, "inputs": [ - { "indexed": true, "name": "owner", "type": "address" }, - { "indexed": true, "name": "spender", "type": "address" }, - { "indexed": false, "name": "value", "type": "uint256" } + { + "indexed": true, + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "name": "spender", + "type": "address" + }, + { + "indexed": false, + "name": "value", + "type": "uint256" + } ], "name": "Approval", "type": "event" @@ -107,11 +200,85 @@ { "anonymous": false, "inputs": [ - { "indexed": true, "name": "from", "type": "address" }, - { "indexed": true, "name": "to", "type": "address" }, - { "indexed": false, "name": "value", "type": "uint256" } + { + "indexed": true, + "name": "from", + "type": "address" + }, + { + "indexed": true, + "name": "to", + "type": "address" + }, + { + "indexed": false, + "name": "value", + "type": "uint256" + } ], "name": "Transfer", "type": "event" + }, + { + "constant": true, + "inputs": [ + { + "name": "owner", + "type": "address" + } + ], + "name": "nonces", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "internalType": "address", + "name": "spender", + "type": "address" + }, + { + "internalType": "uint256", + "name": "value", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + }, + { + "internalType": "uint8", + "name": "v", + "type": "uint8" + }, + { + "internalType": "bytes32", + "name": "r", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "s", + "type": "bytes32" + } + ], + "name": "permit", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" } ] diff --git a/libs/abis/src/abis/CoWSwapEthFlow.json b/libs/abis/src/abis/CoWSwapEthFlow.json new file mode 100644 index 0000000000..2e76a24b83 --- /dev/null +++ b/libs/abis/src/abis/CoWSwapEthFlow.json @@ -0,0 +1,152 @@ +[ + { + "inputs": [ + { + "components": [ + { + "internalType": "contract IERC20", + "name": "buyToken", + "type": "address" + }, + { + "internalType": "address", + "name": "receiver", + "type": "address" + }, + { + "internalType": "uint256", + "name": "sellAmount", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "buyAmount", + "type": "uint256" + }, + { + "internalType": "bytes32", + "name": "appData", + "type": "bytes32" + }, + { + "internalType": "uint256", + "name": "feeAmount", + "type": "uint256" + }, + { + "internalType": "uint32", + "name": "validTo", + "type": "uint32" + }, + { + "internalType": "bool", + "name": "partiallyFillable", + "type": "bool" + }, + { + "internalType": "int64", + "name": "quoteId", + "type": "int64" + } + ], + "internalType": "struct EthFlowOrder.Data", + "name": "order", + "type": "tuple" + } + ], + "name": "createOrder", + "outputs": [ + { + "internalType": "bytes32", + "name": "orderHash", + "type": "bytes32" + } + ], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "contract IERC20", + "name": "buyToken", + "type": "address" + }, + { + "internalType": "address", + "name": "receiver", + "type": "address" + }, + { + "internalType": "uint256", + "name": "sellAmount", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "buyAmount", + "type": "uint256" + }, + { + "internalType": "bytes32", + "name": "appData", + "type": "bytes32" + }, + { + "internalType": "uint256", + "name": "feeAmount", + "type": "uint256" + }, + { + "internalType": "uint32", + "name": "validTo", + "type": "uint32" + }, + { + "internalType": "bool", + "name": "partiallyFillable", + "type": "bool" + }, + { + "internalType": "int64", + "name": "quoteId", + "type": "int64" + } + ], + "internalType": "struct EthFlowOrder.Data", + "name": "order", + "type": "tuple" + } + ], + "name": "invalidateOrder", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "name": "orders", + "outputs": [ + { + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "internalType": "uint32", + "name": "validTo", + "type": "uint32" + } + ], + "stateMutability": "view", + "type": "function" + } +] diff --git a/libs/abis/src/generated/legacy/Erc20.ts b/libs/abis/src/generated/legacy/Erc20.ts index 54c74b62a9..2de889a712 100644 --- a/libs/abis/src/generated/legacy/Erc20.ts +++ b/libs/abis/src/generated/legacy/Erc20.ts @@ -28,6 +28,8 @@ export interface Erc20Interface extends utils.Interface { 'symbol()': FunctionFragment 'transfer(address,uint256)': FunctionFragment 'allowance(address,address)': FunctionFragment + 'nonces(address)': FunctionFragment + 'permit(address,address,uint256,uint256,uint8,bytes32,bytes32)': FunctionFragment } getFunction( @@ -41,6 +43,8 @@ export interface Erc20Interface extends utils.Interface { | 'symbol' | 'transfer' | 'allowance' + | 'nonces' + | 'permit' ): FunctionFragment encodeFunctionData(functionFragment: 'name', values?: undefined): string @@ -61,6 +65,19 @@ export interface Erc20Interface extends utils.Interface { values: [PromiseOrValue, PromiseOrValue] ): string encodeFunctionData(functionFragment: 'allowance', values: [PromiseOrValue, PromiseOrValue]): string + encodeFunctionData(functionFragment: 'nonces', values: [PromiseOrValue]): string + encodeFunctionData( + functionFragment: 'permit', + values: [ + PromiseOrValue, + PromiseOrValue, + PromiseOrValue, + PromiseOrValue, + PromiseOrValue, + PromiseOrValue, + PromiseOrValue + ] + ): string decodeFunctionResult(functionFragment: 'name', data: BytesLike): Result decodeFunctionResult(functionFragment: 'approve', data: BytesLike): Result @@ -71,6 +88,8 @@ export interface Erc20Interface extends utils.Interface { decodeFunctionResult(functionFragment: 'symbol', data: BytesLike): Result decodeFunctionResult(functionFragment: 'transfer', data: BytesLike): Result decodeFunctionResult(functionFragment: 'allowance', data: BytesLike): Result + decodeFunctionResult(functionFragment: 'nonces', data: BytesLike): Result + decodeFunctionResult(functionFragment: 'permit', data: BytesLike): Result events: { 'Approval(address,address,uint256)': EventFragment @@ -156,6 +175,19 @@ export interface Erc20 extends BaseContract { _spender: PromiseOrValue, overrides?: CallOverrides ): Promise<[BigNumber]> + + nonces(owner: PromiseOrValue, overrides?: CallOverrides): Promise<[BigNumber]> + + permit( + owner: PromiseOrValue, + spender: PromiseOrValue, + value: PromiseOrValue, + deadline: PromiseOrValue, + v: PromiseOrValue, + r: PromiseOrValue, + s: PromiseOrValue, + overrides?: Overrides & { from?: PromiseOrValue } + ): Promise } name(overrides?: CallOverrides): Promise @@ -193,6 +225,19 @@ export interface Erc20 extends BaseContract { overrides?: CallOverrides ): Promise + nonces(owner: PromiseOrValue, overrides?: CallOverrides): Promise + + permit( + owner: PromiseOrValue, + spender: PromiseOrValue, + value: PromiseOrValue, + deadline: PromiseOrValue, + v: PromiseOrValue, + r: PromiseOrValue, + s: PromiseOrValue, + overrides?: Overrides & { from?: PromiseOrValue } + ): Promise + callStatic: { name(overrides?: CallOverrides): Promise @@ -228,6 +273,19 @@ export interface Erc20 extends BaseContract { _spender: PromiseOrValue, overrides?: CallOverrides ): Promise + + nonces(owner: PromiseOrValue, overrides?: CallOverrides): Promise + + permit( + owner: PromiseOrValue, + spender: PromiseOrValue, + value: PromiseOrValue, + deadline: PromiseOrValue, + v: PromiseOrValue, + r: PromiseOrValue, + s: PromiseOrValue, + overrides?: CallOverrides + ): Promise } filters: { @@ -289,6 +347,19 @@ export interface Erc20 extends BaseContract { _spender: PromiseOrValue, overrides?: CallOverrides ): Promise + + nonces(owner: PromiseOrValue, overrides?: CallOverrides): Promise + + permit( + owner: PromiseOrValue, + spender: PromiseOrValue, + value: PromiseOrValue, + deadline: PromiseOrValue, + v: PromiseOrValue, + r: PromiseOrValue, + s: PromiseOrValue, + overrides?: Overrides & { from?: PromiseOrValue } + ): Promise } populateTransaction: { @@ -326,5 +397,18 @@ export interface Erc20 extends BaseContract { _spender: PromiseOrValue, overrides?: CallOverrides ): Promise + + nonces(owner: PromiseOrValue, overrides?: CallOverrides): Promise + + permit( + owner: PromiseOrValue, + spender: PromiseOrValue, + value: PromiseOrValue, + deadline: PromiseOrValue, + v: PromiseOrValue, + r: PromiseOrValue, + s: PromiseOrValue, + overrides?: Overrides & { from?: PromiseOrValue } + ): Promise } } diff --git a/libs/abis/src/generated/legacy/factories/Erc20__factory.ts b/libs/abis/src/generated/legacy/factories/Erc20__factory.ts index d0ccd7b39f..b344021c45 100644 --- a/libs/abis/src/generated/legacy/factories/Erc20__factory.ts +++ b/libs/abis/src/generated/legacy/factories/Erc20__factory.ts @@ -227,6 +227,68 @@ const _abi = [ name: 'Transfer', type: 'event', }, + { + constant: true, + inputs: [ + { + name: 'owner', + type: 'address', + }, + ], + name: 'nonces', + outputs: [ + { + name: '', + type: 'uint256', + }, + ], + payable: false, + stateMutability: 'view', + type: 'function', + }, + { + inputs: [ + { + internalType: 'address', + name: 'owner', + type: 'address', + }, + { + internalType: 'address', + name: 'spender', + type: 'address', + }, + { + internalType: 'uint256', + name: 'value', + type: 'uint256', + }, + { + internalType: 'uint256', + name: 'deadline', + type: 'uint256', + }, + { + internalType: 'uint8', + name: 'v', + type: 'uint8', + }, + { + internalType: 'bytes32', + name: 'r', + type: 'bytes32', + }, + { + internalType: 'bytes32', + name: 's', + type: 'bytes32', + }, + ], + name: 'permit', + outputs: [], + stateMutability: 'nonpayable', + type: 'function', + }, ] as const export class Erc20__factory { diff --git a/libs/abis/src/index.ts b/libs/abis/src/index.ts index 0c312d27c5..7f3cce77fd 100644 --- a/libs/abis/src/index.ts +++ b/libs/abis/src/index.ts @@ -11,6 +11,8 @@ import _MerkleDropAbi from './abis/MerkleDrop.json' import _TokenDistroAbi from './abis/TokenDistro.json' +import _CoWSwapEthFlowAbi from './abis/CoWSwapEthFlow.json' + import _ethFlowBarnJson from '@cowprotocol/ethflowcontract/networks.barn.json' import _ethFlowProdJson from '@cowprotocol/ethflowcontract/networks.prod.json' @@ -20,8 +22,6 @@ import _ArgentWalletContractAbi from './abis-legacy/argent-wallet-contract.json' import _ArgentWalletDetectorAbi from './abis-legacy/argent-wallet-detector.json' -import _CoWSwapEthFlowJson from '@cowprotocol/ethflowcontract/artifacts/CoWSwapEthFlow.sol/CoWSwapEthFlow.json' - import _Eip2612Abi from './abis-legacy/eip_2612.json' import _EnsPublicResolverAbi from './abis-legacy/ens-public-resolver.json' @@ -46,6 +46,7 @@ export const vCowAbi = _vCowAbi export const SignatureVerifierMuxerAbi = _SignatureVerifierMuxerAbi export const MerkleDropAbi = _MerkleDropAbi export const TokenDistroAbi = _TokenDistroAbi +export const CoWSwapEthFlowAbi = _CoWSwapEthFlowAbi export * from './generated/custom' export type { GPv2Order } from './generated/custom/ComposableCoW' @@ -71,7 +72,6 @@ export const ethFlowBarnJson = _ethFlowBarnJson export const ethFlowProdJson = _ethFlowProdJson export const ArgentWalletContractAbi = _ArgentWalletContractAbi export const ArgentWalletDetectorAbi = _ArgentWalletDetectorAbi -export const CoWSwapEthFlowJson = _CoWSwapEthFlowJson export const Eip2612Abi = _Eip2612Abi export const EnsPublicResolverAbi = _EnsPublicResolverAbi export const EnsAbi = _EnsAbi diff --git a/libs/analytics/.babelrc b/libs/analytics/.babelrc new file mode 100644 index 0000000000..ef4889c1ab --- /dev/null +++ b/libs/analytics/.babelrc @@ -0,0 +1,20 @@ +{ + "presets": [ + [ + "@nx/react/babel", + { + "runtime": "automatic", + "useBuiltIns": "usage" + } + ] + ], + "plugins": [ + [ + "styled-components", + { + "pure": true, + "ssr": true + } + ] + ] +} diff --git a/libs/analytics/.eslintrc.json b/libs/analytics/.eslintrc.json new file mode 100644 index 0000000000..231aaa5f83 --- /dev/null +++ b/libs/analytics/.eslintrc.json @@ -0,0 +1,21 @@ +{ + "extends": ["plugin:@nx/react", "../../.eslintrc.json"], + "ignorePatterns": ["!**/*"], + "rules": { + "@typescript-eslint/no-explicit-any": "off" + }, + "overrides": [ + { + "files": ["*.ts", "*.tsx", "*.js", "*.jsx"], + "rules": {} + }, + { + "files": ["*.ts", "*.tsx"], + "rules": {} + }, + { + "files": ["*.js", "*.jsx"], + "rules": {} + } + ] +} diff --git a/libs/analytics/README.md b/libs/analytics/README.md new file mode 100644 index 0000000000..f097a1dbbf --- /dev/null +++ b/libs/analytics/README.md @@ -0,0 +1 @@ +# Analytics diff --git a/libs/analytics/jest.config.ts b/libs/analytics/jest.config.ts new file mode 100644 index 0000000000..2e6915c373 --- /dev/null +++ b/libs/analytics/jest.config.ts @@ -0,0 +1,11 @@ +/* eslint-disable */ +export default { + displayName: 'analytics', + preset: '../../jest.preset.js', + transform: { + '^(?!.*\\.(js|jsx|ts|tsx|css|json)$)': '@nx/react/plugins/jest', + '^.+\\.[tj]sx?$': ['babel-jest', { presets: ['@nx/react/babel'] }], + }, + moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx'], + coverageDirectory: '../../coverage/libs/analytics', +} diff --git a/libs/analytics/package.json b/libs/analytics/package.json new file mode 100644 index 0000000000..31f055efc5 --- /dev/null +++ b/libs/analytics/package.json @@ -0,0 +1,12 @@ +{ + "name": "@cowprotocol/analytics", + "version": "0.0.1", + "main": "./index.js", + "types": "./index.d.ts", + "exports": { + ".": { + "import": "./index.mjs", + "require": "./index.js" + } + } +} diff --git a/libs/analytics/project.json b/libs/analytics/project.json new file mode 100644 index 0000000000..3943c48429 --- /dev/null +++ b/libs/analytics/project.json @@ -0,0 +1,46 @@ +{ + "name": "@cowprotocol/analytics", + "$schema": "../../node_modules/nx/schemas/project-schema.json", + "sourceRoot": "libs/analytics/src", + "projectType": "library", + "tags": [], + "targets": { + "lint": { + "executor": "@nx/linter:eslint", + "outputs": ["{options.outputFile}"], + "options": { + "lintFilePatterns": ["libs/analytics/**/*.{ts,tsx,js,jsx}"] + } + }, + "build": { + "executor": "@nx/vite:build", + "outputs": ["{options.outputPath}"], + "defaultConfiguration": "production", + "options": { + "outputPath": "dist/libs/analytics" + }, + "configurations": { + "development": { + "mode": "development" + }, + "production": { + "mode": "production" + } + } + }, + "test": { + "executor": "@nx/jest:jest", + "outputs": ["{workspaceRoot}/coverage/{projectRoot}"], + "options": { + "jestConfig": "libs/analytics/jest.config.ts", + "passWithNoTests": true + }, + "configurations": { + "ci": { + "ci": true, + "codeCoverage": true + } + } + } + } +} diff --git a/apps/cowswap-frontend/src/legacy/components/analytics/events/cowFortune.ts b/libs/analytics/src/events/cowFortune.ts similarity index 100% rename from apps/cowswap-frontend/src/legacy/components/analytics/events/cowFortune.ts rename to libs/analytics/src/events/cowFortune.ts diff --git a/apps/cowswap-frontend/src/legacy/components/analytics/events/listEvents.ts b/libs/analytics/src/events/listEvents.ts similarity index 100% rename from apps/cowswap-frontend/src/legacy/components/analytics/events/listEvents.ts rename to libs/analytics/src/events/listEvents.ts diff --git a/apps/cowswap-frontend/src/legacy/components/analytics/events/otherEvents.ts b/libs/analytics/src/events/otherEvents.ts similarity index 94% rename from apps/cowswap-frontend/src/legacy/components/analytics/events/otherEvents.ts rename to libs/analytics/src/events/otherEvents.ts index 132edbaae1..eab7c4cb22 100644 --- a/apps/cowswap-frontend/src/legacy/components/analytics/events/otherEvents.ts +++ b/libs/analytics/src/events/otherEvents.ts @@ -1,4 +1,4 @@ -import { detectExplorer } from 'legacy/utils/explorer' +import { detectExplorer } from '@cowprotocol/common-utils' import { sendEvent } from '../googleAnalytics' import { Category } from '../types' diff --git a/apps/cowswap-frontend/src/legacy/components/analytics/events/settingsEvents.ts b/libs/analytics/src/events/settingsEvents.ts similarity index 95% rename from apps/cowswap-frontend/src/legacy/components/analytics/events/settingsEvents.ts rename to libs/analytics/src/events/settingsEvents.ts index af0c0ffc5e..0718548e96 100644 --- a/apps/cowswap-frontend/src/legacy/components/analytics/events/settingsEvents.ts +++ b/libs/analytics/src/events/settingsEvents.ts @@ -1,4 +1,4 @@ -import { debounce } from 'legacy/utils/misc' +import { debounce } from '@cowprotocol/common-utils' import { sendEvent } from '../googleAnalytics' import { Category } from '../types' diff --git a/apps/cowswap-frontend/src/legacy/components/analytics/events/swapEvents.ts b/libs/analytics/src/events/swapEvents.ts similarity index 75% rename from apps/cowswap-frontend/src/legacy/components/analytics/events/swapEvents.ts rename to libs/analytics/src/events/swapEvents.ts index 8f0956776f..fdb7bf7798 100644 --- a/apps/cowswap-frontend/src/legacy/components/analytics/events/swapEvents.ts +++ b/libs/analytics/src/events/swapEvents.ts @@ -1,10 +1,9 @@ -import { Field } from 'legacy/state/swap/actions' -import { debounce } from 'legacy/utils/misc' +import { debounce } from '@cowprotocol/common-utils' import { sendEvent } from '../googleAnalytics' import { Category } from '../types' -export function currencySelectAnalytics(field: Field, label: string | undefined) { +export function currencySelectAnalytics(field: string, label: string | undefined) { sendEvent({ category: Category.CURRENCY_SELECT, action: `Change ${field} token`, @@ -19,7 +18,7 @@ export function setMaxSellTokensAnalytics() { }) } -function _changeSwapAmountAnalytics(field: Field, value: number) { +function _changeSwapAmountAnalytics(field: string, value: number) { sendEvent({ category: Category.TRADE, action: `Change ${field} field amount`, @@ -27,7 +26,7 @@ function _changeSwapAmountAnalytics(field: Field, value: number) { }) } -export const changeSwapAmountAnalytics = debounce(([field, value]: [Field, number]) => { +export const changeSwapAmountAnalytics = debounce(([field, value]: [string, number]) => { _changeSwapAmountAnalytics(field, value) }, 2000) diff --git a/apps/cowswap-frontend/src/legacy/components/analytics/events/themeEvents.ts b/libs/analytics/src/events/themeEvents.ts similarity index 100% rename from apps/cowswap-frontend/src/legacy/components/analytics/events/themeEvents.ts rename to libs/analytics/src/events/themeEvents.ts diff --git a/apps/cowswap-frontend/src/legacy/components/analytics/events/transactionEvents.ts b/libs/analytics/src/events/transactionEvents.ts similarity index 80% rename from apps/cowswap-frontend/src/legacy/components/analytics/events/transactionEvents.ts rename to libs/analytics/src/events/transactionEvents.ts index 7e220b2591..94ad4d9dc7 100644 --- a/apps/cowswap-frontend/src/legacy/components/analytics/events/transactionEvents.ts +++ b/libs/analytics/src/events/transactionEvents.ts @@ -1,13 +1,7 @@ import { OrderClass } from '@cowprotocol/cow-sdk' import { sendEvent } from '../googleAnalytics' -import { PIXEL_EVENTS } from '../pixel/constants' -import { sendFacebookEvent } from '../pixel/facebook' -import { sendLinkedinEvent } from '../pixel/linkedin' -import { sendMicrosoftEvent } from '../pixel/microsoft' -import { sendPavedEvent } from '../pixel/paved' -import { sendRedditEvent } from '../pixel/reddit' -import { sendTwitterEvent } from '../pixel/twitter' +import { PixelEvent, sendAllPixels } from '../pixel' import { AnalyticsOrderType, Category } from '../types' const LABEL_FROM_CLASS: Record = { @@ -86,12 +80,7 @@ export function signTradeAnalytics(orderClass: AnalyticsOrderType, label?: strin export type OrderType = 'Posted' | 'Executed' | 'Canceled' | 'Expired' export function orderAnalytics(action: OrderType, orderClass: AnalyticsOrderType, label?: string) { if (action === 'Posted') { - sendFacebookEvent(PIXEL_EVENTS.POST_TRADE) - sendLinkedinEvent(PIXEL_EVENTS.POST_TRADE) - sendTwitterEvent(PIXEL_EVENTS.POST_TRADE) - sendRedditEvent(PIXEL_EVENTS.POST_TRADE) - sendPavedEvent(PIXEL_EVENTS.POST_TRADE) - sendMicrosoftEvent(PIXEL_EVENTS.POST_TRADE) + sendAllPixels(PixelEvent.POST_TRADE) } sendEvent({ diff --git a/apps/cowswap-frontend/src/legacy/components/analytics/events/twapEvents.ts b/libs/analytics/src/events/twapEvents.ts similarity index 100% rename from apps/cowswap-frontend/src/legacy/components/analytics/events/twapEvents.ts rename to libs/analytics/src/events/twapEvents.ts diff --git a/apps/cowswap-frontend/src/legacy/components/analytics/events/walletEvents.ts b/libs/analytics/src/events/walletEvents.ts similarity index 100% rename from apps/cowswap-frontend/src/legacy/components/analytics/events/walletEvents.ts rename to libs/analytics/src/events/walletEvents.ts diff --git a/apps/cowswap-frontend/src/legacy/components/analytics/googleAnalytics.ts b/libs/analytics/src/googleAnalytics.ts similarity index 100% rename from apps/cowswap-frontend/src/legacy/components/analytics/googleAnalytics.ts rename to libs/analytics/src/googleAnalytics.ts diff --git a/apps/cowswap-frontend/src/legacy/components/analytics/index.ts b/libs/analytics/src/index.ts similarity index 87% rename from apps/cowswap-frontend/src/legacy/components/analytics/index.ts rename to libs/analytics/src/index.ts index 64a6c8420e..884c06dbc5 100644 --- a/apps/cowswap-frontend/src/legacy/components/analytics/index.ts +++ b/libs/analytics/src/index.ts @@ -1,11 +1,9 @@ -import { isMobile } from 'legacy/utils/userAgent' +import { isMobile } from '@cowprotocol/common-utils' import { initAnalytics, serviceWorkerAnalytics } from './events/otherEvents' import { googleAnalytics } from './googleAnalytics' import { Dimensions } from './types' -export { useAnalyticsReporter } from './hooks/useAnalyticsReporter' - const GOOGLE_ANALYTICS_ID: string | undefined = process.env.REACT_APP_GOOGLE_ANALYTICS_ID export const GOOGLE_ANALYTICS_CLIENT_ID_STORAGE_KEY = 'ga_client_id' @@ -42,7 +40,6 @@ if (typeof GOOGLE_ANALYTICS_ID === 'string') { serviceWorkerAnalytics() initAnalytics() -// MOD export * from './events/listEvents' export * from './events/settingsEvents' export * from './events/themeEvents' @@ -50,3 +47,8 @@ export * from './events/transactionEvents' export * from './events/walletEvents' export * from './events/swapEvents' export * from './events/otherEvents' +export * from './events/cowFortune' +export * from './events/twapEvents' +export * from './googleAnalytics' +export * from './pixel' +export * from './types' diff --git a/libs/analytics/src/pixel/constants.ts b/libs/analytics/src/pixel/constants.ts new file mode 100644 index 0000000000..6428232da7 --- /dev/null +++ b/libs/analytics/src/pixel/constants.ts @@ -0,0 +1,3 @@ +import { isEns, isProd } from '@cowprotocol/common-utils' + +export const PIXEL_ENABLED = isProd || isEns diff --git a/libs/analytics/src/pixel/facebook.ts b/libs/analytics/src/pixel/facebook.ts new file mode 100644 index 0000000000..250e392cf6 --- /dev/null +++ b/libs/analytics/src/pixel/facebook.ts @@ -0,0 +1,17 @@ +import { enablePixel } from './sendAllPixels' +import { PixelEvent, PixelEventMap } from './types' +import { sendPixel } from './utils' + +const events: PixelEventMap = { + [PixelEvent.INIT]: 'InitiateCheckout', + [PixelEvent.CONNECT_WALLET]: 'Contact', + [PixelEvent.POST_TRADE]: 'Lead', +} + +const sendFacebookEvent = sendPixel((event) => { + window.fbq?.('track', events[event]) +}) + +export function enablePixelFacebook() { + enablePixel(events, sendFacebookEvent) +} diff --git a/libs/analytics/src/pixel/index.ts b/libs/analytics/src/pixel/index.ts new file mode 100644 index 0000000000..396dd8d9da --- /dev/null +++ b/libs/analytics/src/pixel/index.ts @@ -0,0 +1,9 @@ +export { sendAllPixels } from './sendAllPixels' +export * from './types' + +// Register +export { enablePixelFacebook } from './facebook' +export { enablePixelPaved } from './paved' +export { enablePixelReddit } from './reddit' +export { enablePixelTwitter } from './twitter' +export { enablePixelMicrosoft } from './microsoft' diff --git a/libs/analytics/src/pixel/linkedin.ts b/libs/analytics/src/pixel/linkedin.ts new file mode 100644 index 0000000000..102d9f4be3 --- /dev/null +++ b/libs/analytics/src/pixel/linkedin.ts @@ -0,0 +1,17 @@ +import { enablePixel } from './sendAllPixels' +import { PixelEvent, PixelEventMap } from './types' +import { sendPixel } from './utils' + +const events: PixelEventMap = { + [PixelEvent.INIT]: 10759506, + [PixelEvent.CONNECT_WALLET]: 10759514, + [PixelEvent.POST_TRADE]: 10759522, +} + +const sendLinkedinEvent = sendPixel((event) => { + window.lintrk?.('track', { conversion_id: events[event] }) +}) + +export function enablePixelLinkedin() { + enablePixel(events, sendLinkedinEvent) +} diff --git a/libs/analytics/src/pixel/microsoft.ts b/libs/analytics/src/pixel/microsoft.ts new file mode 100644 index 0000000000..618f30e3af --- /dev/null +++ b/libs/analytics/src/pixel/microsoft.ts @@ -0,0 +1,18 @@ +import { enablePixel } from './sendAllPixels' +import { PixelEvent, PixelEventMap } from './types' +import { sendPixel } from './utils' + +const events: PixelEventMap = { + [PixelEvent.INIT]: 'page_view', + [PixelEvent.CONNECT_WALLET]: 'begin_checkout', + [PixelEvent.POST_TRADE]: 'purchase', +} + +const sendMicrosoftEvent = sendPixel((event) => { + window.uetq = window.uetq || [] + window.uetq.push('event', events[event], {}) +}) + +export function enablePixelMicrosoft() { + enablePixel(events, sendMicrosoftEvent) +} diff --git a/libs/analytics/src/pixel/paved.ts b/libs/analytics/src/pixel/paved.ts new file mode 100644 index 0000000000..67b1bccd8b --- /dev/null +++ b/libs/analytics/src/pixel/paved.ts @@ -0,0 +1,17 @@ +import { enablePixel } from './sendAllPixels' +import { PixelEvent, PixelEventMap } from './types' +import { sendPixel } from './utils' + +const events: PixelEventMap = { + [PixelEvent.INIT]: 'search', + [PixelEvent.CONNECT_WALLET]: 'sign_up', + [PixelEvent.POST_TRADE]: 'purchase', +} + +const sendPavedEvent = sendPixel((event) => { + window.pvd?.('event', events[event]) +}) + +export function enablePixelPaved() { + enablePixel(events, sendPavedEvent) +} diff --git a/libs/analytics/src/pixel/reddit.ts b/libs/analytics/src/pixel/reddit.ts new file mode 100644 index 0000000000..eb77a53bd7 --- /dev/null +++ b/libs/analytics/src/pixel/reddit.ts @@ -0,0 +1,17 @@ +import { enablePixel } from './sendAllPixels' +import { PixelEvent, PixelEventMap } from './types' +import { sendPixel } from './utils' + +const events: PixelEventMap = { + [PixelEvent.INIT]: 'Lead', + [PixelEvent.CONNECT_WALLET]: 'SignUp', + [PixelEvent.POST_TRADE]: 'Purchase', +} + +const sendRedditEvent = sendPixel((event) => { + window.rdt?.('track', events[event]) +}) + +export function enablePixelReddit() { + enablePixel(events, sendRedditEvent) +} diff --git a/libs/analytics/src/pixel/sendAllPixels.ts b/libs/analytics/src/pixel/sendAllPixels.ts new file mode 100644 index 0000000000..67eb45570d --- /dev/null +++ b/libs/analytics/src/pixel/sendAllPixels.ts @@ -0,0 +1,35 @@ +import { PixelEvent, PixelEventMap, SendPixel } from './types' + +const sendPixelCallbacks: Map = new Map() + +/** + * Sends all the enabled pixels for the given event + * + * @param event event to send + */ +export function sendAllPixels(event: PixelEvent): void { + const callbacks = sendPixelCallbacks.get(event) + if (!callbacks) return + + callbacks.forEach((callback) => callback(event)) +} + +function _enablePixel(event: PixelEvent, sendPixel: SendPixel) { + let callbacks = sendPixelCallbacks.get(event) + if (!callbacks) { + callbacks = [] + sendPixelCallbacks.set(event, callbacks) + } + + callbacks.push(sendPixel) +} + +/** + * Register a pixel callback for the given set of events events + */ +export function enablePixel(eventMap: PixelEventMap, sendPixel: SendPixel) { + Object.keys(eventMap).forEach((event) => { + const e = event as PixelEvent + _enablePixel(e, sendPixel) + }) +} diff --git a/libs/analytics/src/pixel/twitter.ts b/libs/analytics/src/pixel/twitter.ts new file mode 100644 index 0000000000..40acb0f7f1 --- /dev/null +++ b/libs/analytics/src/pixel/twitter.ts @@ -0,0 +1,17 @@ +import { enablePixel } from './sendAllPixels' +import { PixelEvent, PixelEventMap } from './types' +import { sendPixel } from './utils' + +const events: PixelEventMap = { + [PixelEvent.INIT]: 'tw-oddz2-oddz8', + [PixelEvent.CONNECT_WALLET]: 'tw-oddz2-oddza', + [PixelEvent.POST_TRADE]: 'tw-oddz2-oddzb', +} + +export const sendTwitterEvent = sendPixel((event) => { + window.twq?.('event', events[event], {}) +}) + +export function enablePixelTwitter() { + enablePixel(events, sendTwitterEvent) +} diff --git a/libs/analytics/src/pixel/types.ts b/libs/analytics/src/pixel/types.ts new file mode 100644 index 0000000000..c0a554b750 --- /dev/null +++ b/libs/analytics/src/pixel/types.ts @@ -0,0 +1,9 @@ +export enum PixelEvent { + INIT = 'init', + CONNECT_WALLET = 'connect_wallet', + POST_TRADE = 'post_trade', +} + +export type SendPixel = (event: PixelEvent) => void + +export type PixelEventMap = Record diff --git a/apps/cowswap-frontend/src/legacy/components/analytics/pixel/utils.ts b/libs/analytics/src/pixel/utils.ts similarity index 52% rename from apps/cowswap-frontend/src/legacy/components/analytics/pixel/utils.ts rename to libs/analytics/src/pixel/utils.ts index 531f144a0c..fecc635b3a 100644 --- a/apps/cowswap-frontend/src/legacy/components/analytics/pixel/utils.ts +++ b/libs/analytics/src/pixel/utils.ts @@ -1,8 +1,7 @@ -import { PIXEL_ENABLED, PIXEL_EVENTS } from './constants' +import { PIXEL_ENABLED } from './constants' +import { SendPixel } from './types' -type SendPixelFn = (event: PIXEL_EVENTS) => void - -export function sendPixel(sendFn: SendPixelFn): SendPixelFn { +export function sendPixel(sendFn: SendPixel): SendPixel { return (event) => { if (!PIXEL_ENABLED) { return diff --git a/apps/cowswap-frontend/src/legacy/components/analytics/provider/index.ts b/libs/analytics/src/provider/index.ts similarity index 98% rename from apps/cowswap-frontend/src/legacy/components/analytics/provider/index.ts rename to libs/analytics/src/provider/index.ts index 2c807dc196..219a57d9df 100644 --- a/apps/cowswap-frontend/src/legacy/components/analytics/provider/index.ts +++ b/libs/analytics/src/provider/index.ts @@ -1,10 +1,10 @@ import { ErrorInfo } from 'react' +import { debounce } from '@cowprotocol/common-utils' + import ReactGA from 'react-ga4' import { GaOptions, InitOptions, UaEventOptions } from 'react-ga4/types/ga4' -import { debounce } from 'legacy/utils/misc' - import { Dimensions } from '../types' const DIMENSION_MAP = { diff --git a/apps/cowswap-frontend/src/legacy/components/analytics/types.ts b/libs/analytics/src/types.ts similarity index 100% rename from apps/cowswap-frontend/src/legacy/components/analytics/types.ts rename to libs/analytics/src/types.ts diff --git a/libs/analytics/tsconfig.json b/libs/analytics/tsconfig.json new file mode 100644 index 0000000000..bab74ff2e6 --- /dev/null +++ b/libs/analytics/tsconfig.json @@ -0,0 +1,21 @@ +{ + "compilerOptions": { + "jsx": "react-jsx", + "allowJs": false, + "esModuleInterop": false, + "allowSyntheticDefaultImports": true, + "strict": true, + "types": ["vite/client"] + }, + "files": [], + "include": [], + "references": [ + { + "path": "./tsconfig.lib.json" + }, + { + "path": "./tsconfig.spec.json" + } + ], + "extends": "../../tsconfig.base.json" +} diff --git a/libs/analytics/tsconfig.lib.json b/libs/analytics/tsconfig.lib.json new file mode 100644 index 0000000000..1b2b0c12df --- /dev/null +++ b/libs/analytics/tsconfig.lib.json @@ -0,0 +1,19 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "../../dist/out-tsc", + "types": ["node", "vite/client"] + }, + "files": ["../../node_modules/@nx/react/typings/cssmodule.d.ts", "../../node_modules/@nx/react/typings/image.d.ts"], + "exclude": [ + "**/*.spec.ts", + "**/*.test.ts", + "**/*.spec.tsx", + "**/*.test.tsx", + "**/*.spec.js", + "**/*.test.js", + "**/*.spec.jsx", + "**/*.test.jsx" + ], + "include": ["**/*.js", "**/*.jsx", "**/*.ts", "**/*.tsx"] +} diff --git a/libs/analytics/tsconfig.spec.json b/libs/analytics/tsconfig.spec.json new file mode 100644 index 0000000000..26ef046ac5 --- /dev/null +++ b/libs/analytics/tsconfig.spec.json @@ -0,0 +1,20 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "../../dist/out-tsc", + "module": "commonjs", + "types": ["jest", "node"] + }, + "include": [ + "jest.config.ts", + "src/**/*.test.ts", + "src/**/*.spec.ts", + "src/**/*.test.tsx", + "src/**/*.spec.tsx", + "src/**/*.test.js", + "src/**/*.spec.js", + "src/**/*.test.jsx", + "src/**/*.spec.jsx", + "src/**/*.d.ts" + ] +} diff --git a/libs/analytics/vite.config.ts b/libs/analytics/vite.config.ts new file mode 100644 index 0000000000..078f6d3ff0 --- /dev/null +++ b/libs/analytics/vite.config.ts @@ -0,0 +1,49 @@ +/// +import { defineConfig } from 'vite' +import react from '@vitejs/plugin-react-swc' +import viteTsConfigPaths from 'vite-tsconfig-paths' +import dts from 'vite-plugin-dts' +import * as path from 'path' + +export default defineConfig({ + cacheDir: '../../node_modules/.vite/analytics', + + plugins: [ + dts({ + entryRoot: 'src', + tsConfigFilePath: path.join(__dirname, 'tsconfig.lib.json'), + skipDiagnostics: true, + }), + react(), + viteTsConfigPaths({ + root: '../../', + }), + ], + + // Uncomment this if you are using workers. + // worker: { + // plugins: [ + // viteTsConfigPaths({ + // root: '../../', + // }), + // ], + // }, + + // Configuration for building your library. + // See: https://vitejs.dev/guide/build.html#library-mode + build: { + lib: { + // Could also be a dictionary or array of multiple entry points. + entry: 'src/index.ts', + name: 'analytics', + fileName: 'index', + // Change this to the formats you want to support. + // Don't forget to update your package.json as well. + formats: ['es', 'cjs'], + }, + rollupOptions: { + // External packages that should not be bundled into your library. + external: ['react', 'react-dom', 'react/jsx-runtime'], + }, + }, +}) diff --git a/libs/assets/.babelrc b/libs/assets/.babelrc new file mode 100644 index 0000000000..ef4889c1ab --- /dev/null +++ b/libs/assets/.babelrc @@ -0,0 +1,20 @@ +{ + "presets": [ + [ + "@nx/react/babel", + { + "runtime": "automatic", + "useBuiltIns": "usage" + } + ] + ], + "plugins": [ + [ + "styled-components", + { + "pure": true, + "ssr": true + } + ] + ] +} diff --git a/libs/assets/.eslintrc.json b/libs/assets/.eslintrc.json new file mode 100644 index 0000000000..a39ac5d057 --- /dev/null +++ b/libs/assets/.eslintrc.json @@ -0,0 +1,18 @@ +{ + "extends": ["plugin:@nx/react", "../../.eslintrc.json"], + "ignorePatterns": ["!**/*"], + "overrides": [ + { + "files": ["*.ts", "*.tsx", "*.js", "*.jsx"], + "rules": {} + }, + { + "files": ["*.ts", "*.tsx"], + "rules": {} + }, + { + "files": ["*.js", "*.jsx"], + "rules": {} + } + ] +} diff --git a/libs/assets/README.md b/libs/assets/README.md new file mode 100644 index 0000000000..5d1b13d506 --- /dev/null +++ b/libs/assets/README.md @@ -0,0 +1 @@ +# Assets diff --git a/libs/assets/jest.config.ts b/libs/assets/jest.config.ts new file mode 100644 index 0000000000..6fbf3d7c4d --- /dev/null +++ b/libs/assets/jest.config.ts @@ -0,0 +1,11 @@ +/* eslint-disable */ +export default { + displayName: 'assets', + preset: '../../jest.preset.js', + transform: { + '^(?!.*\\.(js|jsx|ts|tsx|css|json)$)': '@nx/react/plugins/jest', + '^.+\\.[tj]sx?$': ['babel-jest', { presets: ['@nx/react/babel'] }], + }, + moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx'], + coverageDirectory: '../../coverage/libs/assets', +} diff --git a/libs/assets/package.json b/libs/assets/package.json new file mode 100644 index 0000000000..a839ad81d8 --- /dev/null +++ b/libs/assets/package.json @@ -0,0 +1,12 @@ +{ + "name": "@cowprotocol/assets", + "version": "0.0.1", + "main": "./index.js", + "types": "./index.d.ts", + "exports": { + ".": { + "import": "./index.mjs", + "require": "./index.js" + } + } +} diff --git a/libs/assets/project.json b/libs/assets/project.json new file mode 100644 index 0000000000..564800aa19 --- /dev/null +++ b/libs/assets/project.json @@ -0,0 +1,46 @@ +{ + "name": "@cowprotocol/assets", + "$schema": "../../node_modules/nx/schemas/project-schema.json", + "sourceRoot": "libs/assets/src", + "projectType": "library", + "tags": [], + "targets": { + "lint": { + "executor": "@nx/linter:eslint", + "outputs": ["{options.outputFile}"], + "options": { + "lintFilePatterns": ["libs/assets/**/*.{ts,tsx,js,jsx}"] + } + }, + "build": { + "executor": "@nx/vite:build", + "outputs": ["{options.outputPath}"], + "defaultConfiguration": "production", + "options": { + "outputPath": "dist/libs/assets" + }, + "configurations": { + "development": { + "mode": "development" + }, + "production": { + "mode": "production" + } + } + }, + "test": { + "executor": "@nx/jest:jest", + "outputs": ["{workspaceRoot}/coverage/{projectRoot}"], + "options": { + "jestConfig": "libs/assets/jest.config.ts", + "passWithNoTests": true + }, + "configurations": { + "ci": { + "ci": true, + "codeCoverage": true + } + } + } + } +} diff --git a/apps/cowswap-frontend/src/legacy/assets/cow-swap/CowError.png b/libs/assets/src/cow-swap/CowError.png similarity index 100% rename from apps/cowswap-frontend/src/legacy/assets/cow-swap/CowError.png rename to libs/assets/src/cow-swap/CowError.png diff --git a/apps/cowswap-frontend/src/legacy/assets/cow-swap/alert-circle.svg b/libs/assets/src/cow-swap/alert-circle.svg similarity index 100% rename from apps/cowswap-frontend/src/legacy/assets/cow-swap/alert-circle.svg rename to libs/assets/src/cow-swap/alert-circle.svg diff --git a/apps/cowswap-frontend/src/legacy/assets/cow-swap/alert.svg b/libs/assets/src/cow-swap/alert.svg similarity index 100% rename from apps/cowswap-frontend/src/legacy/assets/cow-swap/alert.svg rename to libs/assets/src/cow-swap/alert.svg diff --git a/apps/cowswap-frontend/src/legacy/assets/cow-swap/ammslogo/0x.png b/libs/assets/src/cow-swap/ammslogo/0x.png similarity index 100% rename from apps/cowswap-frontend/src/legacy/assets/cow-swap/ammslogo/0x.png rename to libs/assets/src/cow-swap/ammslogo/0x.png diff --git a/apps/cowswap-frontend/src/legacy/assets/cow-swap/ammslogo/1inch.png b/libs/assets/src/cow-swap/ammslogo/1inch.png similarity index 100% rename from apps/cowswap-frontend/src/legacy/assets/cow-swap/ammslogo/1inch.png rename to libs/assets/src/cow-swap/ammslogo/1inch.png diff --git a/apps/cowswap-frontend/src/legacy/assets/cow-swap/ammslogo/baoswap.png b/libs/assets/src/cow-swap/ammslogo/baoswap.png similarity index 100% rename from apps/cowswap-frontend/src/legacy/assets/cow-swap/ammslogo/baoswap.png rename to libs/assets/src/cow-swap/ammslogo/baoswap.png diff --git a/apps/cowswap-frontend/src/legacy/assets/cow-swap/ammslogo/curve.png b/libs/assets/src/cow-swap/ammslogo/curve.png similarity index 100% rename from apps/cowswap-frontend/src/legacy/assets/cow-swap/ammslogo/curve.png rename to libs/assets/src/cow-swap/ammslogo/curve.png diff --git a/apps/cowswap-frontend/src/legacy/assets/cow-swap/ammslogo/elk.png b/libs/assets/src/cow-swap/ammslogo/elk.png similarity index 100% rename from apps/cowswap-frontend/src/legacy/assets/cow-swap/ammslogo/elk.png rename to libs/assets/src/cow-swap/ammslogo/elk.png diff --git a/apps/cowswap-frontend/src/legacy/assets/cow-swap/ammslogo/honeyswap.png b/libs/assets/src/cow-swap/ammslogo/honeyswap.png similarity index 100% rename from apps/cowswap-frontend/src/legacy/assets/cow-swap/ammslogo/honeyswap.png rename to libs/assets/src/cow-swap/ammslogo/honeyswap.png diff --git a/apps/cowswap-frontend/src/legacy/assets/cow-swap/ammslogo/levinswap.png b/libs/assets/src/cow-swap/ammslogo/levinswap.png similarity index 100% rename from apps/cowswap-frontend/src/legacy/assets/cow-swap/ammslogo/levinswap.png rename to libs/assets/src/cow-swap/ammslogo/levinswap.png diff --git a/apps/cowswap-frontend/src/legacy/assets/cow-swap/ammslogo/matcha.png b/libs/assets/src/cow-swap/ammslogo/matcha.png similarity index 100% rename from apps/cowswap-frontend/src/legacy/assets/cow-swap/ammslogo/matcha.png rename to libs/assets/src/cow-swap/ammslogo/matcha.png diff --git a/apps/cowswap-frontend/src/legacy/assets/cow-swap/ammslogo/paraswap.png b/libs/assets/src/cow-swap/ammslogo/paraswap.png similarity index 100% rename from apps/cowswap-frontend/src/legacy/assets/cow-swap/ammslogo/paraswap.png rename to libs/assets/src/cow-swap/ammslogo/paraswap.png diff --git a/apps/cowswap-frontend/src/legacy/assets/cow-swap/ammslogo/sushi.png b/libs/assets/src/cow-swap/ammslogo/sushi.png similarity index 100% rename from apps/cowswap-frontend/src/legacy/assets/cow-swap/ammslogo/sushi.png rename to libs/assets/src/cow-swap/ammslogo/sushi.png diff --git a/apps/cowswap-frontend/src/legacy/assets/cow-swap/ammslogo/swapr.png b/libs/assets/src/cow-swap/ammslogo/swapr.png similarity index 100% rename from apps/cowswap-frontend/src/legacy/assets/cow-swap/ammslogo/swapr.png rename to libs/assets/src/cow-swap/ammslogo/swapr.png diff --git a/apps/cowswap-frontend/src/legacy/assets/cow-swap/ammslogo/symmetric.png b/libs/assets/src/cow-swap/ammslogo/symmetric.png similarity index 100% rename from apps/cowswap-frontend/src/legacy/assets/cow-swap/ammslogo/symmetric.png rename to libs/assets/src/cow-swap/ammslogo/symmetric.png diff --git a/apps/cowswap-frontend/src/legacy/assets/cow-swap/ammslogo/uniswap.png b/libs/assets/src/cow-swap/ammslogo/uniswap.png similarity index 100% rename from apps/cowswap-frontend/src/legacy/assets/cow-swap/ammslogo/uniswap.png rename to libs/assets/src/cow-swap/ammslogo/uniswap.png diff --git a/apps/cowswap-frontend/src/legacy/assets/cow-swap/anniversary-icons.png b/libs/assets/src/cow-swap/anniversary-icons.png similarity index 100% rename from apps/cowswap-frontend/src/legacy/assets/cow-swap/anniversary-icons.png rename to libs/assets/src/cow-swap/anniversary-icons.png diff --git a/apps/cowswap-frontend/src/legacy/assets/cow-swap/arrow.svg b/libs/assets/src/cow-swap/arrow.svg similarity index 100% rename from apps/cowswap-frontend/src/legacy/assets/cow-swap/arrow.svg rename to libs/assets/src/cow-swap/arrow.svg diff --git a/apps/cowswap-frontend/src/legacy/assets/cow-swap/arrowDownRight.svg b/libs/assets/src/cow-swap/arrowDownRight.svg similarity index 100% rename from apps/cowswap-frontend/src/legacy/assets/cow-swap/arrowDownRight.svg rename to libs/assets/src/cow-swap/arrowDownRight.svg diff --git a/apps/cowswap-frontend/src/legacy/assets/cow-swap/attention.svg b/libs/assets/src/cow-swap/attention.svg similarity index 100% rename from apps/cowswap-frontend/src/legacy/assets/cow-swap/attention.svg rename to libs/assets/src/cow-swap/attention.svg diff --git a/apps/cowswap-frontend/src/legacy/assets/cow-swap/carret-down.svg b/libs/assets/src/cow-swap/carret-down.svg similarity index 100% rename from apps/cowswap-frontend/src/legacy/assets/cow-swap/carret-down.svg rename to libs/assets/src/cow-swap/carret-down.svg diff --git a/apps/cowswap-frontend/src/legacy/assets/cow-swap/check-singular.svg b/libs/assets/src/cow-swap/check-singular.svg similarity index 100% rename from apps/cowswap-frontend/src/legacy/assets/cow-swap/check-singular.svg rename to libs/assets/src/cow-swap/check-singular.svg diff --git a/apps/cowswap-frontend/src/legacy/assets/cow-swap/check.svg b/libs/assets/src/cow-swap/check.svg similarity index 100% rename from apps/cowswap-frontend/src/legacy/assets/cow-swap/check.svg rename to libs/assets/src/cow-swap/check.svg diff --git a/apps/cowswap-frontend/src/legacy/assets/cow-swap/checkmark.svg b/libs/assets/src/cow-swap/checkmark.svg similarity index 100% rename from apps/cowswap-frontend/src/legacy/assets/cow-swap/checkmark.svg rename to libs/assets/src/cow-swap/checkmark.svg diff --git a/apps/cowswap-frontend/src/legacy/assets/cow-swap/code.svg b/libs/assets/src/cow-swap/code.svg similarity index 100% rename from apps/cowswap-frontend/src/legacy/assets/cow-swap/code.svg rename to libs/assets/src/cow-swap/code.svg diff --git a/apps/cowswap-frontend/src/legacy/assets/cow-swap/cookie-policy.svg b/libs/assets/src/cow-swap/cookie-policy.svg similarity index 100% rename from apps/cowswap-frontend/src/legacy/assets/cow-swap/cookie-policy.svg rename to libs/assets/src/cow-swap/cookie-policy.svg diff --git a/apps/cowswap-frontend/src/legacy/assets/cow-swap/cow-404.png b/libs/assets/src/cow-swap/cow-404.png similarity index 100% rename from apps/cowswap-frontend/src/legacy/assets/cow-swap/cow-404.png rename to libs/assets/src/cow-swap/cow-404.png diff --git a/apps/cowswap-frontend/src/legacy/assets/cow-swap/cow-load.gif b/libs/assets/src/cow-swap/cow-load.gif similarity index 100% rename from apps/cowswap-frontend/src/legacy/assets/cow-swap/cow-load.gif rename to libs/assets/src/cow-swap/cow-load.gif diff --git a/apps/cowswap-frontend/src/legacy/assets/cow-swap/cow-load.webp b/libs/assets/src/cow-swap/cow-load.webp similarity index 100% rename from apps/cowswap-frontend/src/legacy/assets/cow-swap/cow-load.webp rename to libs/assets/src/cow-swap/cow-load.webp diff --git a/apps/cowswap-frontend/src/legacy/assets/cow-swap/cow-no-connection.png b/libs/assets/src/cow-swap/cow-no-connection.png similarity index 100% rename from apps/cowswap-frontend/src/legacy/assets/cow-swap/cow-no-connection.png rename to libs/assets/src/cow-swap/cow-no-connection.png diff --git a/apps/cowswap-frontend/src/legacy/assets/cow-swap/cow.svg b/libs/assets/src/cow-swap/cow.svg similarity index 100% rename from apps/cowswap-frontend/src/legacy/assets/cow-swap/cow.svg rename to libs/assets/src/cow-swap/cow.svg diff --git a/apps/cowswap-frontend/src/legacy/assets/cow-swap/cow_v2.svg b/libs/assets/src/cow-swap/cow_v2.svg similarity index 100% rename from apps/cowswap-frontend/src/legacy/assets/cow-swap/cow_v2.svg rename to libs/assets/src/cow-swap/cow_v2.svg diff --git a/apps/cowswap-frontend/src/legacy/assets/cow-swap/cowprotocol.svg b/libs/assets/src/cow-swap/cowprotocol.svg similarity index 100% rename from apps/cowswap-frontend/src/legacy/assets/cow-swap/cowprotocol.svg rename to libs/assets/src/cow-swap/cowprotocol.svg diff --git a/apps/cowswap-frontend/src/legacy/assets/cow-swap/cowswap-diagram.png b/libs/assets/src/cow-swap/cowswap-diagram.png similarity index 100% rename from apps/cowswap-frontend/src/legacy/assets/cow-swap/cowswap-diagram.png rename to libs/assets/src/cow-swap/cowswap-diagram.png diff --git a/apps/cowswap-frontend/src/legacy/assets/cow-swap/cowswap-logo.svg b/libs/assets/src/cow-swap/cowswap-logo.svg similarity index 100% rename from apps/cowswap-frontend/src/legacy/assets/cow-swap/cowswap-logo.svg rename to libs/assets/src/cow-swap/cowswap-logo.svg diff --git a/apps/cowswap-frontend/src/legacy/assets/cow-swap/cursor1.gif b/libs/assets/src/cow-swap/cursor1.gif similarity index 100% rename from apps/cowswap-frontend/src/legacy/assets/cow-swap/cursor1.gif rename to libs/assets/src/cow-swap/cursor1.gif diff --git a/apps/cowswap-frontend/src/legacy/assets/cow-swap/cursor2.gif b/libs/assets/src/cow-swap/cursor2.gif similarity index 100% rename from apps/cowswap-frontend/src/legacy/assets/cow-swap/cursor2.gif rename to libs/assets/src/cow-swap/cursor2.gif diff --git a/apps/cowswap-frontend/src/legacy/assets/cow-swap/cursor3.gif b/libs/assets/src/cow-swap/cursor3.gif similarity index 100% rename from apps/cowswap-frontend/src/legacy/assets/cow-swap/cursor3.gif rename to libs/assets/src/cow-swap/cursor3.gif diff --git a/apps/cowswap-frontend/src/legacy/assets/cow-swap/cursor4.gif b/libs/assets/src/cow-swap/cursor4.gif similarity index 100% rename from apps/cowswap-frontend/src/legacy/assets/cow-swap/cursor4.gif rename to libs/assets/src/cow-swap/cursor4.gif diff --git a/apps/cowswap-frontend/src/legacy/assets/cow-swap/discord.svg b/libs/assets/src/cow-swap/discord.svg similarity index 100% rename from apps/cowswap-frontend/src/legacy/assets/cow-swap/discord.svg rename to libs/assets/src/cow-swap/discord.svg diff --git a/apps/cowswap-frontend/src/legacy/assets/cow-swap/doc.svg b/libs/assets/src/cow-swap/doc.svg similarity index 100% rename from apps/cowswap-frontend/src/legacy/assets/cow-swap/doc.svg rename to libs/assets/src/cow-swap/doc.svg diff --git a/apps/cowswap-frontend/src/legacy/assets/cow-swap/etherscan-icon.svg b/libs/assets/src/cow-swap/etherscan-icon.svg similarity index 100% rename from apps/cowswap-frontend/src/legacy/assets/cow-swap/etherscan-icon.svg rename to libs/assets/src/cow-swap/etherscan-icon.svg diff --git a/apps/cowswap-frontend/src/legacy/assets/cow-swap/exclamation.svg b/libs/assets/src/cow-swap/exclamation.svg similarity index 100% rename from apps/cowswap-frontend/src/legacy/assets/cow-swap/exclamation.svg rename to libs/assets/src/cow-swap/exclamation.svg diff --git a/apps/cowswap-frontend/src/legacy/assets/cow-swap/experiment.svg b/libs/assets/src/cow-swap/experiment.svg similarity index 100% rename from apps/cowswap-frontend/src/legacy/assets/cow-swap/experiment.svg rename to libs/assets/src/cow-swap/experiment.svg diff --git a/apps/cowswap-frontend/src/legacy/assets/cow-swap/feedback.svg b/libs/assets/src/cow-swap/feedback.svg similarity index 100% rename from apps/cowswap-frontend/src/legacy/assets/cow-swap/feedback.svg rename to libs/assets/src/cow-swap/feedback.svg diff --git a/apps/cowswap-frontend/src/legacy/assets/cow-swap/finish.svg b/libs/assets/src/cow-swap/finish.svg similarity index 100% rename from apps/cowswap-frontend/src/legacy/assets/cow-swap/finish.svg rename to libs/assets/src/cow-swap/finish.svg diff --git a/apps/cowswap-frontend/src/legacy/assets/cow-swap/fortune-cookie.png b/libs/assets/src/cow-swap/fortune-cookie.png similarity index 100% rename from apps/cowswap-frontend/src/legacy/assets/cow-swap/fortune-cookie.png rename to libs/assets/src/cow-swap/fortune-cookie.png diff --git a/apps/cowswap-frontend/src/legacy/assets/cow-swap/game.gif b/libs/assets/src/cow-swap/game.gif similarity index 100% rename from apps/cowswap-frontend/src/legacy/assets/cow-swap/game.gif rename to libs/assets/src/cow-swap/game.gif diff --git a/apps/cowswap-frontend/src/legacy/assets/cow-swap/gasless.png b/libs/assets/src/cow-swap/gasless.png similarity index 100% rename from apps/cowswap-frontend/src/legacy/assets/cow-swap/gasless.png rename to libs/assets/src/cow-swap/gasless.png diff --git a/apps/cowswap-frontend/src/legacy/assets/cow-swap/gno.png b/libs/assets/src/cow-swap/gno.png similarity index 100% rename from apps/cowswap-frontend/src/legacy/assets/cow-swap/gno.png rename to libs/assets/src/cow-swap/gno.png diff --git a/apps/cowswap-frontend/src/legacy/assets/cow-swap/halloween-bats.svg b/libs/assets/src/cow-swap/halloween-bats.svg similarity index 100% rename from apps/cowswap-frontend/src/legacy/assets/cow-swap/halloween-bats.svg rename to libs/assets/src/cow-swap/halloween-bats.svg diff --git a/apps/cowswap-frontend/src/legacy/assets/cow-swap/halloween-spider.svg b/libs/assets/src/cow-swap/halloween-spider.svg similarity index 100% rename from apps/cowswap-frontend/src/legacy/assets/cow-swap/halloween-spider.svg rename to libs/assets/src/cow-swap/halloween-spider.svg diff --git a/apps/cowswap-frontend/src/legacy/assets/cow-swap/important.svg b/libs/assets/src/cow-swap/important.svg similarity index 100% rename from apps/cowswap-frontend/src/legacy/assets/cow-swap/important.svg rename to libs/assets/src/cow-swap/important.svg diff --git a/apps/cowswap-frontend/src/legacy/assets/cow-swap/info.svg b/libs/assets/src/cow-swap/info.svg similarity index 100% rename from apps/cowswap-frontend/src/legacy/assets/cow-swap/info.svg rename to libs/assets/src/cow-swap/info.svg diff --git a/apps/cowswap-frontend/src/legacy/assets/cow-swap/loading.svg b/libs/assets/src/cow-swap/loading.svg similarity index 100% rename from apps/cowswap-frontend/src/legacy/assets/cow-swap/loading.svg rename to libs/assets/src/cow-swap/loading.svg diff --git a/apps/cowswap-frontend/src/legacy/assets/cow-swap/meditating-cow-v2.svg b/libs/assets/src/cow-swap/meditating-cow-v2.svg similarity index 100% rename from apps/cowswap-frontend/src/legacy/assets/cow-swap/meditating-cow-v2.svg rename to libs/assets/src/cow-swap/meditating-cow-v2.svg diff --git a/apps/cowswap-frontend/src/legacy/assets/cow-swap/menu.svg b/libs/assets/src/cow-swap/menu.svg similarity index 100% rename from apps/cowswap-frontend/src/legacy/assets/cow-swap/menu.svg rename to libs/assets/src/cow-swap/menu.svg diff --git a/apps/cowswap-frontend/src/legacy/assets/cow-swap/mev.png b/libs/assets/src/cow-swap/mev.png similarity index 100% rename from apps/cowswap-frontend/src/legacy/assets/cow-swap/mev.png rename to libs/assets/src/cow-swap/mev.png diff --git a/apps/cowswap-frontend/src/legacy/assets/cow-swap/moon.svg b/libs/assets/src/cow-swap/moon.svg similarity index 100% rename from apps/cowswap-frontend/src/legacy/assets/cow-swap/moon.svg rename to libs/assets/src/cow-swap/moon.svg diff --git a/apps/cowswap-frontend/src/legacy/assets/cow-swap/network-gnosis-chain-logo.svg b/libs/assets/src/cow-swap/network-gnosis-chain-logo.svg similarity index 100% rename from apps/cowswap-frontend/src/legacy/assets/cow-swap/network-gnosis-chain-logo.svg rename to libs/assets/src/cow-swap/network-gnosis-chain-logo.svg diff --git a/apps/cowswap-frontend/src/legacy/assets/cow-swap/network-goerli-logo.svg b/libs/assets/src/cow-swap/network-goerli-logo.svg similarity index 100% rename from apps/cowswap-frontend/src/legacy/assets/cow-swap/network-goerli-logo.svg rename to libs/assets/src/cow-swap/network-goerli-logo.svg diff --git a/apps/cowswap-frontend/src/legacy/assets/cow-swap/network-mainnet-logo.svg b/libs/assets/src/cow-swap/network-mainnet-logo.svg similarity index 100% rename from apps/cowswap-frontend/src/legacy/assets/cow-swap/network-mainnet-logo.svg rename to libs/assets/src/cow-swap/network-mainnet-logo.svg diff --git a/apps/cowswap-frontend/src/legacy/assets/cow-swap/network-rinkeby-logo.svg b/libs/assets/src/cow-swap/network-rinkeby-logo.svg similarity index 100% rename from apps/cowswap-frontend/src/legacy/assets/cow-swap/network-rinkeby-logo.svg rename to libs/assets/src/cow-swap/network-rinkeby-logo.svg diff --git a/apps/cowswap-frontend/src/legacy/assets/cow-swap/ninja-cow.png b/libs/assets/src/cow-swap/ninja-cow.png similarity index 100% rename from apps/cowswap-frontend/src/legacy/assets/cow-swap/ninja-cow.png rename to libs/assets/src/cow-swap/ninja-cow.png diff --git a/apps/cowswap-frontend/src/legacy/assets/cow-swap/order-cancelled.svg b/libs/assets/src/cow-swap/order-cancelled.svg similarity index 100% rename from apps/cowswap-frontend/src/legacy/assets/cow-swap/order-cancelled.svg rename to libs/assets/src/cow-swap/order-cancelled.svg diff --git a/apps/cowswap-frontend/src/legacy/assets/cow-swap/order-check.svg b/libs/assets/src/cow-swap/order-check.svg similarity index 100% rename from apps/cowswap-frontend/src/legacy/assets/cow-swap/order-check.svg rename to libs/assets/src/cow-swap/order-check.svg diff --git a/apps/cowswap-frontend/src/legacy/assets/cow-swap/order-cross.svg b/libs/assets/src/cow-swap/order-cross.svg similarity index 100% rename from apps/cowswap-frontend/src/legacy/assets/cow-swap/order-cross.svg rename to libs/assets/src/cow-swap/order-cross.svg diff --git a/apps/cowswap-frontend/src/legacy/assets/cow-swap/order-expired.svg b/libs/assets/src/cow-swap/order-expired.svg similarity index 100% rename from apps/cowswap-frontend/src/legacy/assets/cow-swap/order-expired.svg rename to libs/assets/src/cow-swap/order-expired.svg diff --git a/apps/cowswap-frontend/src/legacy/assets/cow-swap/order-open.svg b/libs/assets/src/cow-swap/order-open.svg similarity index 100% rename from apps/cowswap-frontend/src/legacy/assets/cow-swap/order-open.svg rename to libs/assets/src/cow-swap/order-open.svg diff --git a/apps/cowswap-frontend/src/legacy/assets/cow-swap/order-presignature-pending.svg b/libs/assets/src/cow-swap/order-presignature-pending.svg similarity index 100% rename from apps/cowswap-frontend/src/legacy/assets/cow-swap/order-presignature-pending.svg rename to libs/assets/src/cow-swap/order-presignature-pending.svg diff --git a/apps/cowswap-frontend/src/legacy/assets/cow-swap/orderExecution.svg b/libs/assets/src/cow-swap/orderExecution.svg similarity index 100% rename from apps/cowswap-frontend/src/legacy/assets/cow-swap/orderExecution.svg rename to libs/assets/src/cow-swap/orderExecution.svg diff --git a/apps/cowswap-frontend/src/legacy/assets/cow-swap/pie.svg b/libs/assets/src/cow-swap/pie.svg similarity index 100% rename from apps/cowswap-frontend/src/legacy/assets/cow-swap/pie.svg rename to libs/assets/src/cow-swap/pie.svg diff --git a/apps/cowswap-frontend/src/legacy/assets/cow-swap/plus.svg b/libs/assets/src/cow-swap/plus.svg similarity index 100% rename from apps/cowswap-frontend/src/legacy/assets/cow-swap/plus.svg rename to libs/assets/src/cow-swap/plus.svg diff --git a/apps/cowswap-frontend/src/legacy/assets/cow-swap/privacy-policy.svg b/libs/assets/src/cow-swap/privacy-policy.svg similarity index 100% rename from apps/cowswap-frontend/src/legacy/assets/cow-swap/privacy-policy.svg rename to libs/assets/src/cow-swap/privacy-policy.svg diff --git a/apps/cowswap-frontend/src/legacy/assets/cow-swap/protection.svg b/libs/assets/src/cow-swap/protection.svg similarity index 100% rename from apps/cowswap-frontend/src/legacy/assets/cow-swap/protection.svg rename to libs/assets/src/cow-swap/protection.svg diff --git a/apps/cowswap-frontend/src/legacy/assets/cow-swap/question.ts b/libs/assets/src/cow-swap/question.ts similarity index 100% rename from apps/cowswap-frontend/src/legacy/assets/cow-swap/question.ts rename to libs/assets/src/cow-swap/question.ts diff --git a/apps/cowswap-frontend/src/legacy/assets/cow-swap/refund.svg b/libs/assets/src/cow-swap/refund.svg similarity index 100% rename from apps/cowswap-frontend/src/legacy/assets/cow-swap/refund.svg rename to libs/assets/src/cow-swap/refund.svg diff --git a/apps/cowswap-frontend/src/legacy/assets/cow-swap/round-arrow.svg b/libs/assets/src/cow-swap/round-arrow.svg similarity index 100% rename from apps/cowswap-frontend/src/legacy/assets/cow-swap/round-arrow.svg rename to libs/assets/src/cow-swap/round-arrow.svg diff --git a/apps/cowswap-frontend/src/modules/wallet/api/assets/safe-logo.svg b/libs/assets/src/cow-swap/safe-logo.svg similarity index 100% rename from apps/cowswap-frontend/src/modules/wallet/api/assets/safe-logo.svg rename to libs/assets/src/cow-swap/safe-logo.svg diff --git a/apps/cowswap-frontend/src/legacy/assets/cow-swap/savings.svg b/libs/assets/src/cow-swap/savings.svg similarity index 100% rename from apps/cowswap-frontend/src/legacy/assets/cow-swap/savings.svg rename to libs/assets/src/cow-swap/savings.svg diff --git a/apps/cowswap-frontend/src/legacy/assets/cow-swap/send.svg b/libs/assets/src/cow-swap/send.svg similarity index 100% rename from apps/cowswap-frontend/src/legacy/assets/cow-swap/send.svg rename to libs/assets/src/cow-swap/send.svg diff --git a/apps/cowswap-frontend/src/legacy/assets/cow-swap/sun.svg b/libs/assets/src/cow-swap/sun.svg similarity index 100% rename from apps/cowswap-frontend/src/legacy/assets/cow-swap/sun.svg rename to libs/assets/src/cow-swap/sun.svg diff --git a/apps/cowswap-frontend/src/legacy/assets/cow-swap/surplus-cow.svg b/libs/assets/src/cow-swap/surplus-cow.svg similarity index 100% rename from apps/cowswap-frontend/src/legacy/assets/cow-swap/surplus-cow.svg rename to libs/assets/src/cow-swap/surplus-cow.svg diff --git a/apps/cowswap-frontend/src/legacy/assets/cow-swap/terms-and-conditions.svg b/libs/assets/src/cow-swap/terms-and-conditions.svg similarity index 100% rename from apps/cowswap-frontend/src/legacy/assets/cow-swap/terms-and-conditions.svg rename to libs/assets/src/cow-swap/terms-and-conditions.svg diff --git a/apps/cowswap-frontend/src/legacy/assets/cow-swap/transaction-arrows.svg b/libs/assets/src/cow-swap/transaction-arrows.svg similarity index 100% rename from apps/cowswap-frontend/src/legacy/assets/cow-swap/transaction-arrows.svg rename to libs/assets/src/cow-swap/transaction-arrows.svg diff --git a/apps/cowswap-frontend/src/legacy/assets/cow-swap/transaction-confirmed.svg b/libs/assets/src/cow-swap/transaction-confirmed.svg similarity index 100% rename from apps/cowswap-frontend/src/legacy/assets/cow-swap/transaction-confirmed.svg rename to libs/assets/src/cow-swap/transaction-confirmed.svg diff --git a/apps/cowswap-frontend/src/legacy/assets/cow-swap/twitter.svg b/libs/assets/src/cow-swap/twitter.svg similarity index 100% rename from apps/cowswap-frontend/src/legacy/assets/cow-swap/twitter.svg rename to libs/assets/src/cow-swap/twitter.svg diff --git a/apps/cowswap-frontend/src/legacy/assets/cow-swap/usdc.png b/libs/assets/src/cow-swap/usdc.png similarity index 100% rename from apps/cowswap-frontend/src/legacy/assets/cow-swap/usdc.png rename to libs/assets/src/cow-swap/usdc.png diff --git a/apps/cowswap-frontend/src/legacy/assets/cow-swap/vCOW.png b/libs/assets/src/cow-swap/vCOW.png similarity index 100% rename from apps/cowswap-frontend/src/legacy/assets/cow-swap/vCOW.png rename to libs/assets/src/cow-swap/vCOW.png diff --git a/apps/cowswap-frontend/src/legacy/assets/cow-swap/wallet-plus.svg b/libs/assets/src/cow-swap/wallet-plus.svg similarity index 100% rename from apps/cowswap-frontend/src/legacy/assets/cow-swap/wallet-plus.svg rename to libs/assets/src/cow-swap/wallet-plus.svg diff --git a/apps/cowswap-frontend/src/legacy/assets/cow-swap/wxdai.png b/libs/assets/src/cow-swap/wxdai.png similarity index 100% rename from apps/cowswap-frontend/src/legacy/assets/cow-swap/wxdai.png rename to libs/assets/src/cow-swap/wxdai.png diff --git a/apps/cowswap-frontend/src/legacy/assets/cow-swap/x.svg b/libs/assets/src/cow-swap/x.svg similarity index 100% rename from apps/cowswap-frontend/src/legacy/assets/cow-swap/x.svg rename to libs/assets/src/cow-swap/x.svg diff --git a/apps/cowswap-frontend/src/legacy/assets/cow-swap/xdai.png b/libs/assets/src/cow-swap/xdai.png similarity index 100% rename from apps/cowswap-frontend/src/legacy/assets/cow-swap/xdai.png rename to libs/assets/src/cow-swap/xdai.png diff --git a/apps/cowswap-frontend/src/legacy/assets/images/amms-graph-gc.svg b/libs/assets/src/images/amms-graph-gc.svg similarity index 100% rename from apps/cowswap-frontend/src/legacy/assets/images/amms-graph-gc.svg rename to libs/assets/src/images/amms-graph-gc.svg diff --git a/apps/cowswap-frontend/src/legacy/assets/images/amms-graph.svg b/libs/assets/src/images/amms-graph.svg similarity index 100% rename from apps/cowswap-frontend/src/legacy/assets/images/amms-graph.svg rename to libs/assets/src/images/amms-graph.svg diff --git a/apps/cowswap-frontend/src/legacy/assets/images/arrow-down-blue.svg b/libs/assets/src/images/arrow-down-blue.svg similarity index 100% rename from apps/cowswap-frontend/src/legacy/assets/images/arrow-down-blue.svg rename to libs/assets/src/images/arrow-down-blue.svg diff --git a/libs/assets/src/images/arrow-down-grey.svg b/libs/assets/src/images/arrow-down-grey.svg new file mode 100644 index 0000000000..de465dc630 --- /dev/null +++ b/libs/assets/src/images/arrow-down-grey.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/apps/cowswap-frontend/src/legacy/assets/images/big_unicorn.png b/libs/assets/src/images/big_unicorn.png similarity index 100% rename from apps/cowswap-frontend/src/legacy/assets/images/big_unicorn.png rename to libs/assets/src/images/big_unicorn.png diff --git a/apps/cowswap-frontend/src/legacy/assets/images/blue-loader.svg b/libs/assets/src/images/blue-loader.svg similarity index 100% rename from apps/cowswap-frontend/src/legacy/assets/images/blue-loader.svg rename to libs/assets/src/images/blue-loader.svg diff --git a/apps/cowswap-frontend/src/legacy/assets/images/circle-grey.svg b/libs/assets/src/images/circle-grey.svg similarity index 100% rename from apps/cowswap-frontend/src/legacy/assets/images/circle-grey.svg rename to libs/assets/src/images/circle-grey.svg diff --git a/apps/cowswap-frontend/src/legacy/assets/images/circle.svg b/libs/assets/src/images/circle.svg similarity index 100% rename from apps/cowswap-frontend/src/legacy/assets/images/circle.svg rename to libs/assets/src/images/circle.svg diff --git a/apps/cowswap-frontend/src/legacy/assets/images/cow-graph.svg b/libs/assets/src/images/cow-graph.svg similarity index 100% rename from apps/cowswap-frontend/src/legacy/assets/images/cow-graph.svg rename to libs/assets/src/images/cow-graph.svg diff --git a/apps/cowswap-frontend/src/legacy/assets/images/cow-meditating-smoooth.svg b/libs/assets/src/images/cow-meditating-smoooth.svg similarity index 100% rename from apps/cowswap-frontend/src/legacy/assets/images/cow-meditating-smoooth.svg rename to libs/assets/src/images/cow-meditating-smoooth.svg diff --git a/apps/cowswap-frontend/src/legacy/assets/images/cow-meditating.svg b/libs/assets/src/images/cow-meditating.svg similarity index 100% rename from apps/cowswap-frontend/src/legacy/assets/images/cow-meditating.svg rename to libs/assets/src/images/cow-meditating.svg diff --git a/apps/cowswap-frontend/src/legacy/assets/images/dropdown-blue.svg b/libs/assets/src/images/dropdown-blue.svg similarity index 100% rename from apps/cowswap-frontend/src/legacy/assets/images/dropdown-blue.svg rename to libs/assets/src/images/dropdown-blue.svg diff --git a/apps/cowswap-frontend/src/legacy/assets/images/dropdown.svg b/libs/assets/src/images/dropdown.svg similarity index 100% rename from apps/cowswap-frontend/src/legacy/assets/images/dropdown.svg rename to libs/assets/src/images/dropdown.svg diff --git a/apps/cowswap-frontend/src/legacy/assets/images/dropup-blue.svg b/libs/assets/src/images/dropup-blue.svg similarity index 100% rename from apps/cowswap-frontend/src/legacy/assets/images/dropup-blue.svg rename to libs/assets/src/images/dropup-blue.svg diff --git a/apps/cowswap-frontend/src/legacy/assets/images/ethereum-logo.png b/libs/assets/src/images/ethereum-logo.png similarity index 100% rename from apps/cowswap-frontend/src/legacy/assets/images/ethereum-logo.png rename to libs/assets/src/images/ethereum-logo.png diff --git a/apps/cowswap-frontend/src/legacy/assets/images/gas-icon.svg b/libs/assets/src/images/gas-icon.svg similarity index 100% rename from apps/cowswap-frontend/src/legacy/assets/images/gas-icon.svg rename to libs/assets/src/images/gas-icon.svg diff --git a/apps/cowswap-frontend/src/legacy/assets/images/link.svg b/libs/assets/src/images/link.svg similarity index 100% rename from apps/cowswap-frontend/src/legacy/assets/images/link.svg rename to libs/assets/src/images/link.svg diff --git a/apps/cowswap-frontend/src/legacy/assets/images/magnifying-glass.svg b/libs/assets/src/images/magnifying-glass.svg similarity index 100% rename from apps/cowswap-frontend/src/legacy/assets/images/magnifying-glass.svg rename to libs/assets/src/images/magnifying-glass.svg diff --git a/apps/cowswap-frontend/src/legacy/assets/images/menu.svg b/libs/assets/src/images/menu.svg similarity index 100% rename from apps/cowswap-frontend/src/legacy/assets/images/menu.svg rename to libs/assets/src/images/menu.svg diff --git a/apps/cowswap-frontend/src/legacy/assets/images/noise.png b/libs/assets/src/images/noise.png similarity index 100% rename from apps/cowswap-frontend/src/legacy/assets/images/noise.png rename to libs/assets/src/images/noise.png diff --git a/apps/cowswap-frontend/src/legacy/assets/images/plus-blue.svg b/libs/assets/src/images/plus-blue.svg similarity index 100% rename from apps/cowswap-frontend/src/legacy/assets/images/plus-blue.svg rename to libs/assets/src/images/plus-blue.svg diff --git a/apps/cowswap-frontend/src/legacy/assets/images/plus-grey.svg b/libs/assets/src/images/plus-grey.svg similarity index 100% rename from apps/cowswap-frontend/src/legacy/assets/images/plus-grey.svg rename to libs/assets/src/images/plus-grey.svg diff --git a/apps/cowswap-frontend/src/legacy/assets/images/portisIcon.png b/libs/assets/src/images/portisIcon.png similarity index 100% rename from apps/cowswap-frontend/src/legacy/assets/images/portisIcon.png rename to libs/assets/src/images/portisIcon.png diff --git a/apps/cowswap-frontend/src/legacy/assets/images/question-mark.svg b/libs/assets/src/images/question-mark.svg similarity index 100% rename from apps/cowswap-frontend/src/legacy/assets/images/question-mark.svg rename to libs/assets/src/images/question-mark.svg diff --git a/apps/cowswap-frontend/src/legacy/assets/images/question.svg b/libs/assets/src/images/question.svg similarity index 100% rename from apps/cowswap-frontend/src/legacy/assets/images/question.svg rename to libs/assets/src/images/question.svg diff --git a/apps/cowswap-frontend/src/legacy/assets/images/router-icon-grey.svg b/libs/assets/src/images/router-icon-grey.svg similarity index 100% rename from apps/cowswap-frontend/src/legacy/assets/images/router-icon-grey.svg rename to libs/assets/src/images/router-icon-grey.svg diff --git a/apps/cowswap-frontend/src/legacy/assets/images/sandtexture.webp b/libs/assets/src/images/sandtexture.webp similarity index 100% rename from apps/cowswap-frontend/src/legacy/assets/images/sandtexture.webp rename to libs/assets/src/images/sandtexture.webp diff --git a/apps/cowswap-frontend/src/legacy/assets/images/santa-hat.png b/libs/assets/src/images/santa-hat.png similarity index 100% rename from apps/cowswap-frontend/src/legacy/assets/images/santa-hat.png rename to libs/assets/src/images/santa-hat.png diff --git a/apps/cowswap-frontend/src/legacy/assets/images/spinner.svg b/libs/assets/src/images/spinner.svg similarity index 100% rename from apps/cowswap-frontend/src/legacy/assets/images/spinner.svg rename to libs/assets/src/images/spinner.svg diff --git a/apps/cowswap-frontend/src/legacy/assets/images/squiggle.png b/libs/assets/src/images/squiggle.png similarity index 100% rename from apps/cowswap-frontend/src/legacy/assets/images/squiggle.png rename to libs/assets/src/images/squiggle.png diff --git a/apps/cowswap-frontend/src/legacy/assets/images/survey-orb.svg b/libs/assets/src/images/survey-orb.svg similarity index 100% rename from apps/cowswap-frontend/src/legacy/assets/images/survey-orb.svg rename to libs/assets/src/images/survey-orb.svg diff --git a/apps/cowswap-frontend/src/legacy/assets/images/token-list-logo.png b/libs/assets/src/images/token-list-logo.png similarity index 100% rename from apps/cowswap-frontend/src/legacy/assets/images/token-list-logo.png rename to libs/assets/src/images/token-list-logo.png diff --git a/apps/cowswap-frontend/src/legacy/assets/images/token-list/lists-dark.png b/libs/assets/src/images/token-list/lists-dark.png similarity index 100% rename from apps/cowswap-frontend/src/legacy/assets/images/token-list/lists-dark.png rename to libs/assets/src/images/token-list/lists-dark.png diff --git a/apps/cowswap-frontend/src/legacy/assets/images/token-list/lists-light.png b/libs/assets/src/images/token-list/lists-light.png similarity index 100% rename from apps/cowswap-frontend/src/legacy/assets/images/token-list/lists-light.png rename to libs/assets/src/images/token-list/lists-light.png diff --git a/apps/cowswap-frontend/src/legacy/assets/images/token-logo.png b/libs/assets/src/images/token-logo.png similarity index 100% rename from apps/cowswap-frontend/src/legacy/assets/images/token-logo.png rename to libs/assets/src/images/token-logo.png diff --git a/apps/cowswap-frontend/src/legacy/assets/images/tokenlistsgrouped.png b/libs/assets/src/images/tokenlistsgrouped.png similarity index 100% rename from apps/cowswap-frontend/src/legacy/assets/images/tokenlistsgrouped.png rename to libs/assets/src/images/tokenlistsgrouped.png diff --git a/apps/cowswap-frontend/src/legacy/assets/images/trustWallet.png b/libs/assets/src/images/trustWallet.png similarity index 100% rename from apps/cowswap-frontend/src/legacy/assets/images/trustWallet.png rename to libs/assets/src/images/trustWallet.png diff --git a/apps/cowswap-frontend/src/legacy/assets/images/ukraine.png b/libs/assets/src/images/ukraine.png similarity index 100% rename from apps/cowswap-frontend/src/legacy/assets/images/ukraine.png rename to libs/assets/src/images/ukraine.png diff --git a/apps/cowswap-frontend/src/legacy/assets/images/widget-screenshot.png b/libs/assets/src/images/widget-screenshot.png similarity index 100% rename from apps/cowswap-frontend/src/legacy/assets/images/widget-screenshot.png rename to libs/assets/src/images/widget-screenshot.png diff --git a/libs/assets/src/images/x.svg b/libs/assets/src/images/x.svg new file mode 100644 index 0000000000..1345e9bcea --- /dev/null +++ b/libs/assets/src/images/x.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/apps/cowswap-frontend/src/legacy/assets/images/xl_uni.png b/libs/assets/src/images/xl_uni.png similarity index 100% rename from apps/cowswap-frontend/src/legacy/assets/images/xl_uni.png rename to libs/assets/src/images/xl_uni.png diff --git a/libs/assets/src/index.ts b/libs/assets/src/index.ts new file mode 100644 index 0000000000..e69de29bb2 diff --git a/apps/cowswap-frontend/src/legacy/assets/styles/styled.ts b/libs/assets/src/styles/styled.ts similarity index 93% rename from apps/cowswap-frontend/src/legacy/assets/styles/styled.ts rename to libs/assets/src/styles/styled.ts index ac5a1d2343..24e3d25d78 100644 --- a/apps/cowswap-frontend/src/legacy/assets/styles/styled.ts +++ b/libs/assets/src/styles/styled.ts @@ -14,6 +14,6 @@ export const Txt = styled.span<{ font-size: ${({ fontSize }) => `${fontSize ? fontSize : 12}px`}; font-weight: ${({ fontWeight }) => (fontWeight ? fontWeight : 'normal')}; line-height: ${({ lineHeight }) => (lineHeight ? `${lineHeight}px` : 1.2)}; - color: ${({ theme }) => theme.text1}; + color: var(--cow-color-text1); gap: ${({ gap }) => (gap ? `${gap}px` : 0)}; ` diff --git a/apps/cowswap-frontend/src/legacy/assets/svg/QR.svg b/libs/assets/src/svg/QR.svg similarity index 100% rename from apps/cowswap-frontend/src/legacy/assets/svg/QR.svg rename to libs/assets/src/svg/QR.svg diff --git a/apps/cowswap-frontend/src/legacy/assets/svg/arbitrum_logo.svg b/libs/assets/src/svg/arbitrum_logo.svg similarity index 100% rename from apps/cowswap-frontend/src/legacy/assets/svg/arbitrum_logo.svg rename to libs/assets/src/svg/arbitrum_logo.svg diff --git a/apps/cowswap-frontend/src/legacy/assets/svg/celo_logo.svg b/libs/assets/src/svg/celo_logo.svg similarity index 100% rename from apps/cowswap-frontend/src/legacy/assets/svg/celo_logo.svg rename to libs/assets/src/svg/celo_logo.svg diff --git a/apps/cowswap-frontend/src/legacy/assets/svg/dot_line.svg b/libs/assets/src/svg/dot_line.svg similarity index 100% rename from apps/cowswap-frontend/src/legacy/assets/svg/dot_line.svg rename to libs/assets/src/svg/dot_line.svg diff --git a/apps/cowswap-frontend/src/legacy/assets/svg/lightcircle.svg b/libs/assets/src/svg/lightcircle.svg similarity index 100% rename from apps/cowswap-frontend/src/legacy/assets/svg/lightcircle.svg rename to libs/assets/src/svg/lightcircle.svg diff --git a/apps/cowswap-frontend/src/legacy/assets/svg/logo.svg b/libs/assets/src/svg/logo.svg similarity index 99% rename from apps/cowswap-frontend/src/legacy/assets/svg/logo.svg rename to libs/assets/src/svg/logo.svg index d93197e48b..46a1821920 100644 --- a/apps/cowswap-frontend/src/legacy/assets/svg/logo.svg +++ b/libs/assets/src/svg/logo.svg @@ -10,4 +10,5 @@ + diff --git a/apps/cowswap-frontend/src/legacy/assets/svg/logo_pink.svg b/libs/assets/src/svg/logo_pink.svg similarity index 100% rename from apps/cowswap-frontend/src/legacy/assets/svg/logo_pink.svg rename to libs/assets/src/svg/logo_pink.svg diff --git a/apps/cowswap-frontend/src/legacy/assets/svg/matic-token-icon.svg b/libs/assets/src/svg/matic-token-icon.svg similarity index 100% rename from apps/cowswap-frontend/src/legacy/assets/svg/matic-token-icon.svg rename to libs/assets/src/svg/matic-token-icon.svg diff --git a/apps/cowswap-frontend/src/legacy/assets/svg/optimism_logo.svg b/libs/assets/src/svg/optimism_logo.svg similarity index 100% rename from apps/cowswap-frontend/src/legacy/assets/svg/optimism_logo.svg rename to libs/assets/src/svg/optimism_logo.svg diff --git a/apps/cowswap-frontend/src/legacy/assets/svg/optimistic_ethereum.svg b/libs/assets/src/svg/optimistic_ethereum.svg similarity index 100% rename from apps/cowswap-frontend/src/legacy/assets/svg/optimistic_ethereum.svg rename to libs/assets/src/svg/optimistic_ethereum.svg diff --git a/apps/cowswap-frontend/src/legacy/assets/svg/polygon-matic-logo.svg b/libs/assets/src/svg/polygon-matic-logo.svg similarity index 100% rename from apps/cowswap-frontend/src/legacy/assets/svg/polygon-matic-logo.svg rename to libs/assets/src/svg/polygon-matic-logo.svg diff --git a/apps/cowswap-frontend/src/legacy/assets/svg/question.svg b/libs/assets/src/svg/question.svg similarity index 100% rename from apps/cowswap-frontend/src/legacy/assets/svg/question.svg rename to libs/assets/src/svg/question.svg diff --git a/apps/cowswap-frontend/src/legacy/assets/svg/static_route.svg b/libs/assets/src/svg/static_route.svg similarity index 100% rename from apps/cowswap-frontend/src/legacy/assets/svg/static_route.svg rename to libs/assets/src/svg/static_route.svg diff --git a/apps/cowswap-frontend/src/legacy/assets/svg/switch.svg b/libs/assets/src/svg/switch.svg similarity index 100% rename from apps/cowswap-frontend/src/legacy/assets/svg/switch.svg rename to libs/assets/src/svg/switch.svg diff --git a/apps/cowswap-frontend/src/legacy/assets/svg/tokenlist.svg b/libs/assets/src/svg/tokenlist.svg similarity index 100% rename from apps/cowswap-frontend/src/legacy/assets/svg/tokenlist.svg rename to libs/assets/src/svg/tokenlist.svg diff --git a/apps/cowswap-frontend/src/legacy/assets/svg/wordmark.svg b/libs/assets/src/svg/wordmark.svg similarity index 100% rename from apps/cowswap-frontend/src/legacy/assets/svg/wordmark.svg rename to libs/assets/src/svg/wordmark.svg diff --git a/apps/cowswap-frontend/src/legacy/assets/svg/wordmark_pink.svg b/libs/assets/src/svg/wordmark_pink.svg similarity index 100% rename from apps/cowswap-frontend/src/legacy/assets/svg/wordmark_pink.svg rename to libs/assets/src/svg/wordmark_pink.svg diff --git a/apps/cowswap-frontend/src/legacy/assets/svg/wordmark_white.svg b/libs/assets/src/svg/wordmark_white.svg similarity index 100% rename from apps/cowswap-frontend/src/legacy/assets/svg/wordmark_white.svg rename to libs/assets/src/svg/wordmark_white.svg diff --git a/libs/assets/tsconfig.json b/libs/assets/tsconfig.json new file mode 100644 index 0000000000..bab74ff2e6 --- /dev/null +++ b/libs/assets/tsconfig.json @@ -0,0 +1,21 @@ +{ + "compilerOptions": { + "jsx": "react-jsx", + "allowJs": false, + "esModuleInterop": false, + "allowSyntheticDefaultImports": true, + "strict": true, + "types": ["vite/client"] + }, + "files": [], + "include": [], + "references": [ + { + "path": "./tsconfig.lib.json" + }, + { + "path": "./tsconfig.spec.json" + } + ], + "extends": "../../tsconfig.base.json" +} diff --git a/libs/assets/tsconfig.lib.json b/libs/assets/tsconfig.lib.json new file mode 100644 index 0000000000..1b2b0c12df --- /dev/null +++ b/libs/assets/tsconfig.lib.json @@ -0,0 +1,19 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "../../dist/out-tsc", + "types": ["node", "vite/client"] + }, + "files": ["../../node_modules/@nx/react/typings/cssmodule.d.ts", "../../node_modules/@nx/react/typings/image.d.ts"], + "exclude": [ + "**/*.spec.ts", + "**/*.test.ts", + "**/*.spec.tsx", + "**/*.test.tsx", + "**/*.spec.js", + "**/*.test.js", + "**/*.spec.jsx", + "**/*.test.jsx" + ], + "include": ["**/*.js", "**/*.jsx", "**/*.ts", "**/*.tsx"] +} diff --git a/libs/assets/tsconfig.spec.json b/libs/assets/tsconfig.spec.json new file mode 100644 index 0000000000..26ef046ac5 --- /dev/null +++ b/libs/assets/tsconfig.spec.json @@ -0,0 +1,20 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "../../dist/out-tsc", + "module": "commonjs", + "types": ["jest", "node"] + }, + "include": [ + "jest.config.ts", + "src/**/*.test.ts", + "src/**/*.spec.ts", + "src/**/*.test.tsx", + "src/**/*.spec.tsx", + "src/**/*.test.js", + "src/**/*.spec.js", + "src/**/*.test.jsx", + "src/**/*.spec.jsx", + "src/**/*.d.ts" + ] +} diff --git a/libs/assets/vite.config.ts b/libs/assets/vite.config.ts new file mode 100644 index 0000000000..f4563c5110 --- /dev/null +++ b/libs/assets/vite.config.ts @@ -0,0 +1,49 @@ +/// +import { defineConfig } from 'vite' +import react from '@vitejs/plugin-react-swc' +import viteTsConfigPaths from 'vite-tsconfig-paths' +import dts from 'vite-plugin-dts' +import * as path from 'path' + +export default defineConfig({ + cacheDir: '../../node_modules/.vite/assets', + + plugins: [ + dts({ + entryRoot: 'src', + tsConfigFilePath: path.join(__dirname, 'tsconfig.lib.json'), + skipDiagnostics: true, + }), + react(), + viteTsConfigPaths({ + root: '../../', + }), + ], + + // Uncomment this if you are using workers. + // worker: { + // plugins: [ + // viteTsConfigPaths({ + // root: '../../', + // }), + // ], + // }, + + // Configuration for building your library. + // See: https://vitejs.dev/guide/build.html#library-mode + build: { + lib: { + // Could also be a dictionary or array of multiple entry points. + entry: 'src/index.ts', + name: 'assets', + fileName: 'index', + // Change this to the formats you want to support. + // Don't forget to update your package.json as well. + formats: ['es', 'cjs'], + }, + rollupOptions: { + // External packages that should not be bundled into your library. + external: ['react', 'react-dom', 'react/jsx-runtime'], + }, + }, +}) diff --git a/libs/common-const/.babelrc b/libs/common-const/.babelrc new file mode 100644 index 0000000000..ef4889c1ab --- /dev/null +++ b/libs/common-const/.babelrc @@ -0,0 +1,20 @@ +{ + "presets": [ + [ + "@nx/react/babel", + { + "runtime": "automatic", + "useBuiltIns": "usage" + } + ] + ], + "plugins": [ + [ + "styled-components", + { + "pure": true, + "ssr": true + } + ] + ] +} diff --git a/libs/common-const/.eslintrc.json b/libs/common-const/.eslintrc.json new file mode 100644 index 0000000000..a39ac5d057 --- /dev/null +++ b/libs/common-const/.eslintrc.json @@ -0,0 +1,18 @@ +{ + "extends": ["plugin:@nx/react", "../../.eslintrc.json"], + "ignorePatterns": ["!**/*"], + "overrides": [ + { + "files": ["*.ts", "*.tsx", "*.js", "*.jsx"], + "rules": {} + }, + { + "files": ["*.ts", "*.tsx"], + "rules": {} + }, + { + "files": ["*.js", "*.jsx"], + "rules": {} + } + ] +} diff --git a/libs/common-const/README.md b/libs/common-const/README.md new file mode 100644 index 0000000000..01bdccc346 --- /dev/null +++ b/libs/common-const/README.md @@ -0,0 +1 @@ +# Common const diff --git a/libs/common-const/jest.config.ts b/libs/common-const/jest.config.ts new file mode 100644 index 0000000000..96c3ce6fcd --- /dev/null +++ b/libs/common-const/jest.config.ts @@ -0,0 +1,11 @@ +/* eslint-disable */ +export default { + displayName: 'common-const', + preset: '../../jest.preset.js', + transform: { + '^(?!.*\\.(js|jsx|ts|tsx|css|json)$)': '@nx/react/plugins/jest', + '^.+\\.[tj]sx?$': ['babel-jest', { presets: ['@nx/react/babel'] }], + }, + moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx'], + coverageDirectory: '../../coverage/libs/common-const', +} diff --git a/libs/common-const/package.json b/libs/common-const/package.json new file mode 100644 index 0000000000..a4d54a4f13 --- /dev/null +++ b/libs/common-const/package.json @@ -0,0 +1,12 @@ +{ + "name": "@cowprotocol/common-const", + "version": "0.0.1", + "main": "./index.js", + "types": "./index.d.ts", + "exports": { + ".": { + "import": "./index.mjs", + "require": "./index.js" + } + } +} diff --git a/libs/common-const/project.json b/libs/common-const/project.json new file mode 100644 index 0000000000..ab3b759bb3 --- /dev/null +++ b/libs/common-const/project.json @@ -0,0 +1,46 @@ +{ + "name": "@cowprotocol/common-const", + "$schema": "../../node_modules/nx/schemas/project-schema.json", + "sourceRoot": "libs/common-const/src", + "projectType": "library", + "tags": [], + "targets": { + "lint": { + "executor": "@nx/linter:eslint", + "outputs": ["{options.outputFile}"], + "options": { + "lintFilePatterns": ["libs/common-const/**/*.{ts,tsx,js,jsx}"] + } + }, + "build": { + "executor": "@nx/vite:build", + "outputs": ["{options.outputPath}"], + "defaultConfiguration": "production", + "options": { + "outputPath": "dist/libs/common-const" + }, + "configurations": { + "development": { + "mode": "development" + }, + "production": { + "mode": "production" + } + } + }, + "test": { + "executor": "@nx/jest:jest", + "outputs": ["{workspaceRoot}/coverage/{projectRoot}"], + "options": { + "jestConfig": "libs/common-const/jest.config.ts", + "passWithNoTests": true + }, + "configurations": { + "ci": { + "ci": true, + "codeCoverage": true + } + } + } + } +} diff --git a/apps/cowswap-frontend/src/legacy/constants/addresses.ts b/libs/common-const/src/addresses.ts similarity index 63% rename from apps/cowswap-frontend/src/legacy/constants/addresses.ts rename to libs/common-const/src/addresses.ts index 0400a3672d..8857ca62c6 100644 --- a/apps/cowswap-frontend/src/legacy/constants/addresses.ts +++ b/libs/common-const/src/addresses.ts @@ -1,9 +1,19 @@ import { SupportedChainId } from '@cowprotocol/cow-sdk' -import { constructSameAddressMap } from '../utils/constructSameAddressMap' - export type AddressMap = { [chainId: number]: string } +const DEFAULT_NETWORKS = [SupportedChainId.MAINNET, SupportedChainId.GOERLI] + +function constructSameAddressMap( + address: T, + additionalNetworks: SupportedChainId[] = [] +): { [chainId: number]: T } { + return DEFAULT_NETWORKS.concat(additionalNetworks).reduce<{ [chainId: number]: T }>((memo, chainId) => { + memo[chainId] = address + return memo + }, {}) +} + export const MULTICALL_ADDRESS: AddressMap = { ...constructSameAddressMap('0x1F98415757620B543A52E61c46B32eB19261F984', []), [SupportedChainId.GNOSIS_CHAIN]: '0x0f41c16b8ad27c11f181eca85f0941868c1297af', diff --git a/apps/cowswap-frontend/src/legacy/constants/chainInfo.ts b/libs/common-const/src/chainInfo.ts similarity index 89% rename from apps/cowswap-frontend/src/legacy/constants/chainInfo.ts rename to libs/common-const/src/chainInfo.ts index 4c8d873581..f43a04c165 100644 --- a/apps/cowswap-frontend/src/legacy/constants/chainInfo.ts +++ b/libs/common-const/src/chainInfo.ts @@ -1,8 +1,8 @@ import { SupportedChainId } from '@cowprotocol/cow-sdk' -import GnosisChainLogo from 'legacy/assets/cow-swap/network-gnosis-chain-logo.svg' -import GoerliLogo from 'legacy/assets/cow-swap/network-goerli-logo.svg' -import EthereumLogo from 'legacy/assets/cow-swap/network-mainnet-logo.svg' +import GnosisChainLogo from '@cowprotocol/assets/cow-swap/network-gnosis-chain-logo.svg' +import GoerliLogo from '@cowprotocol/assets/cow-swap/network-goerli-logo.svg' +import EthereumLogo from '@cowprotocol/assets/cow-swap/network-mainnet-logo.svg' export enum NetworkType { L1, diff --git a/apps/cowswap-frontend/src/legacy/constants/index.ts b/libs/common-const/src/common.ts similarity index 94% rename from apps/cowswap-frontend/src/legacy/constants/index.ts rename to libs/common-const/src/common.ts index 160523ed91..093a601cac 100644 --- a/apps/cowswap-frontend/src/legacy/constants/index.ts +++ b/libs/common-const/src/common.ts @@ -1,12 +1,12 @@ import networksJson from '@cowprotocol/contracts/networks.json' import { IpfsConfig, SupportedChainId as ChainId } from '@cowprotocol/cow-sdk' -import { ethFlowBarnJson, ethFlowProdJson } from '@cowswap/abis' +import { ethFlowBarnJson, ethFlowProdJson } from '@cowprotocol/abis' import { Fraction, Percent, Token } from '@uniswap/sdk-core' import BigNumber from 'bignumber.js' import ms from 'ms.macro' -import { PINATA_API_KEY, PINATA_SECRET_API_KEY } from 'legacy/constants/ipfs' +import { PINATA_API_KEY, PINATA_SECRET_API_KEY } from './ipfs' // TODO: move those consts to src/constants/common @@ -47,9 +47,6 @@ export const BARN_URL = `barn.cow.fi` export const APP_TITLE = 'CoW Swap | The smartest way to trade cryptocurrencies' -// Smart contract wallets are filtered out by default, no need to add them to this list -export const UNSUPPORTED_WC_WALLETS = new Set(['DeFi Wallet', 'WallETH']) - type Env = 'barn' | 'prod' export const COWSWAP_ETHFLOW_CONTRACT_ADDRESS: Record>> = { @@ -65,13 +62,13 @@ export const COWSWAP_ETHFLOW_CONTRACT_ADDRESS: Record> = { +export const GP_SETTLEMENT_CONTRACT_ADDRESS: Record = { [ChainId.MAINNET]: GPv2Settlement[ChainId.MAINNET].address, [ChainId.GNOSIS_CHAIN]: GPv2Settlement[ChainId.GNOSIS_CHAIN].address, [ChainId.GOERLI]: GPv2Settlement[ChainId.GOERLI].address, } -export const GP_VAULT_RELAYER: Partial> = { +export const GP_VAULT_RELAYER: Record = { [ChainId.MAINNET]: GPv2VaultRelayer[ChainId.MAINNET].address, [ChainId.GNOSIS_CHAIN]: GPv2VaultRelayer[ChainId.GNOSIS_CHAIN].address, [ChainId.GOERLI]: GPv2VaultRelayer[ChainId.GOERLI].address, @@ -99,11 +96,9 @@ export const NATIVE_CURRENCY_BUY_TOKEN: { [chainId in ChainId | number]: Token } [ChainId.GNOSIS_CHAIN]: new Token(ChainId.GNOSIS_CHAIN, NATIVE_CURRENCY_BUY_ADDRESS, 18, 'xDAI', 'xDAI'), } -export const ORDER_ID_SHORT_LENGTH = 8 export const INPUT_OUTPUT_EXPLANATION = 'Only executed swaps incur fees.' export const PENDING_ORDERS_BUFFER = ms`60s` // 60s export const CANCELLED_ORDERS_PENDING_TIME = ms`5min` // 5min -export const EXPIRED_ORDERS_PENDING_TIME = ms`15min` // 15min export const PRICE_API_TIMEOUT_MS = ms`10s` // 10s export const GP_ORDER_UPDATE_INTERVAL = ms`30s` // 30s export const MINIMUM_ORDER_VALID_TO_TIME_SECONDS = 120 diff --git a/apps/cowswap-frontend/src/legacy/utils/gnosis_chain/constants.ts b/libs/common-const/src/gnosis_chain/constants.ts similarity index 100% rename from apps/cowswap-frontend/src/legacy/utils/gnosis_chain/constants.ts rename to libs/common-const/src/gnosis_chain/constants.ts diff --git a/apps/cowswap-frontend/src/legacy/utils/gnosis_chain/hack.ts b/libs/common-const/src/gnosis_chain/hack.ts similarity index 52% rename from apps/cowswap-frontend/src/legacy/utils/gnosis_chain/hack.ts rename to libs/common-const/src/gnosis_chain/hack.ts index fecc3472d0..5f3c2fd721 100644 --- a/apps/cowswap-frontend/src/legacy/utils/gnosis_chain/hack.ts +++ b/libs/common-const/src/gnosis_chain/hack.ts @@ -1,15 +1,18 @@ // this file essentially provides all the overrides employed in uniswap-xdai-sdk fork // + logic for chainId switch to/from xDAI -import { SupportedChainId as ChainId } from '@cowprotocol/cow-sdk' - -import { GpEther as ETHER } from 'legacy/constants/tokens' +import { SupportedChainId } from '@cowprotocol/cow-sdk' import { XDAI_SYMBOL } from './constants' const CURRENCY_SYMBOLS_XDAI = { native: XDAI_SYMBOL, wrapped: 'wxDAI' } const CURRENCY_SYMBOLS_ETH = { native: 'Ether', wrapped: 'WETH' } -export function getChainCurrencySymbols(chainId?: ChainId): { native: string; wrapped: string } { +export function getChainCurrencySymbols(chainId?: SupportedChainId): { native: string; wrapped: string } { if (!chainId) return CURRENCY_SYMBOLS_ETH - return ETHER.onChain(chainId).symbol === XDAI_SYMBOL ? CURRENCY_SYMBOLS_XDAI : CURRENCY_SYMBOLS_ETH + + if (chainId === SupportedChainId.GNOSIS_CHAIN) { + return CURRENCY_SYMBOLS_XDAI + } + + return CURRENCY_SYMBOLS_ETH } diff --git a/apps/cowswap-frontend/src/legacy/utils/goerli/constants.ts b/libs/common-const/src/goerli/constants.ts similarity index 100% rename from apps/cowswap-frontend/src/legacy/utils/goerli/constants.ts rename to libs/common-const/src/goerli/constants.ts diff --git a/libs/common-const/src/index.ts b/libs/common-const/src/index.ts new file mode 100644 index 0000000000..34320bd6e6 --- /dev/null +++ b/libs/common-const/src/index.ts @@ -0,0 +1,14 @@ +export * from './common' +export * from './locales' +export * from './lists' +export * from './tokens' +export * from './intl' +export * from './addresses' +export * from './misc' +export * from './chainInfo' +export * from './networks' +export * from './routing' +export * from './ipfs' +export * from './gnosis_chain/constants' +export * from './gnosis_chain/hack' +export { DAI_GOERLI, WETH_GOERLI, USDT_GOERLI } from './goerli/constants' diff --git a/apps/cowswap-frontend/src/common/constants/intl.ts b/libs/common-const/src/intl.ts similarity index 100% rename from apps/cowswap-frontend/src/common/constants/intl.ts rename to libs/common-const/src/intl.ts diff --git a/apps/cowswap-frontend/src/legacy/constants/ipfs.ts b/libs/common-const/src/ipfs.ts similarity index 100% rename from apps/cowswap-frontend/src/legacy/constants/ipfs.ts rename to libs/common-const/src/ipfs.ts diff --git a/apps/cowswap-frontend/src/legacy/constants/lists.ts b/libs/common-const/src/lists.ts similarity index 96% rename from apps/cowswap-frontend/src/legacy/constants/lists.ts rename to libs/common-const/src/lists.ts index e640b8d21b..7c57d026eb 100644 --- a/apps/cowswap-frontend/src/legacy/constants/lists.ts +++ b/libs/common-const/src/lists.ts @@ -1,6 +1,6 @@ import { SupportedChainId as ChainId } from '@cowprotocol/cow-sdk' -import { RAW_CODE_LINK } from 'legacy/constants' +import { RAW_CODE_LINK } from './common' export type NetworkLists = { [chain in ChainId]: string[] @@ -78,5 +78,3 @@ export const DEFAULT_ACTIVE_LIST_URLS_BY_NETWORK: NetworkLists = { // Set what we want as the default list when no chain id available: default = MAINNET export const DEFAULT_NETWORK_FOR_LISTS = ChainId.MAINNET - -export const DEFAULT_LIST_OF_LISTS: string[] = [] diff --git a/apps/cowswap-frontend/src/legacy/constants/locales.ts b/libs/common-const/src/locales.ts similarity index 100% rename from apps/cowswap-frontend/src/legacy/constants/locales.ts rename to libs/common-const/src/locales.ts diff --git a/apps/cowswap-frontend/src/legacy/constants/misc.ts b/libs/common-const/src/misc.ts similarity index 100% rename from apps/cowswap-frontend/src/legacy/constants/misc.ts rename to libs/common-const/src/misc.ts diff --git a/apps/cowswap-frontend/src/legacy/constants/networks.ts b/libs/common-const/src/networks.ts similarity index 100% rename from apps/cowswap-frontend/src/legacy/constants/networks.ts rename to libs/common-const/src/networks.ts diff --git a/libs/common-const/src/routing.ts b/libs/common-const/src/routing.ts new file mode 100644 index 0000000000..fe6ba032f7 --- /dev/null +++ b/libs/common-const/src/routing.ts @@ -0,0 +1,41 @@ +// a list of tokens by chain + +import { SupportedChainId } from '@cowprotocol/cow-sdk' +import { Currency } from '@uniswap/sdk-core' + +import { COW, DAI, EURE_GNOSIS_CHAIN, USDC_MAINNET, USDT, WBTC, WRAPPED_NATIVE_CURRENCY } from './tokens' + +import { USDC_GNOSIS_CHAIN, WBTC_GNOSIS_CHAIN, WETH_GNOSIS_CHAIN } from './gnosis_chain/constants' +import { DAI_GOERLI, USDC_GOERLI } from './goerli/constants' + +type ChainCurrencyList = { + readonly [chainId: number]: Currency[] +} + +/** + * Shows up in the currency select for swap and add liquidity + */ +export const COMMON_BASES: ChainCurrencyList = { + [SupportedChainId.MAINNET]: [ + DAI, + COW[SupportedChainId.MAINNET], + USDC_MAINNET, + USDT, + WBTC, + WRAPPED_NATIVE_CURRENCY[SupportedChainId.MAINNET], + ], + [SupportedChainId.GOERLI]: [ + WRAPPED_NATIVE_CURRENCY[SupportedChainId.GOERLI], + COW[SupportedChainId.GOERLI], + DAI_GOERLI, + USDC_GOERLI, + ], + [SupportedChainId.GNOSIS_CHAIN]: [ + USDC_GNOSIS_CHAIN, + COW[SupportedChainId.GNOSIS_CHAIN], + EURE_GNOSIS_CHAIN, + WRAPPED_NATIVE_CURRENCY[SupportedChainId.GNOSIS_CHAIN], + WETH_GNOSIS_CHAIN, + WBTC_GNOSIS_CHAIN, + ], +} diff --git a/apps/cowswap-frontend/src/legacy/constants/tokenLists/broken.tokenlist.json b/libs/common-const/src/tokenLists/broken.tokenlist.json similarity index 100% rename from apps/cowswap-frontend/src/legacy/constants/tokenLists/broken.tokenlist.json rename to libs/common-const/src/tokenLists/broken.tokenlist.json diff --git a/apps/cowswap-frontend/src/legacy/constants/tokenLists/unsupported.tokenlist.json b/libs/common-const/src/tokenLists/unsupported.tokenlist.json similarity index 100% rename from apps/cowswap-frontend/src/legacy/constants/tokenLists/unsupported.tokenlist.json rename to libs/common-const/src/tokenLists/unsupported.tokenlist.json diff --git a/apps/cowswap-frontend/src/legacy/constants/tokens.ts b/libs/common-const/src/tokens.ts similarity index 80% rename from apps/cowswap-frontend/src/legacy/constants/tokens.ts rename to libs/common-const/src/tokens.ts index e36b4e57fa..473ddb5cad 100644 --- a/apps/cowswap-frontend/src/legacy/constants/tokens.ts +++ b/libs/common-const/src/tokens.ts @@ -1,12 +1,12 @@ import { SupportedChainId } from '@cowprotocol/cow-sdk' import { Currency, Ether, NativeCurrency, Token, WETH9 } from '@uniswap/sdk-core' -import cowLogo from 'legacy/assets/cow-swap/cow.svg' -import gnoLogo from 'legacy/assets/cow-swap/gno.png' -import usdcLogo from 'legacy/assets/cow-swap/usdc.png' -import vCowLogo from 'legacy/assets/cow-swap/vCOW.png' -import wxDaiLogo from 'legacy/assets/cow-swap/wxdai.png' -import { COW_CONTRACT_ADDRESS, V_COW_CONTRACT_ADDRESS } from 'legacy/constants' +import cowLogo from '@cowprotocol/assets/cow-swap/cow.svg' +import gnoLogo from '@cowprotocol/assets/cow-swap/gno.png' +import usdcLogo from '@cowprotocol/assets/cow-swap/usdc.png' +import vCowLogo from '@cowprotocol/assets/cow-swap/vCOW.png' +import wxDaiLogo from '@cowprotocol/assets/cow-swap/wxdai.png' + import { USDC_GNOSIS_CHAIN, WBTC_GNOSIS_CHAIN, @@ -14,8 +14,9 @@ import { WXDAI, XDAI_NAME, XDAI_SYMBOL, -} from 'legacy/utils/gnosis_chain/constants' -import { DAI_GOERLI, USDT_GOERLI, WBTC_GOERLI, WETH_GOERLI } from 'legacy/utils/goerli/constants' +} from './gnosis_chain/constants' +import { DAI_GOERLI, USDT_GOERLI, WBTC_GOERLI, WETH_GOERLI } from './goerli/constants' +import { COW_CONTRACT_ADDRESS, V_COW_CONTRACT_ADDRESS } from './common' export const USDC_MAINNET = new Token( SupportedChainId.MAINNET, @@ -31,13 +32,6 @@ export const USDC_GOERLI = new Token( 'USDC', 'USD//C' ) -export const AMPL = new Token( - SupportedChainId.MAINNET, - '0xD46bA6D942050d489DBd938a2C909A5d5039A161', - 9, - 'AMPL', - 'Ampleforth' -) export const DAI = new Token( SupportedChainId.MAINNET, '0x6B175474E89094C44Da98b954EedeAC495271d0F', @@ -64,70 +58,6 @@ export const WBTC = new Token( 'WBTC', 'Wrapped BTC' ) -export const FEI = new Token( - SupportedChainId.MAINNET, - '0x956F47F50A910163D8BF957Cf5846D573E7f87CA', - 18, - 'FEI', - 'Fei USD' -) -export const TRIBE = new Token( - SupportedChainId.MAINNET, - '0xc7283b66Eb1EB5FB86327f08e1B5816b0720212B', - 18, - 'TRIBE', - 'Tribe' -) -export const FRAX = new Token( - SupportedChainId.MAINNET, - '0x853d955aCEf822Db058eb8505911ED77F175b99e', - 18, - 'FRAX', - 'Frax' -) -export const FXS = new Token( - SupportedChainId.MAINNET, - '0x3432B6A60D23Ca0dFCa7761B7ab56459D9C964D0', - 18, - 'FXS', - 'Frax Share' -) -export const renBTC = new Token( - SupportedChainId.MAINNET, - '0xEB4C2781e4ebA804CE9a9803C67d0893436bB27D', - 8, - 'renBTC', - 'renBTC' -) -export const ETH2X_FLI = new Token( - SupportedChainId.MAINNET, - '0xAa6E8127831c9DE45ae56bB1b0d4D4Da6e5665BD', - 18, - 'ETH2x-FLI', - 'ETH 2x Flexible Leverage Index' -) -export const sETH2 = new Token( - SupportedChainId.MAINNET, - '0xFe2e637202056d30016725477c5da089Ab0A043A', - 18, - 'sETH2', - 'StakeWise Staked ETH2' -) -export const rETH2 = new Token( - SupportedChainId.MAINNET, - '0x20BC832ca081b91433ff6c17f85701B6e92486c5', - 18, - 'rETH2', - 'StakeWise Reward ETH2' -) -export const SWISE = new Token( - SupportedChainId.MAINNET, - '0x48C3399719B582dD63eB5AADf12A40B4C3f52FA2', - 18, - 'SWISE', - 'StakeWise' -) - export const WRAPPED_NATIVE_CURRENCY: { [chainId in SupportedChainId]: Token } = { [SupportedChainId.MAINNET]: WETH9[SupportedChainId.MAINNET], [SupportedChainId.GNOSIS_CHAIN]: WXDAI, @@ -184,8 +114,6 @@ export class GpEther extends Ether { throw new Error('Unsupported chain ID') } - private static _cachedExtendedEther: { [chainId: number]: NativeCurrency } = {} - public static onChain = nativeOnChain } diff --git a/libs/common-const/tsconfig.json b/libs/common-const/tsconfig.json new file mode 100644 index 0000000000..bab74ff2e6 --- /dev/null +++ b/libs/common-const/tsconfig.json @@ -0,0 +1,21 @@ +{ + "compilerOptions": { + "jsx": "react-jsx", + "allowJs": false, + "esModuleInterop": false, + "allowSyntheticDefaultImports": true, + "strict": true, + "types": ["vite/client"] + }, + "files": [], + "include": [], + "references": [ + { + "path": "./tsconfig.lib.json" + }, + { + "path": "./tsconfig.spec.json" + } + ], + "extends": "../../tsconfig.base.json" +} diff --git a/libs/common-const/tsconfig.lib.json b/libs/common-const/tsconfig.lib.json new file mode 100644 index 0000000000..1b2b0c12df --- /dev/null +++ b/libs/common-const/tsconfig.lib.json @@ -0,0 +1,19 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "../../dist/out-tsc", + "types": ["node", "vite/client"] + }, + "files": ["../../node_modules/@nx/react/typings/cssmodule.d.ts", "../../node_modules/@nx/react/typings/image.d.ts"], + "exclude": [ + "**/*.spec.ts", + "**/*.test.ts", + "**/*.spec.tsx", + "**/*.test.tsx", + "**/*.spec.js", + "**/*.test.js", + "**/*.spec.jsx", + "**/*.test.jsx" + ], + "include": ["**/*.js", "**/*.jsx", "**/*.ts", "**/*.tsx"] +} diff --git a/libs/common-const/tsconfig.spec.json b/libs/common-const/tsconfig.spec.json new file mode 100644 index 0000000000..26ef046ac5 --- /dev/null +++ b/libs/common-const/tsconfig.spec.json @@ -0,0 +1,20 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "../../dist/out-tsc", + "module": "commonjs", + "types": ["jest", "node"] + }, + "include": [ + "jest.config.ts", + "src/**/*.test.ts", + "src/**/*.spec.ts", + "src/**/*.test.tsx", + "src/**/*.spec.tsx", + "src/**/*.test.js", + "src/**/*.spec.js", + "src/**/*.test.jsx", + "src/**/*.spec.jsx", + "src/**/*.d.ts" + ] +} diff --git a/libs/common-const/vite.config.ts b/libs/common-const/vite.config.ts new file mode 100644 index 0000000000..fc139c12d2 --- /dev/null +++ b/libs/common-const/vite.config.ts @@ -0,0 +1,49 @@ +/// +import { defineConfig } from 'vite' +import react from '@vitejs/plugin-react-swc' +import viteTsConfigPaths from 'vite-tsconfig-paths' +import dts from 'vite-plugin-dts' +import * as path from 'path' + +export default defineConfig({ + cacheDir: '../../node_modules/.vite/common-const', + + plugins: [ + dts({ + entryRoot: 'src', + tsConfigFilePath: path.join(__dirname, 'tsconfig.lib.json'), + skipDiagnostics: true, + }), + react(), + viteTsConfigPaths({ + root: '../../', + }), + ], + + // Uncomment this if you are using workers. + // worker: { + // plugins: [ + // viteTsConfigPaths({ + // root: '../../', + // }), + // ], + // }, + + // Configuration for building your library. + // See: https://vitejs.dev/guide/build.html#library-mode + build: { + lib: { + // Could also be a dictionary or array of multiple entry points. + entry: 'src/index.ts', + name: 'common-const', + fileName: 'index', + // Change this to the formats you want to support. + // Don't forget to update your package.json as well. + formats: ['es', 'cjs'], + }, + rollupOptions: { + // External packages that should not be bundled into your library. + external: ['react', 'react-dom', 'react/jsx-runtime'], + }, + }, +}) diff --git a/libs/common-hooks/.babelrc b/libs/common-hooks/.babelrc new file mode 100644 index 0000000000..ef4889c1ab --- /dev/null +++ b/libs/common-hooks/.babelrc @@ -0,0 +1,20 @@ +{ + "presets": [ + [ + "@nx/react/babel", + { + "runtime": "automatic", + "useBuiltIns": "usage" + } + ] + ], + "plugins": [ + [ + "styled-components", + { + "pure": true, + "ssr": true + } + ] + ] +} diff --git a/libs/common-hooks/.eslintrc.json b/libs/common-hooks/.eslintrc.json new file mode 100644 index 0000000000..231aaa5f83 --- /dev/null +++ b/libs/common-hooks/.eslintrc.json @@ -0,0 +1,21 @@ +{ + "extends": ["plugin:@nx/react", "../../.eslintrc.json"], + "ignorePatterns": ["!**/*"], + "rules": { + "@typescript-eslint/no-explicit-any": "off" + }, + "overrides": [ + { + "files": ["*.ts", "*.tsx", "*.js", "*.jsx"], + "rules": {} + }, + { + "files": ["*.ts", "*.tsx"], + "rules": {} + }, + { + "files": ["*.js", "*.jsx"], + "rules": {} + } + ] +} diff --git a/libs/common-hooks/README.md b/libs/common-hooks/README.md new file mode 100644 index 0000000000..6fc5afcb20 --- /dev/null +++ b/libs/common-hooks/README.md @@ -0,0 +1 @@ +# Common hooks diff --git a/libs/common-hooks/jest.config.ts b/libs/common-hooks/jest.config.ts new file mode 100644 index 0000000000..ca22397e85 --- /dev/null +++ b/libs/common-hooks/jest.config.ts @@ -0,0 +1,11 @@ +/* eslint-disable */ +export default { + displayName: 'common-hooks', + preset: '../../jest.preset.js', + transform: { + '^(?!.*\\.(js|jsx|ts|tsx|css|json)$)': '@nx/react/plugins/jest', + '^.+\\.[tj]sx?$': ['babel-jest', { presets: ['@nx/react/babel'] }], + }, + moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx'], + coverageDirectory: '../../coverage/libs/common-hooks', +} diff --git a/libs/common-hooks/package.json b/libs/common-hooks/package.json new file mode 100644 index 0000000000..38109c240d --- /dev/null +++ b/libs/common-hooks/package.json @@ -0,0 +1,12 @@ +{ + "name": "@cowprotocol/common-hooks", + "version": "0.0.1", + "main": "./index.js", + "types": "./index.d.ts", + "exports": { + ".": { + "import": "./index.mjs", + "require": "./index.js" + } + } +} diff --git a/libs/common-hooks/project.json b/libs/common-hooks/project.json new file mode 100644 index 0000000000..7de25fb3e2 --- /dev/null +++ b/libs/common-hooks/project.json @@ -0,0 +1,46 @@ +{ + "name": "@cowprotocol/common-hooks", + "$schema": "../../node_modules/nx/schemas/project-schema.json", + "sourceRoot": "libs/common-hooks/src", + "projectType": "library", + "tags": [], + "targets": { + "lint": { + "executor": "@nx/linter:eslint", + "outputs": ["{options.outputFile}"], + "options": { + "lintFilePatterns": ["libs/common-hooks/**/*.{ts,tsx,js,jsx}"] + } + }, + "build": { + "executor": "@nx/vite:build", + "outputs": ["{options.outputPath}"], + "defaultConfiguration": "production", + "options": { + "outputPath": "dist/libs/common-hooks" + }, + "configurations": { + "development": { + "mode": "development" + }, + "production": { + "mode": "production" + } + } + }, + "test": { + "executor": "@nx/jest:jest", + "outputs": ["{workspaceRoot}/coverage/{projectRoot}"], + "options": { + "jestConfig": "libs/common-hooks/jest.config.ts", + "passWithNoTests": true + }, + "configurations": { + "ci": { + "ci": true, + "codeCoverage": true + } + } + } + } +} diff --git a/libs/common-hooks/src/index.ts b/libs/common-hooks/src/index.ts new file mode 100644 index 0000000000..57ca43320f --- /dev/null +++ b/libs/common-hooks/src/index.ts @@ -0,0 +1,24 @@ +export * from './useContract' +export * from './useDebounce' +export * from './usePrevious' +export * from './useParsedQueryString' +export * from './useIsMounted' +export * from './useLoadingWithTimeout' +export * from './useInterval' +export * from './useNetworkName' +export * from './useIsOnline' +export * from './useTheme' +export * from './useColor' +export * from './useToggle' +export * from './useOnClickOutside' +export * from './useFilterTokens' +export * from './useTimeAgo' +export * from './useIsWindowVisible' +export * from './useGetReceipt' +export * from './useBlockNumber' +export * from './useMachineTime' +export * from './useFetchFile' +export * from './useWindowSize' +export * from './useCopyClipboard' +export * from './useLast' +export * from './useDebouncedChangeHandler' diff --git a/apps/cowswap-frontend/src/lib/hooks/useBlockNumber.tsx b/libs/common-hooks/src/useBlockNumber.tsx similarity index 95% rename from apps/cowswap-frontend/src/lib/hooks/useBlockNumber.tsx rename to libs/common-hooks/src/useBlockNumber.tsx index d17087e524..0eee5685fb 100644 --- a/apps/cowswap-frontend/src/lib/hooks/useBlockNumber.tsx +++ b/libs/common-hooks/src/useBlockNumber.tsx @@ -1,9 +1,8 @@ import { createContext, ReactNode, useCallback, useContext, useEffect, useMemo, useState } from 'react' +import { useIsWindowVisible } from './useIsWindowVisible' import { useWeb3React } from '@web3-react/core' -import useIsWindowVisible from 'legacy/hooks/useIsWindowVisible' - const MISSING_PROVIDER = Symbol() const BlockNumberContext = createContext< | { @@ -22,7 +21,7 @@ function useBlockNumberContext() { } /** Requires that BlockUpdater be installed in the DOM tree. */ -export default function useBlockNumber(): number | undefined { +export function useBlockNumber(): number | undefined { return useBlockNumberContext().value } diff --git a/apps/cowswap-frontend/src/legacy/hooks/useColor/useColorMod.ts b/libs/common-hooks/src/useColor/index.ts similarity index 95% rename from apps/cowswap-frontend/src/legacy/hooks/useColor/useColorMod.ts rename to libs/common-hooks/src/useColor/index.ts index 5a252d47ff..f1c2c8b8e1 100644 --- a/apps/cowswap-frontend/src/legacy/hooks/useColor/useColorMod.ts +++ b/libs/common-hooks/src/useColor/index.ts @@ -3,8 +3,7 @@ import { useLayoutEffect, useState } from 'react' import Vibrant from 'node-vibrant/lib/bundle' import { shade } from 'polished' import { hex } from 'wcag-contrast' - -import uriToHttp from 'lib/utils/uriToHttp' +import { uriToHttp } from '@cowprotocol/common-utils' export async function getColorFromUriPath(uri: string): Promise { const formattedPath = uriToHttp(uri)[0] diff --git a/apps/cowswap-frontend/src/legacy/hooks/useContract.ts b/libs/common-hooks/src/useContract.ts similarity index 80% rename from apps/cowswap-frontend/src/legacy/hooks/useContract.ts rename to libs/common-hooks/src/useContract.ts index 7f68aa81e6..f526ff170f 100644 --- a/apps/cowswap-frontend/src/legacy/hooks/useContract.ts +++ b/libs/common-hooks/src/useContract.ts @@ -2,18 +2,11 @@ import { useMemo } from 'react' import { SupportedChainId } from '@cowprotocol/cow-sdk' import { - ArgentWalletDetector, - EnsPublicResolver, - EnsRegistrar, Erc20, Erc721, Erc1155, Weth, - CoWSwapEthFlowJson, - ArgentWalletDetectorAbi, Eip2612Abi, - EnsPublicResolverAbi, - EnsAbi, Erc20Abi, Erc20Bytes32Abi, Erc721Abi, @@ -26,7 +19,8 @@ import { CoWSwapEthFlow, vCowAbi, UniswapInterfaceMulticall, -} from '@cowswap/abis' + CoWSwapEthFlowAbi, +} from '@cowprotocol/abis' import { Contract } from '@ethersproject/contracts' import type { JsonRpcProvider } from '@ethersproject/providers' import { useWeb3React } from '@web3-react/core' @@ -35,13 +29,12 @@ import { COWSWAP_ETHFLOW_CONTRACT_ADDRESS, GP_SETTLEMENT_CONTRACT_ADDRESS, V_COW_CONTRACT_ADDRESS, -} from 'legacy/constants' -import { ARGENT_WALLET_DETECTOR_ADDRESS, ENS_REGISTRAR_ADDRESSES, MULTICALL_ADDRESS } from 'legacy/constants/addresses' -import { WRAPPED_NATIVE_CURRENCY } from 'legacy/constants/tokens' -import { getContract } from 'legacy/utils' -import { isEns, isProd, isStaging } from 'legacy/utils/environments' + MULTICALL_ADDRESS, + WRAPPED_NATIVE_CURRENCY, +} from '@cowprotocol/common-const' +import { getContract, isEns, isProd, isStaging } from '@cowprotocol/common-utils' -import { useWalletInfo } from 'modules/wallet' +import { useWalletInfo } from '@cowprotocol/wallet' const { abi: MulticallABI } = UniswapInterfaceMulticallAbi @@ -90,18 +83,6 @@ export function useERC1155Contract(nftAddress?: string) { return useContract(nftAddress, Erc1155Abi, false) } -export function useArgentWalletDetectorContract() { - return useContract(ARGENT_WALLET_DETECTOR_ADDRESS, ArgentWalletDetectorAbi, false) -} - -export function useENSRegistrarContract(withSignerIfPossible?: boolean) { - return useContract(ENS_REGISTRAR_ADDRESSES, EnsAbi, withSignerIfPossible) -} - -export function useENSResolverContract(address: string | undefined, withSignerIfPossible?: boolean) { - return useContract(address, EnsPublicResolverAbi, withSignerIfPossible) -} - export function useBytes32TokenContract(tokenAddress?: string, withSignerIfPossible?: boolean): Contract | null { return useContract(tokenAddress, Erc20Bytes32Abi, withSignerIfPossible) } @@ -114,8 +95,6 @@ export function useInterfaceMulticall() { return useContract(MULTICALL_ADDRESS, MulticallABI, false) as UniswapInterfaceMulticall } -const COWSWAP_ETHFLOW_ABI = CoWSwapEthFlowJson.abi - export function useEthFlowContract(): CoWSwapEthFlow | null { const { chainId } = useWalletInfo() @@ -123,7 +102,7 @@ export function useEthFlowContract(): CoWSwapEthFlow | null { const contractAddress = chainId ? COWSWAP_ETHFLOW_CONTRACT_ADDRESS[contractEnv][chainId] : undefined - return useContract(contractAddress, COWSWAP_ETHFLOW_ABI, true) + return useContract(contractAddress, CoWSwapEthFlowAbi, true) } export function useGP2SettlementContract(): GPv2Settlement | null { diff --git a/apps/cowswap-frontend/src/legacy/hooks/useCopyClipboard.ts b/libs/common-hooks/src/useCopyClipboard.ts similarity index 85% rename from apps/cowswap-frontend/src/legacy/hooks/useCopyClipboard.ts rename to libs/common-hooks/src/useCopyClipboard.ts index c922affd50..a0b9e91803 100644 --- a/apps/cowswap-frontend/src/legacy/hooks/useCopyClipboard.ts +++ b/libs/common-hooks/src/useCopyClipboard.ts @@ -2,7 +2,7 @@ import { useCallback, useEffect, useState } from 'react' import copy from 'copy-to-clipboard' -export default function useCopyClipboard(timeout = 500): [boolean, (toCopy: string) => void] { +export function useCopyClipboard(timeout = 500): [boolean, (toCopy: string) => void] { const [isCopied, setIsCopied] = useState(false) const staticCopy = useCallback((text: string) => { diff --git a/apps/cowswap-frontend/src/legacy/hooks/useDebounce.ts b/libs/common-hooks/src/useDebounce.ts similarity index 92% rename from apps/cowswap-frontend/src/legacy/hooks/useDebounce.ts rename to libs/common-hooks/src/useDebounce.ts index c03ee2bc68..fcedeacaa6 100644 --- a/apps/cowswap-frontend/src/legacy/hooks/useDebounce.ts +++ b/libs/common-hooks/src/useDebounce.ts @@ -5,7 +5,7 @@ import { useEffect, useState } from 'react' * Non-primitives *must* wrap the value in useMemo, or the value will be updated due to referential inequality. */ // modified from https://usehooks.com/useDebounce/ -export default function useDebounce(value: T, delay: number): T { +export function useDebounce(value: T, delay: number): T { const [debouncedValue, setDebouncedValue] = useState(value) useEffect(() => { diff --git a/apps/cowswap-frontend/src/legacy/hooks/useDebouncedChangeHandler.tsx b/libs/common-hooks/src/useDebouncedChangeHandler.tsx similarity index 95% rename from apps/cowswap-frontend/src/legacy/hooks/useDebouncedChangeHandler.tsx rename to libs/common-hooks/src/useDebouncedChangeHandler.tsx index 21a71f9b90..5d78e63ca3 100644 --- a/apps/cowswap-frontend/src/legacy/hooks/useDebouncedChangeHandler.tsx +++ b/libs/common-hooks/src/useDebouncedChangeHandler.tsx @@ -6,7 +6,7 @@ import { useCallback, useEffect, useRef, useState } from 'react' * @param onChange change handler that should receive the debounced updates to the value * @param debouncedMs how long we should wait for changes to be applied */ -export default function useDebouncedChangeHandler( +export function useDebouncedChangeHandler( value: T, onChange: (newValue: T) => void, debouncedMs = 100 diff --git a/apps/cowswap-frontend/src/legacy/hooks/useFetchFile.ts b/libs/common-hooks/src/useFetchFile.ts similarity index 93% rename from apps/cowswap-frontend/src/legacy/hooks/useFetchFile.ts rename to libs/common-hooks/src/useFetchFile.ts index 0ee84cf6e9..0ad4d93c52 100644 --- a/apps/cowswap-frontend/src/legacy/hooks/useFetchFile.ts +++ b/libs/common-hooks/src/useFetchFile.ts @@ -4,7 +4,7 @@ function getErrorMessage(filePath: string, res: Response): string { return `Error fetching file ${filePath} - status: ${res.statusText}` } -export default function useFetchFile(filePath: string) { +export function useFetchFile(filePath: string) { const [file, setFile] = useState(null) const [error, setError] = useState(null) diff --git a/apps/cowswap-frontend/src/legacy/hooks/useFilterTokens.ts b/libs/common-hooks/src/useFilterTokens.ts similarity index 88% rename from apps/cowswap-frontend/src/legacy/hooks/useFilterTokens.ts rename to libs/common-hooks/src/useFilterTokens.ts index 8143f436e9..00539eb4cf 100644 --- a/apps/cowswap-frontend/src/legacy/hooks/useFilterTokens.ts +++ b/libs/common-hooks/src/useFilterTokens.ts @@ -2,9 +2,9 @@ import { useMemo } from 'react' import { Token } from '@uniswap/sdk-core' -import { isAddress } from 'legacy/utils' +import { isAddress } from '@cowprotocol/common-utils' -export default function useFilterTokens(tokens: Token[], query: string): Token[] { +export function useFilterTokens(tokens: Token[], query: string): Token[] { return useMemo(() => { // only calc anything if we actually have more than 1 token in list // and the user is actively searching tokens diff --git a/apps/cowswap-frontend/src/legacy/hooks/useGetReceipt.ts b/libs/common-hooks/src/useGetReceipt.ts similarity index 78% rename from apps/cowswap-frontend/src/legacy/hooks/useGetReceipt.ts rename to libs/common-hooks/src/useGetReceipt.ts index 90f66fa516..533ee94615 100644 --- a/apps/cowswap-frontend/src/legacy/hooks/useGetReceipt.ts +++ b/libs/common-hooks/src/useGetReceipt.ts @@ -3,20 +3,21 @@ import { useCallback } from 'react' import { TransactionReceipt } from '@ethersproject/abstract-provider' import { useWeb3React } from '@web3-react/core' -import { RetryResult } from 'types' - -import { retry, RetryableError, RetryOptions } from 'legacy/utils/retry' - -import { useWalletInfo } from 'modules/wallet' +import { retry, RetryableError, RetryOptions } from '@cowprotocol/common-utils' +import { SupportedChainId } from '@cowprotocol/cow-sdk' const DEFAULT_RETRY_OPTIONS: RetryOptions = { n: 3, minWait: 1000, maxWait: 3000 } const RETRY_OPTIONS_BY_CHAIN_ID: { [chainId: number]: RetryOptions } = {} +interface RetryResult { + promise: Promise + cancel: () => void +} + export type GetReceipt = (hash: string) => RetryResult -export function useGetReceipt(): GetReceipt { +export function useGetReceipt(chainId: SupportedChainId): GetReceipt { const { provider } = useWeb3React() - const { chainId } = useWalletInfo() const getReceipt = useCallback( (hash) => { diff --git a/apps/cowswap-frontend/src/lib/hooks/useInterval.ts b/libs/common-hooks/src/useInterval.ts similarity index 89% rename from apps/cowswap-frontend/src/lib/hooks/useInterval.ts rename to libs/common-hooks/src/useInterval.ts index 926e7c2545..274b32511b 100644 --- a/apps/cowswap-frontend/src/lib/hooks/useInterval.ts +++ b/libs/common-hooks/src/useInterval.ts @@ -6,7 +6,7 @@ import { useEffect, useRef } from 'react' * @param delay if null, the callback will not be invoked * @param leading if true, the callback will be invoked immediately (on the leading edge); otherwise, it will be invoked after delay */ -export default function useInterval(callback: () => void, delay: null | number, leading = true) { +export function useInterval(callback: () => void, delay: null | number, leading = true) { const savedCallback = useRef<() => void>() // Remember the latest callback. diff --git a/apps/cowswap-frontend/src/legacy/hooks/useIsMounted.ts b/libs/common-hooks/src/useIsMounted.ts similarity index 89% rename from apps/cowswap-frontend/src/legacy/hooks/useIsMounted.ts rename to libs/common-hooks/src/useIsMounted.ts index ef187c973b..f91a60b959 100644 --- a/apps/cowswap-frontend/src/legacy/hooks/useIsMounted.ts +++ b/libs/common-hooks/src/useIsMounted.ts @@ -4,7 +4,7 @@ import { useRef, useEffect } from 'react' * Creates a ref that can be used to solve the issue of * "Can't perform a React state update on an unmounted component." */ -export default function useIsMounted() { +export function useIsMounted() { const isMounted = useRef(false) useEffect(() => { diff --git a/apps/cowswap-frontend/src/legacy/hooks/useIsOnline.ts b/libs/common-hooks/src/useIsOnline.ts similarity index 95% rename from apps/cowswap-frontend/src/legacy/hooks/useIsOnline.ts rename to libs/common-hooks/src/useIsOnline.ts index f98a07c190..54d957f736 100644 --- a/apps/cowswap-frontend/src/legacy/hooks/useIsOnline.ts +++ b/libs/common-hooks/src/useIsOnline.ts @@ -2,7 +2,7 @@ import { useCallback, useEffect, useState } from 'react' import ms from 'ms.macro' -import { getTimeoutAbortController } from 'utils/request' +import { getTimeoutAbortController } from '@cowprotocol/common-utils' const CONNECTIVITY_CHECK_POLLING_TIME = ms`30s` const CONNECTIVITY_CHECK_TIMEOUT = ms`15s` @@ -37,7 +37,7 @@ export async function hasConnectivity(): Promise { /** * Returns whether the window is currently visible to the user. */ -export default function useIsOnline(): boolean { +export function useIsOnline(): boolean { const [online, setOnline] = useState(isOnline()) // Double-check if we REALLY don't have connectivity when the browser says so (There's cases where `online = false` flag might be not true) diff --git a/apps/cowswap-frontend/src/legacy/hooks/useIsWindowVisible.ts b/libs/common-hooks/src/useIsWindowVisible.ts similarity index 93% rename from apps/cowswap-frontend/src/legacy/hooks/useIsWindowVisible.ts rename to libs/common-hooks/src/useIsWindowVisible.ts index 2fe4247355..765def549a 100644 --- a/apps/cowswap-frontend/src/legacy/hooks/useIsWindowVisible.ts +++ b/libs/common-hooks/src/useIsWindowVisible.ts @@ -11,7 +11,7 @@ function isWindowVisible() { /** * Returns whether the window is currently visible to the user. */ -export default function useIsWindowVisible(): boolean { +export function useIsWindowVisible(): boolean { const [focused, setFocused] = useState(false) const listener = useCallback(() => { setFocused(isWindowVisible()) diff --git a/apps/cowswap-frontend/src/legacy/hooks/useLast.ts b/libs/common-hooks/src/useLast.ts similarity index 94% rename from apps/cowswap-frontend/src/legacy/hooks/useLast.ts rename to libs/common-hooks/src/useLast.ts index 33f169bd22..07c1fbc0ad 100644 --- a/apps/cowswap-frontend/src/legacy/hooks/useLast.ts +++ b/libs/common-hooks/src/useLast.ts @@ -5,7 +5,7 @@ import { useEffect, useState } from 'react' * @param value changing value * @param filterFn function that determines whether a given value should be considered for the last value */ -export default function useLast( +export function useLast( value: T | undefined | null, filterFn?: (value: T | null | undefined) => boolean ): T | null | undefined { diff --git a/apps/cowswap-frontend/src/legacy/hooks/useLoadingWithTimeout.ts b/libs/common-hooks/src/useLoadingWithTimeout.ts similarity index 92% rename from apps/cowswap-frontend/src/legacy/hooks/useLoadingWithTimeout.ts rename to libs/common-hooks/src/useLoadingWithTimeout.ts index 73675783e5..f0ef775825 100644 --- a/apps/cowswap-frontend/src/legacy/hooks/useLoadingWithTimeout.ts +++ b/libs/common-hooks/src/useLoadingWithTimeout.ts @@ -1,6 +1,6 @@ import { useEffect, useState } from 'react' -export default function useLoadingWithTimeout(isLoading: boolean, time: number) { +export function useLoadingWithTimeout(isLoading: boolean, time: number) { const [delayedLoad, setDelayedLoad] = useState(isLoading) useEffect(() => { diff --git a/apps/cowswap-frontend/src/legacy/hooks/useMachineTime.ts b/libs/common-hooks/src/useMachineTime.ts similarity index 52% rename from apps/cowswap-frontend/src/legacy/hooks/useMachineTime.ts rename to libs/common-hooks/src/useMachineTime.ts index a25087b251..3781dcfce9 100644 --- a/apps/cowswap-frontend/src/legacy/hooks/useMachineTime.ts +++ b/libs/common-hooks/src/useMachineTime.ts @@ -1,8 +1,7 @@ import { useState } from 'react' +import { useInterval } from './useInterval' -import useInterval from 'lib/hooks/useInterval' - -const useMachineTimeMs = (updateInterval: number): number => { +export const useMachineTimeMs = (updateInterval: number): number => { const [now, setNow] = useState(Date.now()) useInterval(() => { @@ -10,5 +9,3 @@ const useMachineTimeMs = (updateInterval: number): number => { }, updateInterval) return now } - -export default useMachineTimeMs diff --git a/libs/common-hooks/src/useNetworkName.ts b/libs/common-hooks/src/useNetworkName.ts new file mode 100644 index 0000000000..93492f5df0 --- /dev/null +++ b/libs/common-hooks/src/useNetworkName.ts @@ -0,0 +1,13 @@ +import { useMemo } from 'react' + +import { CHAIN_INFO } from '@cowprotocol/common-const' + +import { useWalletInfo } from '@cowprotocol/wallet' + +export function useNetworkName(): string | undefined { + const { chainId } = useWalletInfo() + + return useMemo(() => { + return CHAIN_INFO[chainId].label || '' + }, [chainId]) +} diff --git a/apps/cowswap-frontend/src/legacy/hooks/useOnClickOutside.tsx b/libs/common-hooks/src/useOnClickOutside.tsx similarity index 100% rename from apps/cowswap-frontend/src/legacy/hooks/useOnClickOutside.tsx rename to libs/common-hooks/src/useOnClickOutside.tsx diff --git a/apps/cowswap-frontend/src/legacy/hooks/useParsedQueryString.ts b/libs/common-hooks/src/useParsedQueryString.ts similarity index 90% rename from apps/cowswap-frontend/src/legacy/hooks/useParsedQueryString.ts rename to libs/common-hooks/src/useParsedQueryString.ts index 0780e568d3..38e8113bcb 100644 --- a/apps/cowswap-frontend/src/legacy/hooks/useParsedQueryString.ts +++ b/libs/common-hooks/src/useParsedQueryString.ts @@ -12,7 +12,7 @@ export function parsedQueryString(search?: string): ParsedQs { return search && search.length > 1 ? parse(search, { parseArrays: false, ignoreQueryPrefix: true }) : {} } -export default function useParsedQueryString(): ParsedQs { +export function useParsedQueryString(): ParsedQs { const { search } = useLocation() return useMemo(() => parsedQueryString(search), [search]) } diff --git a/apps/cowswap-frontend/src/legacy/hooks/usePrevious.ts b/libs/common-hooks/src/usePrevious.ts similarity index 90% rename from apps/cowswap-frontend/src/legacy/hooks/usePrevious.ts rename to libs/common-hooks/src/usePrevious.ts index 18d5ba3dba..6e83485f1e 100644 --- a/apps/cowswap-frontend/src/legacy/hooks/usePrevious.ts +++ b/libs/common-hooks/src/usePrevious.ts @@ -1,7 +1,7 @@ import { useEffect, useRef } from 'react' // modified from https://usehooks.com/usePrevious/ -export default function usePrevious(value: T) { +export function usePrevious(value: T) { // The ref object is a generic container whose current property is mutable ... // ... and can hold any value, similar to an instance property on a class const ref = useRef() diff --git a/libs/common-hooks/src/useTheme.ts b/libs/common-hooks/src/useTheme.ts new file mode 100644 index 0000000000..0e79aabdc3 --- /dev/null +++ b/libs/common-hooks/src/useTheme.ts @@ -0,0 +1,7 @@ +import { useContext } from 'react' + +import { ThemeContext } from 'styled-components' + +export function useTheme() { + return useContext(ThemeContext) +} diff --git a/apps/cowswap-frontend/src/legacy/hooks/useTimeAgo.ts b/libs/common-hooks/src/useTimeAgo.ts similarity index 84% rename from apps/cowswap-frontend/src/legacy/hooks/useTimeAgo.ts rename to libs/common-hooks/src/useTimeAgo.ts index 5ea6cb654f..166e9eb6b3 100644 --- a/apps/cowswap-frontend/src/legacy/hooks/useTimeAgo.ts +++ b/libs/common-hooks/src/useTimeAgo.ts @@ -2,7 +2,7 @@ import { useEffect, useState } from 'react' import * as timeago from 'timeago.js' -export default function useTimeAgo(value?: string | Date, interval = 1000): string { +export function useTimeAgo(value?: string | Date, interval = 1000): string { const [timeAgoValue, setTimeAgoValue] = useState('') useEffect(() => { diff --git a/apps/cowswap-frontend/src/legacy/hooks/useToggle.ts b/libs/common-hooks/src/useToggle.ts similarity index 70% rename from apps/cowswap-frontend/src/legacy/hooks/useToggle.ts rename to libs/common-hooks/src/useToggle.ts index 2da340a46b..852375bac9 100644 --- a/apps/cowswap-frontend/src/legacy/hooks/useToggle.ts +++ b/libs/common-hooks/src/useToggle.ts @@ -1,6 +1,6 @@ import { useCallback, useState } from 'react' -export default function useToggle(initialState = false): [boolean, () => void] { +export function useToggle(initialState = false): [boolean, () => void] { const [state, setState] = useState(initialState) const toggle = useCallback(() => setState((state) => !state), []) return [state, toggle] diff --git a/apps/cowswap-frontend/src/legacy/hooks/useWindowSize.ts b/libs/common-hooks/src/useWindowSize.ts similarity index 100% rename from apps/cowswap-frontend/src/legacy/hooks/useWindowSize.ts rename to libs/common-hooks/src/useWindowSize.ts diff --git a/libs/common-hooks/tsconfig.json b/libs/common-hooks/tsconfig.json new file mode 100644 index 0000000000..bab74ff2e6 --- /dev/null +++ b/libs/common-hooks/tsconfig.json @@ -0,0 +1,21 @@ +{ + "compilerOptions": { + "jsx": "react-jsx", + "allowJs": false, + "esModuleInterop": false, + "allowSyntheticDefaultImports": true, + "strict": true, + "types": ["vite/client"] + }, + "files": [], + "include": [], + "references": [ + { + "path": "./tsconfig.lib.json" + }, + { + "path": "./tsconfig.spec.json" + } + ], + "extends": "../../tsconfig.base.json" +} diff --git a/libs/common-hooks/tsconfig.lib.json b/libs/common-hooks/tsconfig.lib.json new file mode 100644 index 0000000000..1b2b0c12df --- /dev/null +++ b/libs/common-hooks/tsconfig.lib.json @@ -0,0 +1,19 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "../../dist/out-tsc", + "types": ["node", "vite/client"] + }, + "files": ["../../node_modules/@nx/react/typings/cssmodule.d.ts", "../../node_modules/@nx/react/typings/image.d.ts"], + "exclude": [ + "**/*.spec.ts", + "**/*.test.ts", + "**/*.spec.tsx", + "**/*.test.tsx", + "**/*.spec.js", + "**/*.test.js", + "**/*.spec.jsx", + "**/*.test.jsx" + ], + "include": ["**/*.js", "**/*.jsx", "**/*.ts", "**/*.tsx"] +} diff --git a/libs/common-hooks/tsconfig.spec.json b/libs/common-hooks/tsconfig.spec.json new file mode 100644 index 0000000000..26ef046ac5 --- /dev/null +++ b/libs/common-hooks/tsconfig.spec.json @@ -0,0 +1,20 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "../../dist/out-tsc", + "module": "commonjs", + "types": ["jest", "node"] + }, + "include": [ + "jest.config.ts", + "src/**/*.test.ts", + "src/**/*.spec.ts", + "src/**/*.test.tsx", + "src/**/*.spec.tsx", + "src/**/*.test.js", + "src/**/*.spec.js", + "src/**/*.test.jsx", + "src/**/*.spec.jsx", + "src/**/*.d.ts" + ] +} diff --git a/libs/common-hooks/vite.config.ts b/libs/common-hooks/vite.config.ts new file mode 100644 index 0000000000..de5a06d695 --- /dev/null +++ b/libs/common-hooks/vite.config.ts @@ -0,0 +1,49 @@ +/// +import { defineConfig } from 'vite' +import react from '@vitejs/plugin-react-swc' +import viteTsConfigPaths from 'vite-tsconfig-paths' +import dts from 'vite-plugin-dts' +import * as path from 'path' + +export default defineConfig({ + cacheDir: '../../node_modules/.vite/common-hooks', + + plugins: [ + dts({ + entryRoot: 'src', + tsConfigFilePath: path.join(__dirname, 'tsconfig.lib.json'), + skipDiagnostics: true, + }), + react(), + viteTsConfigPaths({ + root: '../../', + }), + ], + + // Uncomment this if you are using workers. + // worker: { + // plugins: [ + // viteTsConfigPaths({ + // root: '../../', + // }), + // ], + // }, + + // Configuration for building your library. + // See: https://vitejs.dev/guide/build.html#library-mode + build: { + lib: { + // Could also be a dictionary or array of multiple entry points. + entry: 'src/index.ts', + name: 'common-hooks', + fileName: 'index', + // Change this to the formats you want to support. + // Don't forget to update your package.json as well. + formats: ['es', 'cjs'], + }, + rollupOptions: { + // External packages that should not be bundled into your library. + external: ['react', 'react-dom', 'react/jsx-runtime'], + }, + }, +}) diff --git a/libs/common-utils/.babelrc b/libs/common-utils/.babelrc new file mode 100644 index 0000000000..ef4889c1ab --- /dev/null +++ b/libs/common-utils/.babelrc @@ -0,0 +1,20 @@ +{ + "presets": [ + [ + "@nx/react/babel", + { + "runtime": "automatic", + "useBuiltIns": "usage" + } + ] + ], + "plugins": [ + [ + "styled-components", + { + "pure": true, + "ssr": true + } + ] + ] +} diff --git a/libs/common-utils/.env b/libs/common-utils/.env new file mode 100644 index 0000000000..8293a86c66 --- /dev/null +++ b/libs/common-utils/.env @@ -0,0 +1,96 @@ +# PRICE ESTIMATION +REACT_APP_PRICE_FEED_GP_ENABLED=true +REACT_APP_PRICE_FEED_PARASWAP_ENABLED=true +REACT_APP_PRICE_FEED_1INCH_ENABLED=true +REACT_APP_PRICE_FEED_0X_ENABLED=true + +# Order book API urls +#REACT_APP_ORDER_BOOK_URLS='{"1":"https://YOUR_HOST","100":"https://YOUR_HOST","5":"https://YOUR_HOST"}' + +# AppData, build yours at https://explorer.cow.fi/appdata +REACT_APP_FULL_APP_DATA_PRODUCTION='{"version":"0.7.0","appCode":"CoW Swap","environment":"production","metadata":{}}' +REACT_APP_FULL_APP_DATA_ENS='{"version":"0.7.0","appCode":"CoW Swap","environment":"ens","metadata":{}}' +REACT_APP_FULL_APP_DATA_BARN='{"version":"0.7.0","appCode":"CoW Swap","environment":"barn","metadata":{}}' +REACT_APP_FULL_APP_DATA_STAGING='{"version":"0.7.0","appCode":"CoW Swap","environment":"staging","metadata":{}}' +REACT_APP_FULL_APP_DATA_PR='{"version":"0.7.0","appCode":"CoW Swap","environment":"pr","metadata":{}}' +REACT_APP_FULL_APP_DATA_DEVELOPMENT='{"version":"0.7.0","appCode":"CoW Swap","environment":"development","metadata":{}}' +REACT_APP_FULL_APP_DATA_LOCAL='{"version":"0.7.0","appCode":"CoW Swap","environment":"local","metadata":{}}' + +# INFURA KEY +REACT_APP_INFURA_KEY=586e7e6b7c7e437aa41f5da496a749f5 + +# Cypress Integration Tests +INTEGRATION_TEST_PRIVATE_KEY= +INTEGRATION_TESTS_INFURA_KEY= + + +# BLOCKNATIVE KEY +# if you need that locally, get the key from blocknative. Access details in shared team vault +#REACT_APP_BLOCKNATIVE_API_KEY= + +# Node +REACT_APP_CHAIN_ID="1" +REACT_APP_SUPPORTED_CHAIN_IDS="1,100,5" +REACT_APP_NETWORK_URL_1=https://mainnet.infura.io/v3/586e7e6b7c7e437aa41f5da496a749f5 +REACT_APP_NETWORK_URL_5=https://goerli.infura.io/v3/586e7e6b7c7e437aa41f5da496a749f5 +REACT_APP_NETWORK_URL_100=https://rpc.gnosischain.com + +# Wallet Connect +# REACT_APP_WALLET_CONNECT_V1_BRIDGE='https://safe-walletconnect.safe.global' + +# Wallets +REACT_APP_PORTIS_ID="c0e2bf01-4b08-4fd5-ac7b-8e26b58cd236" +REACT_APP_FORTMATIC_KEY="pk_live_6AED76CA755EFDC7" +REACT_APP_FORTMATIC_SITE_VERIFICATION="LzjrtdM7hqVJfvvA" + +# Domain regex (to detect environment) +REACT_APP_DOMAIN_REGEX_LOCAL="^(:?localhost:\d{2,5}|(?:127|192)(?:\.[0-9]{1,3}){3})" +REACT_APP_DOMAIN_REGEX_PR="^pr\d+--cowswap\.review|^(swap-dev-git-[\w\d-]+|swap-\w{9}-)cowswap\.vercel\.app" +REACT_APP_DOMAIN_REGEX_DEV="^(cowswap\.dev|dev\.swap\.cow\.fi|swap-develop\.vercel\.app)" +REACT_APP_DOMAIN_REGEX_STAGING="^(cowswap\.staging|staging\.swap\.cow\.fi|swap-staging\.vercel\.app)" +REACT_APP_DOMAIN_REGEX_PROD="^(swap\.cow\.fi|swap-prod\.vercel\.app)$" +REACT_APP_DOMAIN_REGEX_BARN="^(barn\.cow\.fi|swap-barn\.vercel\.app)$" +REACT_APP_DOMAIN_REGEX_ENS="(:?^cowswap\.eth|ipfs)" + +# Path regex (to detect environment) +REACT_APP_PATH_REGEX_ENS="/ipfs" + +# Analytics +#REACT_APP_GOOGLE_ANALYTICS_ID= + +# Sentry +#REACT_APP_SENTRY_DSN='https://' +#REACT_APP_SENTRY_TRACES_SAMPLE_RATE="1.0" +#REACT_APP_SENTRY_AUTH_TOKEN='' + +# API +#REACT_APP_API_URL_PROD_MAINNET= +#REACT_APP_API_URL_PROD_XDAI= +#REACT_APP_API_URL_PROD_GOERLI= +#REACT_APP_API_URL_STAGING_MAINNET= +#REACT_APP_API_URL_STAGING_XDAI= +#REACT_APP_API_URL_STAGING_GOERLI= + +# EXPLORER +#REACT_APP_EXPLORER_URL_DEV= +#REACT_APP_EXPLORER_URL_STAGING= +#REACT_APP_EXPLORER_URL_PROD= +#REACT_APP_EXPLORER_URL_BARN= + +# Enables mock mode (default = true) +REACT_APP_MOCK=true + +# IPFS uploading +REACT_APP_PINATA_API_KEY= +REACT_APP_PINATA_SECRET_API_KEY= + +# Appzi NPS feedback +REACT_APP_FEEDBACK_ENABLED_DEV=false +#REACT_APP_APPZI_FEEDBACK_KEY= +#REACT_APP_APPZI_NPS_KEY= + +# Amplitude +# REACT_APP_AMPLITUDE_KEY= + +# Launch darkly +REACT_APP_LAUNCH_DARKLY_KEY=643681f370ea6d135128b2ce diff --git a/libs/common-utils/.eslintrc.json b/libs/common-utils/.eslintrc.json new file mode 100644 index 0000000000..231aaa5f83 --- /dev/null +++ b/libs/common-utils/.eslintrc.json @@ -0,0 +1,21 @@ +{ + "extends": ["plugin:@nx/react", "../../.eslintrc.json"], + "ignorePatterns": ["!**/*"], + "rules": { + "@typescript-eslint/no-explicit-any": "off" + }, + "overrides": [ + { + "files": ["*.ts", "*.tsx", "*.js", "*.jsx"], + "rules": {} + }, + { + "files": ["*.ts", "*.tsx"], + "rules": {} + }, + { + "files": ["*.js", "*.jsx"], + "rules": {} + } + ] +} diff --git a/libs/common-utils/README.md b/libs/common-utils/README.md new file mode 100644 index 0000000000..1ecf2638af --- /dev/null +++ b/libs/common-utils/README.md @@ -0,0 +1,42 @@ +# Snackbars + +![](./demo.png) + +## Usage + +```tsx +// Add the widget in the root component + +import { SnackbarsWidget } from '@cowprotocol/common-utils' + +export function App() { + return ( + + + + + ) +} +``` + +```tsx +// Use the hook to add a snackbar + +import { useAddSnackbar } from '@cowprotocol/common-utils' + +export function MyComponent() { + const addSnackbar = useAddSnackbar() + + addSnackbar({ + content: {walletName} account changed, + id: 'account-changed', + icon: 'success' + }) +} +``` + +This library was generated with [Nx](https://nx.dev). + +## Running unit tests + +Run `nx test common-utils` to execute the unit tests via [Vitest](https://vitest.dev/). diff --git a/libs/common-utils/jest.config.ts b/libs/common-utils/jest.config.ts new file mode 100644 index 0000000000..c1973b852d --- /dev/null +++ b/libs/common-utils/jest.config.ts @@ -0,0 +1,11 @@ +/* eslint-disable */ +export default { + displayName: 'common-utils', + preset: '../../jest.preset.js', + transform: { + '^(?!.*\\.(js|jsx|ts|tsx|css|json)$)': '@nx/react/plugins/jest', + '^.+\\.[tj]sx?$': ['babel-jest', { presets: ['@nx/react/babel'] }], + }, + moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx'], + coverageDirectory: '../../coverage/libs/common-utils', +} diff --git a/libs/common-utils/package.json b/libs/common-utils/package.json new file mode 100644 index 0000000000..6ff7b85475 --- /dev/null +++ b/libs/common-utils/package.json @@ -0,0 +1,12 @@ +{ + "name": "@cowprotocol/common-utils", + "version": "0.0.1", + "main": "./index.js", + "types": "./index.d.ts", + "exports": { + ".": { + "import": "./index.mjs", + "require": "./index.js" + } + } +} diff --git a/libs/common-utils/project.json b/libs/common-utils/project.json new file mode 100644 index 0000000000..8fd06b9f7b --- /dev/null +++ b/libs/common-utils/project.json @@ -0,0 +1,46 @@ +{ + "name": "@cowprotocol/common-utils", + "$schema": "../../node_modules/nx/schemas/project-schema.json", + "sourceRoot": "libs/common-utils/src", + "projectType": "library", + "tags": [], + "targets": { + "lint": { + "executor": "@nx/linter:eslint", + "outputs": ["{options.outputFile}"], + "options": { + "lintFilePatterns": ["libs/common-utils/**/*.{ts,tsx,js,jsx}"] + } + }, + "build": { + "executor": "@nx/vite:build", + "outputs": ["{options.outputPath}"], + "defaultConfiguration": "production", + "options": { + "outputPath": "dist/libs/common-utils" + }, + "configurations": { + "development": { + "mode": "development" + }, + "production": { + "mode": "production" + } + } + }, + "test": { + "executor": "@nx/jest:jest", + "outputs": ["{workspaceRoot}/coverage/{projectRoot}"], + "options": { + "jestConfig": "libs/common-utils/jest.config.ts", + "passWithNoTests": true + }, + "configurations": { + "ci": { + "ci": true, + "codeCoverage": true + } + } + } + } +} diff --git a/apps/cowswap-frontend/src/utils/amountFormat/README.md b/libs/common-utils/src/amountFormat/README.md similarity index 100% rename from apps/cowswap-frontend/src/utils/amountFormat/README.md rename to libs/common-utils/src/amountFormat/README.md diff --git a/apps/cowswap-frontend/src/utils/amountFormat/index.test.ts b/libs/common-utils/src/amountFormat/index.test.ts similarity index 97% rename from apps/cowswap-frontend/src/utils/amountFormat/index.test.ts rename to libs/common-utils/src/amountFormat/index.test.ts index 6f5343a866..f864a38c27 100644 --- a/apps/cowswap-frontend/src/utils/amountFormat/index.test.ts +++ b/libs/common-utils/src/amountFormat/index.test.ts @@ -1,7 +1,6 @@ import { CurrencyAmount, Percent } from '@uniswap/sdk-core' -import { USDC_GNOSIS_CHAIN } from 'legacy/utils/gnosis_chain/constants' -import { DAI_GOERLI, USDC_GOERLI } from 'legacy/utils/goerli/constants' +import { USDC_GNOSIS_CHAIN, DAI_GOERLI, USDC_GOERLI } from '@cowprotocol/common-const' import { formatAmountWithPrecision, formatFiatAmount, formatPercent, formatTokenAmount } from './index' diff --git a/apps/cowswap-frontend/src/utils/amountFormat/index.ts b/libs/common-utils/src/amountFormat/index.ts similarity index 89% rename from apps/cowswap-frontend/src/utils/amountFormat/index.ts rename to libs/common-utils/src/amountFormat/index.ts index 457f0d8759..093b89ac36 100644 --- a/apps/cowswap-frontend/src/utils/amountFormat/index.ts +++ b/libs/common-utils/src/amountFormat/index.ts @@ -1,16 +1,20 @@ import { Currency, CurrencyAmount, Percent, Rounding } from '@uniswap/sdk-core' import JSBI from 'jsbi' -import { FractionLike, Nullish } from 'types' +import { FractionLike, Nullish } from '../types' -import { AMOUNT_PRECISION, FIAT_PRECISION, PERCENTAGE_PRECISION, ZERO_FRACTION } from 'legacy/constants' -import { maxAmountSpend } from 'legacy/utils/maxAmountSpend' - -import { INTL_NUMBER_FORMAT } from 'common/constants/intl' -import { FractionUtils } from 'utils/fractionUtils' -import { trimTrailingZeros } from 'utils/trimTrailingZeros' +import { + AMOUNT_PRECISION, + FIAT_PRECISION, + PERCENTAGE_PRECISION, + ZERO_FRACTION, + INTL_NUMBER_FORMAT, +} from '@cowprotocol/common-const' import { getPrecisionForAmount, getSuffixForAmount, lessThanPrecisionSymbol, trimHugeAmounts } from './utils' +import { trimTrailingZeros } from '../trimTrailingZeros' +import { FractionUtils } from '../fractionUtils' +import { maxAmountSpend } from '../maxAmountSpend' export function formatFiatAmount(amount: Nullish): string { return formatAmountWithPrecision(amount, FIAT_PRECISION) diff --git a/apps/cowswap-frontend/src/utils/amountFormat/utils.ts b/libs/common-utils/src/amountFormat/utils.ts similarity index 94% rename from apps/cowswap-frontend/src/utils/amountFormat/utils.ts rename to libs/common-utils/src/amountFormat/utils.ts index 0b9ac4554e..e5258df037 100644 --- a/apps/cowswap-frontend/src/utils/amountFormat/utils.ts +++ b/libs/common-utils/src/amountFormat/utils.ts @@ -1,9 +1,9 @@ import { CurrencyAmount, Fraction } from '@uniswap/sdk-core' import JSBI from 'jsbi' -import { FractionLike, Nullish } from 'types' +import { FractionLike, Nullish } from '../types' -import { FractionUtils } from 'utils/fractionUtils' +import { FractionUtils } from '../fractionUtils' const ONE = JSBI.BigInt(1) const HUNDRED_K = JSBI.BigInt(100_000) diff --git a/apps/cowswap-frontend/src/legacy/utils/anonymizeLink.test.ts b/libs/common-utils/src/anonymizeLink.test.ts similarity index 100% rename from apps/cowswap-frontend/src/legacy/utils/anonymizeLink.test.ts rename to libs/common-utils/src/anonymizeLink.test.ts diff --git a/apps/cowswap-frontend/src/legacy/utils/anonymizeLink.ts b/libs/common-utils/src/anonymizeLink.ts similarity index 100% rename from apps/cowswap-frontend/src/legacy/utils/anonymizeLink.ts rename to libs/common-utils/src/anonymizeLink.ts diff --git a/apps/cowswap-frontend/src/legacy/utils/appzi.ts b/libs/common-utils/src/appzi.ts similarity index 96% rename from apps/cowswap-frontend/src/legacy/utils/appzi.ts rename to libs/common-utils/src/appzi.ts index 1fde05ac09..83795f8590 100644 --- a/apps/cowswap-frontend/src/legacy/utils/appzi.ts +++ b/libs/common-utils/src/appzi.ts @@ -1,10 +1,9 @@ import ms from 'ms.macro' import ReactAppzi from 'react-appzi' -import { environmentName, isProdLike } from 'legacy/utils/environments' -import { userAgent, majorBrowserVersion, isImTokenBrowser } from 'legacy/utils/userAgent' - import EventEmitter from 'events' +import { isImTokenBrowser, majorBrowserVersion, userAgent } from './userAgent' +import { environmentName, isProdLike } from './environments' // Metamask IOS app uses a version from July 2019 which causes problems in appZi const OLD_CHROME_FROM_METAMASK_IOS_APP = 76 diff --git a/apps/cowswap-frontend/src/utils/areFractionsEqual.ts b/libs/common-utils/src/areFractionsEqual.ts similarity index 100% rename from apps/cowswap-frontend/src/utils/areFractionsEqual.ts rename to libs/common-utils/src/areFractionsEqual.ts diff --git a/apps/cowswap-frontend/src/legacy/utils/async.ts b/libs/common-utils/src/async.ts similarity index 100% rename from apps/cowswap-frontend/src/legacy/utils/async.ts rename to libs/common-utils/src/async.ts diff --git a/apps/cowswap-frontend/src/legacy/utils/blocks.ts b/libs/common-utils/src/blocks.ts similarity index 100% rename from apps/cowswap-frontend/src/legacy/utils/blocks.ts rename to libs/common-utils/src/blocks.ts diff --git a/apps/cowswap-frontend/src/modules/utils/orderUtils/buildPriceFromCurrencyAmounts.ts b/libs/common-utils/src/buildPriceFromCurrencyAmounts.ts similarity index 91% rename from apps/cowswap-frontend/src/modules/utils/orderUtils/buildPriceFromCurrencyAmounts.ts rename to libs/common-utils/src/buildPriceFromCurrencyAmounts.ts index 6b3e3e9e72..c25068e3cb 100644 --- a/apps/cowswap-frontend/src/modules/utils/orderUtils/buildPriceFromCurrencyAmounts.ts +++ b/libs/common-utils/src/buildPriceFromCurrencyAmounts.ts @@ -1,8 +1,7 @@ import { Currency, CurrencyAmount, Price } from '@uniswap/sdk-core' -import { Nullish } from 'types' - -import { isFractionFalsy } from 'utils/isFractionFalsy' +import { Nullish } from './types' +import { isFractionFalsy } from './isFractionFalsy' export function buildPriceFromCurrencyAmounts( inputCurrencyAmount: CurrencyAmount, diff --git a/apps/cowswap-frontend/src/legacy/utils/calculateGasMargin.test.ts b/libs/common-utils/src/calculateGasMargin.test.ts similarity index 100% rename from apps/cowswap-frontend/src/legacy/utils/calculateGasMargin.test.ts rename to libs/common-utils/src/calculateGasMargin.test.ts diff --git a/apps/cowswap-frontend/src/legacy/utils/calculateGasMargin.ts b/libs/common-utils/src/calculateGasMargin.ts similarity index 100% rename from apps/cowswap-frontend/src/legacy/utils/calculateGasMargin.ts rename to libs/common-utils/src/calculateGasMargin.ts diff --git a/apps/cowswap-frontend/src/legacy/utils/calculatePriceImpact.test.ts b/libs/common-utils/src/calculatePriceImpact.test.ts similarity index 100% rename from apps/cowswap-frontend/src/legacy/utils/calculatePriceImpact.test.ts rename to libs/common-utils/src/calculatePriceImpact.test.ts diff --git a/apps/cowswap-frontend/src/legacy/utils/calculateSlippageAmount.test.ts b/libs/common-utils/src/calculateSlippageAmount.test.ts similarity index 100% rename from apps/cowswap-frontend/src/legacy/utils/calculateSlippageAmount.test.ts rename to libs/common-utils/src/calculateSlippageAmount.test.ts diff --git a/apps/cowswap-frontend/src/legacy/utils/calculateSlippageAmount.ts b/libs/common-utils/src/calculateSlippageAmount.ts similarity index 74% rename from apps/cowswap-frontend/src/legacy/utils/calculateSlippageAmount.ts rename to libs/common-utils/src/calculateSlippageAmount.ts index 87588fc006..4ea0d01be8 100644 --- a/apps/cowswap-frontend/src/legacy/utils/calculateSlippageAmount.ts +++ b/libs/common-utils/src/calculateSlippageAmount.ts @@ -1,8 +1,8 @@ -import { Currency, CurrencyAmount, Percent } from '@uniswap/sdk-core' +import { Currency, CurrencyAmount, Fraction, Percent } from '@uniswap/sdk-core' import JSBI from 'jsbi' -import { ONE_FRACTION } from 'legacy/constants/misc' +const ONE_FRACTION = new Fraction(1, 1) export function calculateSlippageAmount(value: CurrencyAmount, slippage: Percent): [JSBI, JSBI] { if (slippage.lessThan(0) || slippage.greaterThan(ONE_FRACTION)) throw new Error('Unexpected slippage') diff --git a/libs/common-utils/src/capitalizeFirstLetter.ts b/libs/common-utils/src/capitalizeFirstLetter.ts new file mode 100644 index 0000000000..263cb0ec2e --- /dev/null +++ b/libs/common-utils/src/capitalizeFirstLetter.ts @@ -0,0 +1,5 @@ +export function capitalizeFirstLetter(str: string): string { + if (!str) return str + + return str.charAt(0).toUpperCase() + str.slice(1) +} diff --git a/apps/cowswap-frontend/src/lib/utils/contenthashToUri.ts b/libs/common-utils/src/contenthashToUri.ts similarity index 94% rename from apps/cowswap-frontend/src/lib/utils/contenthashToUri.ts rename to libs/common-utils/src/contenthashToUri.ts index 2c667f108f..23eb13e19a 100644 --- a/apps/cowswap-frontend/src/lib/utils/contenthashToUri.ts +++ b/libs/common-utils/src/contenthashToUri.ts @@ -18,7 +18,7 @@ const UTF_8_DECODER = new TextDecoder('utf-8') * Returns the URI representation of the content hash for supported codecs * @param contenthash to decode */ -export default function contenthashToUri(contenthash: string): string { +export function contenthashToUri(contenthash: string): string { const data = hexToUint8Array(contenthash) const codec = getNameFromData(data) switch (codec) { diff --git a/apps/cowswap-frontend/src/utils/currencyAmountToTokenAmount.ts b/libs/common-utils/src/currencyAmountToTokenAmount.ts similarity index 64% rename from apps/cowswap-frontend/src/utils/currencyAmountToTokenAmount.ts rename to libs/common-utils/src/currencyAmountToTokenAmount.ts index 7193c4943b..d52376d533 100644 --- a/apps/cowswap-frontend/src/utils/currencyAmountToTokenAmount.ts +++ b/libs/common-utils/src/currencyAmountToTokenAmount.ts @@ -1,8 +1,8 @@ import { Currency, CurrencyAmount, Token } from '@uniswap/sdk-core' -import { Nullish } from 'types' - -export function currencyAmountToTokenAmount(amount: Nullish>): CurrencyAmount | null { +export function currencyAmountToTokenAmount( + amount: CurrencyAmount | null | undefined +): CurrencyAmount | null { if (!amount) return null if (amount.currency.isToken) return amount as CurrencyAmount diff --git a/apps/cowswap-frontend/src/legacy/utils/currencyId.ts b/libs/common-utils/src/currencyId.ts similarity index 100% rename from apps/cowswap-frontend/src/legacy/utils/currencyId.ts rename to libs/common-utils/src/currencyId.ts diff --git a/apps/cowswap-frontend/src/utils/deepEqual.ts b/libs/common-utils/src/deepEqual.ts similarity index 100% rename from apps/cowswap-frontend/src/utils/deepEqual.ts rename to libs/common-utils/src/deepEqual.ts diff --git a/apps/cowswap-frontend/src/legacy/utils/deterministicHash.test.ts b/libs/common-utils/src/deterministicHash.test.ts similarity index 100% rename from apps/cowswap-frontend/src/legacy/utils/deterministicHash.test.ts rename to libs/common-utils/src/deterministicHash.test.ts diff --git a/apps/cowswap-frontend/src/legacy/utils/deterministicHash.ts b/libs/common-utils/src/deterministicHash.ts similarity index 100% rename from apps/cowswap-frontend/src/legacy/utils/deterministicHash.ts rename to libs/common-utils/src/deterministicHash.ts diff --git a/apps/cowswap-frontend/src/utils/displayTime.tsx b/libs/common-utils/src/displayTime.tsx similarity index 100% rename from apps/cowswap-frontend/src/utils/displayTime.tsx rename to libs/common-utils/src/displayTime.tsx diff --git a/apps/cowswap-frontend/src/utils/doesTokenMatchSymbolOrAddress.ts b/libs/common-utils/src/doesTokenMatchSymbolOrAddress.ts similarity index 100% rename from apps/cowswap-frontend/src/utils/doesTokenMatchSymbolOrAddress.ts rename to libs/common-utils/src/doesTokenMatchSymbolOrAddress.ts diff --git a/apps/cowswap-frontend/src/legacy/utils/env.ts b/libs/common-utils/src/env.ts similarity index 100% rename from apps/cowswap-frontend/src/legacy/utils/env.ts rename to libs/common-utils/src/env.ts diff --git a/apps/cowswap-frontend/src/legacy/utils/environments.test.ts b/libs/common-utils/src/environments.test.ts similarity index 100% rename from apps/cowswap-frontend/src/legacy/utils/environments.test.ts rename to libs/common-utils/src/environments.test.ts diff --git a/apps/cowswap-frontend/src/legacy/utils/environments.ts b/libs/common-utils/src/environments.ts similarity index 100% rename from apps/cowswap-frontend/src/legacy/utils/environments.ts rename to libs/common-utils/src/environments.ts diff --git a/apps/cowswap-frontend/src/legacy/utils/explorer.ts b/libs/common-utils/src/explorer.ts similarity index 93% rename from apps/cowswap-frontend/src/legacy/utils/explorer.ts rename to libs/common-utils/src/explorer.ts index cf68f39964..f93fd71b6b 100644 --- a/apps/cowswap-frontend/src/legacy/utils/explorer.ts +++ b/libs/common-utils/src/explorer.ts @@ -1,6 +1,4 @@ -import { SupportedChainId as ChainId } from '@cowprotocol/cow-sdk' - -import { OrderID } from 'api/gnosisProtocol' +import { SupportedChainId as ChainId, UID } from '@cowprotocol/cow-sdk' import { isLocal, isDev, isPr, isStaging, isBarn } from './environments' @@ -36,7 +34,7 @@ export function getExplorerBaseUrl(chainId: ChainId): string { } } -export function getExplorerOrderLink(chainId: ChainId, orderId: OrderID): string { +export function getExplorerOrderLink(chainId: ChainId, orderId: UID): string { const baseUrl = getExplorerBaseUrl(chainId) return baseUrl + `/orders/${orderId}` diff --git a/apps/cowswap-frontend/src/utils/featureFlags.ts b/libs/common-utils/src/featureFlags.ts similarity index 88% rename from apps/cowswap-frontend/src/utils/featureFlags.ts rename to libs/common-utils/src/featureFlags.ts index 11d570c7a9..5eab21a3a1 100644 --- a/apps/cowswap-frontend/src/utils/featureFlags.ts +++ b/libs/common-utils/src/featureFlags.ts @@ -1,7 +1,8 @@ -import { isProdLike } from 'legacy/utils/environments' +import { isProdLike } from './environments' // We can define here some flags to be enabled while we develop // TODO: update this before the deployment + const ENABLED_FOR_DEVELOP: string[] = [] export class FeatureFlag { diff --git a/apps/cowswap-frontend/src/utils/format.ts b/libs/common-utils/src/format.ts similarity index 100% rename from apps/cowswap-frontend/src/utils/format.ts rename to libs/common-utils/src/format.ts diff --git a/apps/cowswap-frontend/src/legacy/utils/formatCurrencyAmount.ts b/libs/common-utils/src/formatCurrencyAmount.ts similarity index 88% rename from apps/cowswap-frontend/src/legacy/utils/formatCurrencyAmount.ts rename to libs/common-utils/src/formatCurrencyAmount.ts index ededc1e331..14411e5b7a 100644 --- a/apps/cowswap-frontend/src/legacy/utils/formatCurrencyAmount.ts +++ b/libs/common-utils/src/formatCurrencyAmount.ts @@ -2,9 +2,9 @@ import { Currency, CurrencyAmount, Fraction, Price } from '@uniswap/sdk-core' import JSBI from 'jsbi' -import { DEFAULT_LOCALE, SupportedLocale } from 'legacy/constants/locales' +import { DEFAULT_LOCALE, SupportedLocale } from '@cowprotocol/common-const' -import formatLocaleNumber from 'lib/utils/formatLocaleNumber' +import formatLocaleNumber from './formatLocaleNumber' export function formatCurrencyAmount( amount: CurrencyAmount | undefined, diff --git a/apps/cowswap-frontend/src/lib/utils/formatLocaleNumber.test.ts b/libs/common-utils/src/formatLocaleNumber.test.ts similarity index 87% rename from apps/cowswap-frontend/src/lib/utils/formatLocaleNumber.test.ts rename to libs/common-utils/src/formatLocaleNumber.test.ts index 7640446f3f..2c7ef66907 100644 --- a/apps/cowswap-frontend/src/lib/utils/formatLocaleNumber.test.ts +++ b/libs/common-utils/src/formatLocaleNumber.test.ts @@ -1,4 +1,4 @@ -import { SUPPORTED_LOCALES, SupportedLocale } from 'legacy/constants/locales' +import { SUPPORTED_LOCALES, SupportedLocale } from '@cowprotocol/common-const' import formatLocaleNumber from './formatLocaleNumber' @@ -15,6 +15,7 @@ function expectedOutput(l: SupportedLocale): string { case 'zh-TW': return `4,000,000.123` case 'fr-FR': + // eslint-disable-next-line no-irregular-whitespace return `4 000 000,123` case 'ar-SA': return `٤٬٠٠٠٬٠٠٠٫١٢٣` @@ -28,6 +29,7 @@ function expectedOutput(l: SupportedLocale): string { case 'ru-RU': case 'sv-SE': case 'uk-UA': + // eslint-disable-next-line no-irregular-whitespace return `4 000 000,123` case 'ca-ES': case 'da-DK': diff --git a/apps/cowswap-frontend/src/lib/utils/formatLocaleNumber.ts b/libs/common-utils/src/formatLocaleNumber.ts similarity index 94% rename from apps/cowswap-frontend/src/lib/utils/formatLocaleNumber.ts rename to libs/common-utils/src/formatLocaleNumber.ts index b8f8b5cbac..9cc88b8f18 100644 --- a/apps/cowswap-frontend/src/lib/utils/formatLocaleNumber.ts +++ b/libs/common-utils/src/formatLocaleNumber.ts @@ -1,6 +1,6 @@ import { Currency, CurrencyAmount, Price } from '@uniswap/sdk-core' -import { DEFAULT_LOCALE, SUPPORTED_LOCALES } from 'legacy/constants/locales' +import { DEFAULT_LOCALE, SUPPORTED_LOCALES } from '@cowprotocol/common-const' interface FormatLocaleNumberArgs { number: CurrencyAmount | Price | number diff --git a/apps/cowswap-frontend/src/utils/fractionUtils.test.ts b/libs/common-utils/src/fractionUtils.test.ts similarity index 100% rename from apps/cowswap-frontend/src/utils/fractionUtils.test.ts rename to libs/common-utils/src/fractionUtils.test.ts diff --git a/apps/cowswap-frontend/src/utils/fractionUtils.ts b/libs/common-utils/src/fractionUtils.ts similarity index 80% rename from apps/cowswap-frontend/src/utils/fractionUtils.ts rename to libs/common-utils/src/fractionUtils.ts index b4f3ee6d0c..f98270b611 100644 --- a/apps/cowswap-frontend/src/utils/fractionUtils.ts +++ b/libs/common-utils/src/fractionUtils.ts @@ -2,12 +2,10 @@ import { BigintIsh, Currency, CurrencyAmount, Fraction, Price, Rounding, Token } import { BigNumber } from 'bignumber.js' import JSBI from 'jsbi' -import { FractionLike, Nullish } from 'types' +import { FractionLike, Nullish } from './types' -import { FULL_PRICE_PRECISION } from 'legacy/constants' - -import { adjustDecimalsAtoms } from 'utils/orderUtils/calculateAmountForRate' -import { trimTrailingZeros } from 'utils/trimTrailingZeros' +import { FULL_PRICE_PRECISION } from '@cowprotocol/common-const' +import { trimTrailingZeros } from './trimTrailingZeros' export class FractionUtils { static serializeFractionToJSON(fraction: Nullish): string { @@ -82,7 +80,11 @@ export class FractionUtils { */ static toPrice(fraction: Fraction, inputCurrency: Token, outputCurrency: Token): Price { // Note that here the fraction shows the price in units (for both tokens). The Price class is decimals aware, so we need to adapt it - const adjustedFraction = adjustDecimalsAtoms(fraction, inputCurrency.decimals, outputCurrency.decimals) + const adjustedFraction = FractionUtils.adjustDecimalsAtoms( + fraction, + inputCurrency.decimals, + outputCurrency.decimals + ) return new Price({ quoteAmount: CurrencyAmount.fromRawAmount(outputCurrency, adjustedFraction.numerator), @@ -100,13 +102,28 @@ export class FractionUtils { * @returns */ static fromPrice(price: Price): Fraction { - return adjustDecimalsAtoms( + return FractionUtils.adjustDecimalsAtoms( new Fraction(price.numerator, price.denominator), price.quoteCurrency.decimals, price.baseCurrency.decimals ) } + /** + * Adjust a fraction defined in units for both token to consider the decimals. + * For example, a fraction like 1.1/1 representing the price of USDC, DAI in units, will be turned into + * 1.1/1000000000000 in atoms + */ + static adjustDecimalsAtoms(value: Fraction, decimalsA: number, decimalsB: number): Fraction { + if (decimalsA === decimalsB) { + return value + } + + const decimalsShift = JSBI.BigInt(JSBI.exponentiate(JSBI.BigInt(10), JSBI.BigInt(Math.abs(decimalsA - decimalsB)))) + + return decimalsA < decimalsB ? value.multiply(decimalsShift) : value.divide(decimalsShift) + } + /** * Converts a number into a Fraction * diff --git a/apps/cowswap-frontend/src/utils/genericPropsChecker.test.ts b/libs/common-utils/src/genericPropsChecker.test.ts similarity index 100% rename from apps/cowswap-frontend/src/utils/genericPropsChecker.test.ts rename to libs/common-utils/src/genericPropsChecker.test.ts diff --git a/apps/cowswap-frontend/src/utils/genericPropsChecker.ts b/libs/common-utils/src/genericPropsChecker.ts similarity index 100% rename from apps/cowswap-frontend/src/utils/genericPropsChecker.ts rename to libs/common-utils/src/genericPropsChecker.ts diff --git a/apps/cowswap-frontend/src/utils/getAddress.ts b/libs/common-utils/src/getAddress.ts similarity index 54% rename from apps/cowswap-frontend/src/utils/getAddress.ts rename to libs/common-utils/src/getAddress.ts index a29ff61f43..753efa6c2f 100644 --- a/apps/cowswap-frontend/src/utils/getAddress.ts +++ b/libs/common-utils/src/getAddress.ts @@ -1,11 +1,9 @@ import { Currency } from '@uniswap/sdk-core' -import { WrappedTokenInfo } from 'legacy/state/lists/wrappedTokenInfo' - export function getAddress(currency: Currency | null | undefined): string | null { if (!currency || currency.isNative) { return null } - return currency?.address || (currency as WrappedTokenInfo)?.tokenInfo?.address || null + return currency?.address || (currency as { tokenInfo?: { address?: string } })?.tokenInfo?.address || null } diff --git a/apps/cowswap-frontend/src/utils/getCurrentChainIdFromUrl.test.ts b/libs/common-utils/src/getCurrentChainIdFromUrl.test.ts similarity index 100% rename from apps/cowswap-frontend/src/utils/getCurrentChainIdFromUrl.test.ts rename to libs/common-utils/src/getCurrentChainIdFromUrl.test.ts diff --git a/apps/cowswap-frontend/src/utils/getCurrentChainIdFromUrl.ts b/libs/common-utils/src/getCurrentChainIdFromUrl.ts similarity index 100% rename from apps/cowswap-frontend/src/utils/getCurrentChainIdFromUrl.ts rename to libs/common-utils/src/getCurrentChainIdFromUrl.ts diff --git a/apps/cowswap-frontend/src/utils/getDoesMessageIncludeToken.ts b/libs/common-utils/src/getDoesMessageIncludeToken.ts similarity index 100% rename from apps/cowswap-frontend/src/utils/getDoesMessageIncludeToken.ts rename to libs/common-utils/src/getDoesMessageIncludeToken.ts diff --git a/apps/cowswap-frontend/src/legacy/utils/getExplorerLink.test.ts b/libs/common-utils/src/getExplorerLink.test.ts similarity index 100% rename from apps/cowswap-frontend/src/legacy/utils/getExplorerLink.test.ts rename to libs/common-utils/src/getExplorerLink.test.ts diff --git a/apps/cowswap-frontend/src/legacy/utils/getExplorerLink.ts b/libs/common-utils/src/getExplorerLink.ts similarity index 100% rename from apps/cowswap-frontend/src/legacy/utils/getExplorerLink.ts rename to libs/common-utils/src/getExplorerLink.ts diff --git a/apps/cowswap-frontend/src/utils/getIntOrFloat.ts b/libs/common-utils/src/getIntOrFloat.ts similarity index 100% rename from apps/cowswap-frontend/src/utils/getIntOrFloat.ts rename to libs/common-utils/src/getIntOrFloat.ts diff --git a/apps/cowswap-frontend/src/utils/getIsNativeToken.ts b/libs/common-utils/src/getIsNativeToken.ts similarity index 83% rename from apps/cowswap-frontend/src/utils/getIsNativeToken.ts rename to libs/common-utils/src/getIsNativeToken.ts index 75f380a12e..e6da863fcd 100644 --- a/apps/cowswap-frontend/src/utils/getIsNativeToken.ts +++ b/libs/common-utils/src/getIsNativeToken.ts @@ -1,6 +1,6 @@ import { SupportedChainId } from '@cowprotocol/cow-sdk' -import { NATIVE_CURRENCY_BUY_TOKEN } from 'legacy/constants' +import { NATIVE_CURRENCY_BUY_TOKEN } from '@cowprotocol/common-const' import { doesTokenMatchSymbolOrAddress } from './doesTokenMatchSymbolOrAddress' diff --git a/apps/cowswap-frontend/src/utils/getIsWrapOrUnwrap.ts b/libs/common-utils/src/getIsWrapOrUnwrap.ts similarity index 84% rename from apps/cowswap-frontend/src/utils/getIsWrapOrUnwrap.ts rename to libs/common-utils/src/getIsWrapOrUnwrap.ts index 11305d728f..5e61384504 100644 --- a/apps/cowswap-frontend/src/utils/getIsWrapOrUnwrap.ts +++ b/libs/common-utils/src/getIsWrapOrUnwrap.ts @@ -1,11 +1,10 @@ import { SupportedChainId } from '@cowprotocol/cow-sdk' -import { NATIVE_CURRENCY_BUY_TOKEN } from 'legacy/constants' -import { WRAPPED_NATIVE_CURRENCY } from 'legacy/constants/tokens' +import { NATIVE_CURRENCY_BUY_TOKEN, WRAPPED_NATIVE_CURRENCY } from '@cowprotocol/common-const' import { doesTokenMatchSymbolOrAddress } from './doesTokenMatchSymbolOrAddress' -import { Nullish } from '../types' +import { Nullish } from './types' export function getIsWrapOrUnwrap( chainId: SupportedChainId, diff --git a/apps/cowswap-frontend/src/utils/getQuoteUnsupportedToken.ts b/libs/common-utils/src/getQuoteUnsupportedToken.ts similarity index 100% rename from apps/cowswap-frontend/src/utils/getQuoteUnsupportedToken.ts rename to libs/common-utils/src/getQuoteUnsupportedToken.ts diff --git a/apps/cowswap-frontend/src/utils/getRandomInt.ts b/libs/common-utils/src/getRandomInt.ts similarity index 100% rename from apps/cowswap-frontend/src/utils/getRandomInt.ts rename to libs/common-utils/src/getRandomInt.ts diff --git a/apps/cowswap-frontend/src/legacy/utils/getUserAgent.ts b/libs/common-utils/src/getUserAgent.ts similarity index 100% rename from apps/cowswap-frontend/src/legacy/utils/getUserAgent.ts rename to libs/common-utils/src/getUserAgent.ts diff --git a/libs/common-utils/src/index.ts b/libs/common-utils/src/index.ts new file mode 100644 index 0000000000..ef8fd97326 --- /dev/null +++ b/libs/common-utils/src/index.ts @@ -0,0 +1,54 @@ +export * from './env' +export * from './environments' +export * from './legacyAddressUtils' +export * from './format' +export * from './tokens' +export * from './misc' +export * from './time' +export * from './isZero' +export * from './retry' +export * from './request' +export * from './async' +export * from './uriToHttp' +export * from './contenthashToUri' +export * from './parseENSAddress' +export * from './safeNamehash' +export * from './calculateGasMargin' +export * from './doesTokenMatchSymbolOrAddress' +export * from './amountFormat/index' +export * from './explorer' +export * from './getQuoteUnsupportedToken' +export * from './buildPriceFromCurrencyAmounts' +export * from './tryParseCurrencyAmount' +export * from './resolveENSContentHash' +export * from './fractionUtils' +export * from './getCurrentChainIdFromUrl' +export * from './node' +export * from './isInjectedWidget' +export * from './toggleBodyClass' +export * from './featureFlags' +export * from './currencyId' +export * from './isFractionFalsy' +export * from './getAddress' +export * from './tooltips' +export * from './genericPropsChecker' +export * from './sound' +export * from './userAgent' +export * from './getExplorerLink' +export * from './getIsNativeToken' +export * from './getIsWrapOrUnwrap' +export * from './logging' +export * from './getIntOrFloat' +export * from './appzi' +export * from './anonymizeLink' +export * from './deepEqual' +export * from './rawToTokenAmount' +export * from './areFractionsEqual' +export * from './currencyAmountToTokenAmount' +export * from './localStorage' +export * from './getRandomInt' +export * from './isEnoughAmount' +export * from './tryParseFractionalAmount' +export * from './maxAmountSpend' +export * from './capitalizeFirstLetter' +export * from './jotai/atomWithPartialUpdate' diff --git a/apps/cowswap-frontend/src/utils/isEnoughAmount.ts b/libs/common-utils/src/isEnoughAmount.ts similarity index 100% rename from apps/cowswap-frontend/src/utils/isEnoughAmount.ts rename to libs/common-utils/src/isEnoughAmount.ts diff --git a/apps/cowswap-frontend/src/utils/isFractionFalsy.ts b/libs/common-utils/src/isFractionFalsy.ts similarity index 100% rename from apps/cowswap-frontend/src/utils/isFractionFalsy.ts rename to libs/common-utils/src/isFractionFalsy.ts diff --git a/apps/cowswap-frontend/src/common/utils/isInjectedWidget.ts b/libs/common-utils/src/isInjectedWidget.ts similarity index 100% rename from apps/cowswap-frontend/src/common/utils/isInjectedWidget.ts rename to libs/common-utils/src/isInjectedWidget.ts diff --git a/apps/cowswap-frontend/src/utils/isNotNullish.ts b/libs/common-utils/src/isNotNullish.ts similarity index 77% rename from apps/cowswap-frontend/src/utils/isNotNullish.ts rename to libs/common-utils/src/isNotNullish.ts index 4bbccdbd58..c016871db6 100644 --- a/apps/cowswap-frontend/src/utils/isNotNullish.ts +++ b/libs/common-utils/src/isNotNullish.ts @@ -1,4 +1,4 @@ -import { Nullish } from 'types' +import { Nullish } from './types' export function isNotNullish(input: Nullish): input is T { return input !== null && input !== undefined diff --git a/apps/cowswap-frontend/src/legacy/utils/isZero.ts b/libs/common-utils/src/isZero.ts similarity index 68% rename from apps/cowswap-frontend/src/legacy/utils/isZero.ts rename to libs/common-utils/src/isZero.ts index 1b84e67560..ca6d44a162 100644 --- a/apps/cowswap-frontend/src/legacy/utils/isZero.ts +++ b/libs/common-utils/src/isZero.ts @@ -2,6 +2,6 @@ * Returns true if the string value is zero in hex * @param hexNumberString */ -export default function isZero(hexNumberString: string) { +export function isZero(hexNumberString: string) { return /^0x0*$/.test(hexNumberString) } diff --git a/apps/cowswap-frontend/src/utils/jotai/atomWithPartialUpdate.ts b/libs/common-utils/src/jotai/atomWithPartialUpdate.ts similarity index 82% rename from apps/cowswap-frontend/src/utils/jotai/atomWithPartialUpdate.ts rename to libs/common-utils/src/jotai/atomWithPartialUpdate.ts index ae0ac9c5ad..6b3fab7bed 100644 --- a/apps/cowswap-frontend/src/utils/jotai/atomWithPartialUpdate.ts +++ b/libs/common-utils/src/jotai/atomWithPartialUpdate.ts @@ -1,5 +1,4 @@ -import { PrimitiveAtom, WritableAtom } from 'jotai' -import { atom } from 'jotai/index' +import { atom, PrimitiveAtom, WritableAtom } from 'jotai' export function atomWithPartialUpdate(anyAtom: PrimitiveAtom): { atom: typeof anyAtom diff --git a/apps/cowswap-frontend/src/legacy/utils/index.test.ts b/libs/common-utils/src/legacyAddressUtils.test.ts similarity index 89% rename from apps/cowswap-frontend/src/legacy/utils/index.test.ts rename to libs/common-utils/src/legacyAddressUtils.test.ts index 45b4642f70..890cf964f2 100644 --- a/apps/cowswap-frontend/src/legacy/utils/index.test.ts +++ b/libs/common-utils/src/legacyAddressUtils.test.ts @@ -1,13 +1,10 @@ -import { isAddress, shortenAddress } from '.' +import { isAddress, shortenAddress } from './legacyAddressUtils' describe('utils', () => { describe('#isAddress', () => { it('returns false if not', () => { expect(isAddress('')).toBe(false) expect(isAddress('0x0000')).toBe(false) - expect(isAddress(1)).toBe(false) - expect(isAddress({})).toBe(false) - expect(isAddress(undefined)).toBe(false) }) it('returns the checksummed address', () => { diff --git a/apps/cowswap-frontend/src/legacy/utils/index.ts b/libs/common-utils/src/legacyAddressUtils.ts similarity index 90% rename from apps/cowswap-frontend/src/legacy/utils/index.ts rename to libs/common-utils/src/legacyAddressUtils.ts index 176479f1e5..b5e706ee73 100644 --- a/apps/cowswap-frontend/src/legacy/utils/index.ts +++ b/libs/common-utils/src/legacyAddressUtils.ts @@ -1,16 +1,16 @@ import { SupportedChainId as ChainId } from '@cowprotocol/cow-sdk' import { getAddress } from '@ethersproject/address' import { AddressZero } from '@ethersproject/constants' -import { Contract } from '@ethersproject/contracts' +import { Contract, ContractInterface } from '@ethersproject/contracts' import { JsonRpcProvider, JsonRpcSigner } from '@ethersproject/providers' +import { getExplorerOrderLink } from './explorer' -import { ORDER_ID_SHORT_LENGTH } from 'legacy/constants' -import { getExplorerOrderLink } from 'legacy/utils/explorer' +const ORDER_ID_SHORT_LENGTH = 8 // returns the checksummed address if the address is valid, otherwise returns false -export function isAddress(value: any): string | false { +export function isAddress(value: string | undefined | null): string | false { try { - return getAddress(value) + return getAddress(value as never) } catch { return false } @@ -36,12 +36,17 @@ export function getProviderOrSigner(provider: JsonRpcProvider, account?: string) } // account is optional -export function getContract(address: string, ABI: any, provider: JsonRpcProvider, account?: string): Contract { +export function getContract( + address: string, + ABI: ContractInterface, + provider: JsonRpcProvider, + account?: string +): Contract { if (!isAddress(address) || address === AddressZero) { throw Error(`Invalid 'address' parameter '${address}'.`) } - return new Contract(address, ABI, getProviderOrSigner(provider, account) as any) + return new Contract(address, ABI, getProviderOrSigner(provider, account)) } export function escapeRegExp(string: string): string { diff --git a/apps/cowswap-frontend/src/utils/localStorage.ts b/libs/common-utils/src/localStorage.ts similarity index 100% rename from apps/cowswap-frontend/src/utils/localStorage.ts rename to libs/common-utils/src/localStorage.ts diff --git a/apps/cowswap-frontend/src/legacy/utils/logging/index.ts b/libs/common-utils/src/logging/index.ts similarity index 90% rename from apps/cowswap-frontend/src/legacy/utils/logging/index.ts rename to libs/common-utils/src/logging/index.ts index fc922f318f..2955e23795 100644 --- a/apps/cowswap-frontend/src/legacy/utils/logging/index.ts +++ b/libs/common-utils/src/logging/index.ts @@ -1,8 +1,5 @@ import * as Sentry from '@sentry/react' -import OperatorError from 'api/gnosisProtocol/errors/OperatorError' -import QuoteError from 'api/gnosisProtocol/errors/QuoteError' - type SentryErrorOptions = { message: string name: string @@ -12,7 +9,7 @@ type SentryErrorOptions = { } export function constructSentryError( - baseError: QuoteError | OperatorError | Error, + baseError: Error, response: any, { message, name, optionalTags = {} }: SentryErrorOptions ) { diff --git a/apps/cowswap-frontend/src/legacy/utils/maxAmountSpend.ts b/libs/common-utils/src/maxAmountSpend.ts similarity index 100% rename from apps/cowswap-frontend/src/legacy/utils/maxAmountSpend.ts rename to libs/common-utils/src/maxAmountSpend.ts diff --git a/apps/cowswap-frontend/src/legacy/utils/misc.ts b/libs/common-utils/src/misc.ts similarity index 98% rename from apps/cowswap-frontend/src/legacy/utils/misc.ts rename to libs/common-utils/src/misc.ts index 0c8d68004e..8ca3b699d7 100644 --- a/apps/cowswap-frontend/src/legacy/utils/misc.ts +++ b/libs/common-utils/src/misc.ts @@ -2,7 +2,10 @@ import { SupportedChainId as ChainId } from '@cowprotocol/cow-sdk' import { OrderKind } from '@cowprotocol/cow-sdk' import { Percent } from '@uniswap/sdk-core' -import { Market } from 'legacy/types' +interface Market { + baseToken: T + quoteToken: T +} const PROVIDER_REJECT_REQUEST_CODES = [4001, -32000] // See https://eips.ethereum.org/EIPS/eip-1193 const PROVIDER_REJECT_REQUEST_ERROR_MESSAGES = [ diff --git a/apps/cowswap-frontend/src/legacy/utils/node.ts b/libs/common-utils/src/node.ts similarity index 100% rename from apps/cowswap-frontend/src/legacy/utils/node.ts rename to libs/common-utils/src/node.ts diff --git a/apps/cowswap-frontend/src/lib/utils/parseENSAddress.test.ts b/libs/common-utils/src/parseENSAddress.test.ts similarity index 95% rename from apps/cowswap-frontend/src/lib/utils/parseENSAddress.test.ts rename to libs/common-utils/src/parseENSAddress.test.ts index 9a3f5fc946..975449b601 100644 --- a/apps/cowswap-frontend/src/lib/utils/parseENSAddress.test.ts +++ b/libs/common-utils/src/parseENSAddress.test.ts @@ -1,4 +1,4 @@ -import parseENSAddress from './parseENSAddress' +import { parseENSAddress } from './parseENSAddress' describe('parseENSAddress', () => { it('test cases', () => { diff --git a/apps/cowswap-frontend/src/lib/utils/parseENSAddress.ts b/libs/common-utils/src/parseENSAddress.ts similarity index 64% rename from apps/cowswap-frontend/src/lib/utils/parseENSAddress.ts rename to libs/common-utils/src/parseENSAddress.ts index ababade998..68818595fc 100644 --- a/apps/cowswap-frontend/src/lib/utils/parseENSAddress.ts +++ b/libs/common-utils/src/parseENSAddress.ts @@ -1,8 +1,6 @@ const ENS_NAME_REGEX = /^(([a-zA-Z0-9]+(-[a-zA-Z0-9]+)*\.)+)eth(\/.*)?$/ -export default function parseENSAddress( - ensAddress: string -): { ensName: string; ensPath: string | undefined } | undefined { +export function parseENSAddress(ensAddress: string): { ensName: string; ensPath: string | undefined } | undefined { const match = ensAddress.match(ENS_NAME_REGEX) if (!match) return undefined return { ensName: `${match[1].toLowerCase()}eth`, ensPath: match[4] } diff --git a/apps/cowswap-frontend/src/utils/rawToTokenAmount.ts b/libs/common-utils/src/rawToTokenAmount.ts similarity index 100% rename from apps/cowswap-frontend/src/utils/rawToTokenAmount.ts rename to libs/common-utils/src/rawToTokenAmount.ts diff --git a/apps/cowswap-frontend/src/utils/request.ts b/libs/common-utils/src/request.ts similarity index 100% rename from apps/cowswap-frontend/src/utils/request.ts rename to libs/common-utils/src/request.ts diff --git a/apps/cowswap-frontend/src/lib/utils/resolveENSContentHash.ts b/libs/common-utils/src/resolveENSContentHash.ts similarity index 93% rename from apps/cowswap-frontend/src/lib/utils/resolveENSContentHash.ts rename to libs/common-utils/src/resolveENSContentHash.ts index 97e9f5e6aa..a3560b1166 100644 --- a/apps/cowswap-frontend/src/lib/utils/resolveENSContentHash.ts +++ b/libs/common-utils/src/resolveENSContentHash.ts @@ -59,7 +59,7 @@ function resolverContract(resolverAddress: string, provider: Provider): Contract * @param ensName to resolve * @param provider provider to use to fetch the data */ -export default async function resolveENSContentHash(ensName: string, provider: Provider): Promise { +export async function resolveENSContentHash(ensName: string, provider: Provider): Promise { const ensRegistrarContract = new Contract(REGISTRAR_ADDRESS, REGISTRAR_ABI, provider) const hash = namehash(ensName) const resolverAddress = await ensRegistrarContract.resolver(hash) diff --git a/apps/cowswap-frontend/src/legacy/utils/retry.test.ts b/libs/common-utils/src/retry.test.ts similarity index 100% rename from apps/cowswap-frontend/src/legacy/utils/retry.test.ts rename to libs/common-utils/src/retry.test.ts diff --git a/apps/cowswap-frontend/src/legacy/utils/retry.ts b/libs/common-utils/src/retry.ts similarity index 94% rename from apps/cowswap-frontend/src/legacy/utils/retry.ts rename to libs/common-utils/src/retry.ts index 789b2c92b6..768be301fc 100644 --- a/apps/cowswap-frontend/src/legacy/utils/retry.ts +++ b/libs/common-utils/src/retry.ts @@ -43,8 +43,10 @@ export function retry( ): { promise: Promise; cancel: () => void } { let completed = false let rejectCancelled: (error: Error) => void + // eslint-disable-next-line no-async-promise-executor const promise = new Promise(async (resolve, reject) => { rejectCancelled = reject + // eslint-disable-next-line no-constant-condition while (true) { let result: T try { diff --git a/apps/cowswap-frontend/src/legacy/utils/safeNamehash.ts b/libs/common-utils/src/safeNamehash.ts similarity index 100% rename from apps/cowswap-frontend/src/legacy/utils/safeNamehash.ts rename to libs/common-utils/src/safeNamehash.ts diff --git a/apps/cowswap-frontend/src/legacy/utils/sound.ts b/libs/common-utils/src/sound.ts similarity index 100% rename from apps/cowswap-frontend/src/legacy/utils/sound.ts rename to libs/common-utils/src/sound.ts diff --git a/apps/cowswap-frontend/src/legacy/utils/swapErrorToUserReadableMessage.tsx b/libs/common-utils/src/swapErrorToUserReadableMessage.tsx similarity index 100% rename from apps/cowswap-frontend/src/legacy/utils/swapErrorToUserReadableMessage.tsx rename to libs/common-utils/src/swapErrorToUserReadableMessage.tsx diff --git a/apps/cowswap-frontend/src/utils/time.ts b/libs/common-utils/src/time.ts similarity index 100% rename from apps/cowswap-frontend/src/utils/time.ts rename to libs/common-utils/src/time.ts diff --git a/apps/cowswap-frontend/src/legacy/utils/toggleBodyClass.ts b/libs/common-utils/src/toggleBodyClass.ts similarity index 100% rename from apps/cowswap-frontend/src/legacy/utils/toggleBodyClass.ts rename to libs/common-utils/src/toggleBodyClass.ts diff --git a/apps/cowswap-frontend/src/legacy/utils/tokens.ts b/libs/common-utils/src/tokens.ts similarity index 82% rename from apps/cowswap-frontend/src/legacy/utils/tokens.ts rename to libs/common-utils/src/tokens.ts index 80c4124f25..de556a5f11 100644 --- a/apps/cowswap-frontend/src/legacy/utils/tokens.ts +++ b/libs/common-utils/src/tokens.ts @@ -1,7 +1,10 @@ import { SupportedChainId as ChainId } from '@cowprotocol/cow-sdk' -import { NATIVE_CURRENCY_BUY_ADDRESS } from 'legacy/constants' -import { GpEther as ETHER, WRAPPED_NATIVE_CURRENCY as WETH } from 'legacy/constants/tokens' +import { + NATIVE_CURRENCY_BUY_ADDRESS, + GpEther as ETHER, + WRAPPED_NATIVE_CURRENCY as WETH, +} from '@cowprotocol/common-const' export function isNativeAddress(tokenAddress: string, chainId: ChainId) { return tokenAddress === 'ETH' || tokenAddress === ETHER.onChain(chainId).symbol diff --git a/apps/cowswap-frontend/src/legacy/utils/tooltips.ts b/libs/common-utils/src/tooltips.ts similarity index 89% rename from apps/cowswap-frontend/src/legacy/utils/tooltips.ts rename to libs/common-utils/src/tooltips.ts index 9093b7c648..1f35e44235 100644 --- a/apps/cowswap-frontend/src/legacy/utils/tooltips.ts +++ b/libs/common-utils/src/tooltips.ts @@ -1,6 +1,5 @@ import { Percent } from '@uniswap/sdk-core' - -import { formatPercent } from 'utils/amountFormat' +import { formatPercent } from './amountFormat' export function getMinimumReceivedTooltip(allowedSlippage: Percent, isExactIn: boolean): string { return `${ diff --git a/apps/cowswap-frontend/src/utils/trimTrailingZeros.test.ts b/libs/common-utils/src/trimTrailingZeros.test.ts similarity index 100% rename from apps/cowswap-frontend/src/utils/trimTrailingZeros.test.ts rename to libs/common-utils/src/trimTrailingZeros.test.ts diff --git a/apps/cowswap-frontend/src/utils/trimTrailingZeros.ts b/libs/common-utils/src/trimTrailingZeros.ts similarity index 100% rename from apps/cowswap-frontend/src/utils/trimTrailingZeros.ts rename to libs/common-utils/src/trimTrailingZeros.ts diff --git a/apps/cowswap-frontend/src/lib/utils/tryParseCurrencyAmount.ts b/libs/common-utils/src/tryParseCurrencyAmount.ts similarity index 78% rename from apps/cowswap-frontend/src/lib/utils/tryParseCurrencyAmount.ts rename to libs/common-utils/src/tryParseCurrencyAmount.ts index 630f395e93..6d13db3884 100644 --- a/apps/cowswap-frontend/src/lib/utils/tryParseCurrencyAmount.ts +++ b/libs/common-utils/src/tryParseCurrencyAmount.ts @@ -7,13 +7,13 @@ import JSBI from 'jsbi' * Parses a CurrencyAmount from the passed string. * Returns the CurrencyAmount, or undefined if parsing fails. */ -export default function tryParseCurrencyAmount(value: string, currency: T): CurrencyAmount -export default function tryParseCurrencyAmount(value: Fraction, currency: T): CurrencyAmount -export default function tryParseCurrencyAmount( +export function tryParseCurrencyAmount(value: string, currency: T): CurrencyAmount +export function tryParseCurrencyAmount(value: Fraction, currency: T): CurrencyAmount +export function tryParseCurrencyAmount( value?: string, currency?: T ): CurrencyAmount | undefined -export default function tryParseCurrencyAmount( +export function tryParseCurrencyAmount( value?: string | Fraction, currency?: T ): CurrencyAmount | undefined { diff --git a/apps/cowswap-frontend/src/utils/tryParseFractionalAmount.ts b/libs/common-utils/src/tryParseFractionalAmount.ts similarity index 90% rename from apps/cowswap-frontend/src/utils/tryParseFractionalAmount.ts rename to libs/common-utils/src/tryParseFractionalAmount.ts index 0c4dc7e8c9..e2c55d5860 100644 --- a/apps/cowswap-frontend/src/utils/tryParseFractionalAmount.ts +++ b/libs/common-utils/src/tryParseFractionalAmount.ts @@ -1,6 +1,5 @@ import { Currency, CurrencyAmount } from '@uniswap/sdk-core' - -import { FractionUtils } from 'utils/fractionUtils' +import { FractionUtils } from './fractionUtils' export function tryParseFractionalAmount( currency: Currency | null, diff --git a/libs/common-utils/src/types.ts b/libs/common-utils/src/types.ts new file mode 100644 index 0000000000..ea882b0091 --- /dev/null +++ b/libs/common-utils/src/types.ts @@ -0,0 +1,25 @@ +import { Currency, CurrencyAmount, Fraction, Price } from '@uniswap/sdk-core' + +export type Writeable = { -readonly [P in keyof T]: T[P] } + +export type Nullish = T | null | undefined + +// This is for Pixel tracking injected code +declare global { + interface Window { + fbq: any // Facebook (Meta) + lintrk: any // Linkedin + twq: any // Twitter + rdt: any // Reddit + pvd: any // Paved + uetq: any // Microsoft Ads + } +} +export type FractionLike = Fraction | Price | CurrencyAmount + +export type ComposableCowInfo = { + id?: string + parentId?: string + isVirtualPart?: boolean + isTheLastPart?: boolean +} diff --git a/apps/cowswap-frontend/src/lib/utils/uriToHttp.test.ts b/libs/common-utils/src/uriToHttp.test.ts similarity index 96% rename from apps/cowswap-frontend/src/lib/utils/uriToHttp.test.ts rename to libs/common-utils/src/uriToHttp.test.ts index 2e922cf9fa..482fb4720a 100644 --- a/apps/cowswap-frontend/src/lib/utils/uriToHttp.test.ts +++ b/libs/common-utils/src/uriToHttp.test.ts @@ -1,4 +1,4 @@ -import uriToHttp from './uriToHttp' +import { uriToHttp } from './uriToHttp' describe('uriToHttp', () => { it('returns .eth.link for ens names', () => { diff --git a/apps/cowswap-frontend/src/lib/utils/uriToHttp.ts b/libs/common-utils/src/uriToHttp.ts similarity index 81% rename from apps/cowswap-frontend/src/lib/utils/uriToHttp.ts rename to libs/common-utils/src/uriToHttp.ts index 5de73c982c..1158fff329 100644 --- a/apps/cowswap-frontend/src/lib/utils/uriToHttp.ts +++ b/libs/common-utils/src/uriToHttp.ts @@ -2,7 +2,7 @@ * Given a URI that may be ipfs, ipns, http, https, ar, or data protocol, return the fetch-able http(s) URLs for the same content * @param uri to convert to fetch-able http url */ -export default function uriToHttp(uri: string): string[] { +export function uriToHttp(uri: string): string[] { const protocol = uri.split(':')[0].toLowerCase() switch (protocol) { case 'data': @@ -12,12 +12,15 @@ export default function uriToHttp(uri: string): string[] { case 'http': return ['https' + uri.substr(4), uri] case 'ipfs': + // eslint-disable-next-line no-case-declarations const hash = uri.match(/^ipfs:(\/\/)?(ipfs\/)?(.*)$/i)?.[3] // TODO: probably a bug on original code return [`https://cloudflare-ipfs.com/ipfs/${hash}/`, `https://ipfs.io/ipfs/${hash}/`] case 'ipns': + // eslint-disable-next-line no-case-declarations const name = uri.match(/^ipns:(\/\/)?(.*)$/i)?.[2] return [`https://cloudflare-ipfs.com/ipns/${name}/`, `https://ipfs.io/ipns/${name}/`] case 'ar': + // eslint-disable-next-line no-case-declarations const tx = uri.match(/^ar:(\/\/)?(.*)$/i)?.[2] return [`https://arweave.net/${tx}`] default: diff --git a/apps/cowswap-frontend/src/legacy/utils/userAgent.ts b/libs/common-utils/src/userAgent.ts similarity index 100% rename from apps/cowswap-frontend/src/legacy/utils/userAgent.ts rename to libs/common-utils/src/userAgent.ts diff --git a/libs/common-utils/tsconfig.json b/libs/common-utils/tsconfig.json new file mode 100644 index 0000000000..bab74ff2e6 --- /dev/null +++ b/libs/common-utils/tsconfig.json @@ -0,0 +1,21 @@ +{ + "compilerOptions": { + "jsx": "react-jsx", + "allowJs": false, + "esModuleInterop": false, + "allowSyntheticDefaultImports": true, + "strict": true, + "types": ["vite/client"] + }, + "files": [], + "include": [], + "references": [ + { + "path": "./tsconfig.lib.json" + }, + { + "path": "./tsconfig.spec.json" + } + ], + "extends": "../../tsconfig.base.json" +} diff --git a/libs/common-utils/tsconfig.lib.json b/libs/common-utils/tsconfig.lib.json new file mode 100644 index 0000000000..1b2b0c12df --- /dev/null +++ b/libs/common-utils/tsconfig.lib.json @@ -0,0 +1,19 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "../../dist/out-tsc", + "types": ["node", "vite/client"] + }, + "files": ["../../node_modules/@nx/react/typings/cssmodule.d.ts", "../../node_modules/@nx/react/typings/image.d.ts"], + "exclude": [ + "**/*.spec.ts", + "**/*.test.ts", + "**/*.spec.tsx", + "**/*.test.tsx", + "**/*.spec.js", + "**/*.test.js", + "**/*.spec.jsx", + "**/*.test.jsx" + ], + "include": ["**/*.js", "**/*.jsx", "**/*.ts", "**/*.tsx"] +} diff --git a/libs/common-utils/tsconfig.spec.json b/libs/common-utils/tsconfig.spec.json new file mode 100644 index 0000000000..26ef046ac5 --- /dev/null +++ b/libs/common-utils/tsconfig.spec.json @@ -0,0 +1,20 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "../../dist/out-tsc", + "module": "commonjs", + "types": ["jest", "node"] + }, + "include": [ + "jest.config.ts", + "src/**/*.test.ts", + "src/**/*.spec.ts", + "src/**/*.test.tsx", + "src/**/*.spec.tsx", + "src/**/*.test.js", + "src/**/*.spec.js", + "src/**/*.test.jsx", + "src/**/*.spec.jsx", + "src/**/*.d.ts" + ] +} diff --git a/libs/common-utils/vite.config.ts b/libs/common-utils/vite.config.ts new file mode 100644 index 0000000000..9232cc2b74 --- /dev/null +++ b/libs/common-utils/vite.config.ts @@ -0,0 +1,56 @@ +/// +import { defineConfig } from 'vite' +import react from '@vitejs/plugin-react-swc' +import viteTsConfigPaths from 'vite-tsconfig-paths' +import dts from 'vite-plugin-dts' +import * as path from 'path' +import { getReactProcessEnv } from '../../tools/getReactProcessEnv' + +export default defineConfig(({ mode }) => { + return { + define: { + ...getReactProcessEnv(mode), + }, + + cacheDir: '../../node_modules/.vite/common-utils', + + plugins: [ + dts({ + entryRoot: 'src', + tsConfigFilePath: path.join(__dirname, 'tsconfig.lib.json'), + skipDiagnostics: true, + }), + react(), + viteTsConfigPaths({ + root: '../../', + }), + ], + + // Uncomment this if you are using workers. + // worker: { + // plugins: [ + // viteTsConfigPaths({ + // root: '../../', + // }), + // ], + // }, + + // Configuration for building your library. + // See: https://vitejs.dev/guide/build.html#library-mode + build: { + lib: { + // Could also be a dictionary or array of multiple entry points. + entry: 'src/index.ts', + name: 'common-utils', + fileName: 'index', + // Change this to the formats you want to support. + // Don't forget to update your package.json as well. + formats: ['es', 'cjs'], + }, + rollupOptions: { + // External packages that should not be bundled into your library. + external: ['react', 'react-dom', 'react/jsx-runtime'], + }, + }, + } +}) diff --git a/libs/core/.babelrc b/libs/core/.babelrc new file mode 100644 index 0000000000..ef4889c1ab --- /dev/null +++ b/libs/core/.babelrc @@ -0,0 +1,20 @@ +{ + "presets": [ + [ + "@nx/react/babel", + { + "runtime": "automatic", + "useBuiltIns": "usage" + } + ] + ], + "plugins": [ + [ + "styled-components", + { + "pure": true, + "ssr": true + } + ] + ] +} diff --git a/libs/core/.eslintrc.json b/libs/core/.eslintrc.json new file mode 100644 index 0000000000..a39ac5d057 --- /dev/null +++ b/libs/core/.eslintrc.json @@ -0,0 +1,18 @@ +{ + "extends": ["plugin:@nx/react", "../../.eslintrc.json"], + "ignorePatterns": ["!**/*"], + "overrides": [ + { + "files": ["*.ts", "*.tsx", "*.js", "*.jsx"], + "rules": {} + }, + { + "files": ["*.ts", "*.tsx"], + "rules": {} + }, + { + "files": ["*.js", "*.jsx"], + "rules": {} + } + ] +} diff --git a/libs/core/README.md b/libs/core/README.md new file mode 100644 index 0000000000..3b616f93d9 --- /dev/null +++ b/libs/core/README.md @@ -0,0 +1 @@ +# Core diff --git a/libs/core/jest.config.ts b/libs/core/jest.config.ts new file mode 100644 index 0000000000..ae2ca52072 --- /dev/null +++ b/libs/core/jest.config.ts @@ -0,0 +1,11 @@ +/* eslint-disable */ +export default { + displayName: 'core', + preset: '../../jest.preset.js', + transform: { + '^(?!.*\\.(js|jsx|ts|tsx|css|json)$)': '@nx/react/plugins/jest', + '^.+\\.[tj]sx?$': ['babel-jest', { presets: ['@nx/react/babel'] }], + }, + moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx'], + coverageDirectory: '../../coverage/libs/core', +} diff --git a/libs/core/package.json b/libs/core/package.json new file mode 100644 index 0000000000..9ca3cccdc7 --- /dev/null +++ b/libs/core/package.json @@ -0,0 +1,12 @@ +{ + "name": "@cowprotocol/core", + "version": "0.0.1", + "main": "./index.js", + "types": "./index.d.ts", + "exports": { + ".": { + "import": "./index.mjs", + "require": "./index.js" + } + } +} diff --git a/libs/core/project.json b/libs/core/project.json new file mode 100644 index 0000000000..fb33a1f5f1 --- /dev/null +++ b/libs/core/project.json @@ -0,0 +1,46 @@ +{ + "name": "@cowprotocol/core", + "$schema": "../../node_modules/nx/schemas/project-schema.json", + "sourceRoot": "libs/core/src", + "projectType": "library", + "tags": [], + "targets": { + "lint": { + "executor": "@nx/linter:eslint", + "outputs": ["{options.outputFile}"], + "options": { + "lintFilePatterns": ["libs/core/**/*.{ts,tsx,js,jsx}"] + } + }, + "build": { + "executor": "@nx/vite:build", + "outputs": ["{options.outputPath}"], + "defaultConfiguration": "production", + "options": { + "outputPath": "dist/libs/core" + }, + "configurations": { + "development": { + "mode": "development" + }, + "production": { + "mode": "production" + } + } + }, + "test": { + "executor": "@nx/jest:jest", + "outputs": ["{workspaceRoot}/coverage/{projectRoot}"], + "options": { + "jestConfig": "libs/core/jest.config.ts", + "passWithNoTests": true + }, + "configurations": { + "ci": { + "ci": true, + "codeCoverage": true + } + } + } + } +} diff --git a/apps/cowswap-frontend/src/modules/gasPirce/index.ts b/libs/core/src/gasPirce/index.ts similarity index 100% rename from apps/cowswap-frontend/src/modules/gasPirce/index.ts rename to libs/core/src/gasPirce/index.ts diff --git a/apps/cowswap-frontend/src/modules/gasPirce/state/gasPriceAtom.ts b/libs/core/src/gasPirce/state/gasPriceAtom.ts similarity index 100% rename from apps/cowswap-frontend/src/modules/gasPirce/state/gasPriceAtom.ts rename to libs/core/src/gasPirce/state/gasPriceAtom.ts diff --git a/apps/cowswap-frontend/src/api/gnosisSafe/index.ts b/libs/core/src/gnosisSafe/index.ts similarity index 97% rename from apps/cowswap-frontend/src/api/gnosisSafe/index.ts rename to libs/core/src/gnosisSafe/index.ts index ee5b84cabf..c12a6531b9 100644 --- a/apps/cowswap-frontend/src/api/gnosisSafe/index.ts +++ b/libs/core/src/gnosisSafe/index.ts @@ -7,8 +7,6 @@ import { SafeMultisigTransactionResponse } from '@safe-global/safe-core-sdk-type // eslint-disable-next-line no-restricted-imports import { ethers } from 'ethers' -import { registerOnWindow } from 'legacy/utils/misc' - const SAFE_TRANSACTION_SERVICE_URL: Partial> = { [SupportedChainId.MAINNET]: 'https://safe-transaction-mainnet.safe.global', [SupportedChainId.GNOSIS_CHAIN]: 'https://safe-transaction-gnosis-chain.safe.global', @@ -100,5 +98,3 @@ export function getSafeInfo(chainId: number, safeAddress: string, library: Web3P return Promise.reject(error) } } - -registerOnWindow({ getSafeTransaction, getSafeInfo }) diff --git a/libs/core/src/index.ts b/libs/core/src/index.ts new file mode 100644 index 0000000000..7ec7c07d69 --- /dev/null +++ b/libs/core/src/index.ts @@ -0,0 +1,3 @@ +export * from './jotaiStore' +export * from './gasPirce' +export * from './gnosisSafe' diff --git a/apps/cowswap-frontend/src/jotaiStore.ts b/libs/core/src/jotaiStore.ts similarity index 100% rename from apps/cowswap-frontend/src/jotaiStore.ts rename to libs/core/src/jotaiStore.ts diff --git a/libs/core/tsconfig.json b/libs/core/tsconfig.json new file mode 100644 index 0000000000..bab74ff2e6 --- /dev/null +++ b/libs/core/tsconfig.json @@ -0,0 +1,21 @@ +{ + "compilerOptions": { + "jsx": "react-jsx", + "allowJs": false, + "esModuleInterop": false, + "allowSyntheticDefaultImports": true, + "strict": true, + "types": ["vite/client"] + }, + "files": [], + "include": [], + "references": [ + { + "path": "./tsconfig.lib.json" + }, + { + "path": "./tsconfig.spec.json" + } + ], + "extends": "../../tsconfig.base.json" +} diff --git a/libs/core/tsconfig.lib.json b/libs/core/tsconfig.lib.json new file mode 100644 index 0000000000..1b2b0c12df --- /dev/null +++ b/libs/core/tsconfig.lib.json @@ -0,0 +1,19 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "../../dist/out-tsc", + "types": ["node", "vite/client"] + }, + "files": ["../../node_modules/@nx/react/typings/cssmodule.d.ts", "../../node_modules/@nx/react/typings/image.d.ts"], + "exclude": [ + "**/*.spec.ts", + "**/*.test.ts", + "**/*.spec.tsx", + "**/*.test.tsx", + "**/*.spec.js", + "**/*.test.js", + "**/*.spec.jsx", + "**/*.test.jsx" + ], + "include": ["**/*.js", "**/*.jsx", "**/*.ts", "**/*.tsx"] +} diff --git a/libs/core/tsconfig.spec.json b/libs/core/tsconfig.spec.json new file mode 100644 index 0000000000..26ef046ac5 --- /dev/null +++ b/libs/core/tsconfig.spec.json @@ -0,0 +1,20 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "../../dist/out-tsc", + "module": "commonjs", + "types": ["jest", "node"] + }, + "include": [ + "jest.config.ts", + "src/**/*.test.ts", + "src/**/*.spec.ts", + "src/**/*.test.tsx", + "src/**/*.spec.tsx", + "src/**/*.test.js", + "src/**/*.spec.js", + "src/**/*.test.jsx", + "src/**/*.spec.jsx", + "src/**/*.d.ts" + ] +} diff --git a/libs/core/vite.config.ts b/libs/core/vite.config.ts new file mode 100644 index 0000000000..5060b85db8 --- /dev/null +++ b/libs/core/vite.config.ts @@ -0,0 +1,49 @@ +/// +import { defineConfig } from 'vite' +import react from '@vitejs/plugin-react-swc' +import viteTsConfigPaths from 'vite-tsconfig-paths' +import dts from 'vite-plugin-dts' +import * as path from 'path' + +export default defineConfig({ + cacheDir: '../../node_modules/.vite/core', + + plugins: [ + dts({ + entryRoot: 'src', + tsConfigFilePath: path.join(__dirname, 'tsconfig.lib.json'), + skipDiagnostics: true, + }), + react(), + viteTsConfigPaths({ + root: '../../', + }), + ], + + // Uncomment this if you are using workers. + // worker: { + // plugins: [ + // viteTsConfigPaths({ + // root: '../../', + // }), + // ], + // }, + + // Configuration for building your library. + // See: https://vitejs.dev/guide/build.html#library-mode + build: { + lib: { + // Could also be a dictionary or array of multiple entry points. + entry: 'src/index.ts', + name: 'core', + fileName: 'index', + // Change this to the formats you want to support. + // Don't forget to update your package.json as well. + formats: ['es', 'cjs'], + }, + rollupOptions: { + // External packages that should not be bundled into your library. + external: ['react', 'react-dom', 'react/jsx-runtime'], + }, + }, +}) diff --git a/libs/ens/.babelrc b/libs/ens/.babelrc new file mode 100644 index 0000000000..ef4889c1ab --- /dev/null +++ b/libs/ens/.babelrc @@ -0,0 +1,20 @@ +{ + "presets": [ + [ + "@nx/react/babel", + { + "runtime": "automatic", + "useBuiltIns": "usage" + } + ] + ], + "plugins": [ + [ + "styled-components", + { + "pure": true, + "ssr": true + } + ] + ] +} diff --git a/libs/ens/.eslintrc.json b/libs/ens/.eslintrc.json new file mode 100644 index 0000000000..a39ac5d057 --- /dev/null +++ b/libs/ens/.eslintrc.json @@ -0,0 +1,18 @@ +{ + "extends": ["plugin:@nx/react", "../../.eslintrc.json"], + "ignorePatterns": ["!**/*"], + "overrides": [ + { + "files": ["*.ts", "*.tsx", "*.js", "*.jsx"], + "rules": {} + }, + { + "files": ["*.ts", "*.tsx"], + "rules": {} + }, + { + "files": ["*.js", "*.jsx"], + "rules": {} + } + ] +} diff --git a/libs/ens/README.md b/libs/ens/README.md new file mode 100644 index 0000000000..a20b45dc80 --- /dev/null +++ b/libs/ens/README.md @@ -0,0 +1 @@ +# ENS diff --git a/libs/ens/jest.config.ts b/libs/ens/jest.config.ts new file mode 100644 index 0000000000..35d3bf8180 --- /dev/null +++ b/libs/ens/jest.config.ts @@ -0,0 +1,11 @@ +/* eslint-disable */ +export default { + displayName: 'ens', + preset: '../../jest.preset.js', + transform: { + '^(?!.*\\.(js|jsx|ts|tsx|css|json)$)': '@nx/react/plugins/jest', + '^.+\\.[tj]sx?$': ['babel-jest', { presets: ['@nx/react/babel'] }], + }, + moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx'], + coverageDirectory: '../../coverage/libs/ens', +} diff --git a/libs/ens/package.json b/libs/ens/package.json new file mode 100644 index 0000000000..089aca8f63 --- /dev/null +++ b/libs/ens/package.json @@ -0,0 +1,12 @@ +{ + "name": "@cowprotocol/ens", + "version": "0.0.1", + "main": "./index.js", + "types": "./index.d.ts", + "exports": { + ".": { + "import": "./index.mjs", + "require": "./index.js" + } + } +} diff --git a/libs/ens/project.json b/libs/ens/project.json new file mode 100644 index 0000000000..cf52dfa562 --- /dev/null +++ b/libs/ens/project.json @@ -0,0 +1,46 @@ +{ + "name": "@cowprotocol/ens", + "$schema": "../../node_modules/nx/schemas/project-schema.json", + "sourceRoot": "libs/ens/src", + "projectType": "library", + "tags": [], + "targets": { + "lint": { + "executor": "@nx/linter:eslint", + "outputs": ["{options.outputFile}"], + "options": { + "lintFilePatterns": ["libs/ens/**/*.{ts,tsx,js,jsx}"] + } + }, + "build": { + "executor": "@nx/vite:build", + "outputs": ["{options.outputPath}"], + "defaultConfiguration": "production", + "options": { + "outputPath": "dist/libs/ens" + }, + "configurations": { + "development": { + "mode": "development" + }, + "production": { + "mode": "production" + } + } + }, + "test": { + "executor": "@nx/jest:jest", + "outputs": ["{workspaceRoot}/coverage/{projectRoot}"], + "options": { + "jestConfig": "libs/ens/jest.config.ts", + "passWithNoTests": true + }, + "configurations": { + "ci": { + "ci": true, + "codeCoverage": true + } + } + } + } +} diff --git a/apps/cowswap-frontend/src/legacy/hooks/useENS.ts b/libs/ens/src/hooks/useENS.ts similarity index 79% rename from apps/cowswap-frontend/src/legacy/hooks/useENS.ts rename to libs/ens/src/hooks/useENS.ts index 4011ca9cb3..a524ffaeb1 100644 --- a/apps/cowswap-frontend/src/legacy/hooks/useENS.ts +++ b/libs/ens/src/hooks/useENS.ts @@ -1,15 +1,15 @@ import { useMemo } from 'react' -import useENSAddress from './useENSAddress' -import useENSName from './useENSName' +import { isAddress } from '@cowprotocol/common-utils' -import { isAddress } from '../utils' +import { useENSAddress } from './useENSAddress' +import { useENSName } from './useENSName' /** * Given a name or address, does a lookup to resolve to an address and name * @param nameOrAddress ENS name or address */ -export default function useENS(nameOrAddress?: string | null): { +export function useENS(nameOrAddress?: string | null): { loading: boolean address: string | null name: string | null diff --git a/libs/ens/src/hooks/useENSAddress.ts b/libs/ens/src/hooks/useENSAddress.ts new file mode 100644 index 0000000000..617d88982d --- /dev/null +++ b/libs/ens/src/hooks/useENSAddress.ts @@ -0,0 +1,21 @@ +import { useMemo } from 'react' + +import { safeNamehash } from '@cowprotocol/common-utils' +import { useENSResolverMethod } from './useENSResolverMethod' + +/** + * Does a lookup for an ENS name to find its address. + */ +export function useENSAddress(ensName?: string | null): { loading: boolean; address: string | null } { + const ensNodeArgument = useMemo(() => (ensName === null ? undefined : safeNamehash(ensName)), [ensName]) + + const { data: addr, isLoading: addrLoading } = useENSResolverMethod('addr', ensNodeArgument) + + return useMemo( + () => ({ + address: addr ?? null, + loading: addrLoading, + }), + [addr, addrLoading] + ) +} diff --git a/libs/ens/src/hooks/useENSAvatar.ts b/libs/ens/src/hooks/useENSAvatar.ts new file mode 100644 index 0000000000..6c04dcd73e --- /dev/null +++ b/libs/ens/src/hooks/useENSAvatar.ts @@ -0,0 +1,198 @@ +import { useEffect, useMemo, useState } from 'react' + +import { safeNamehash, uriToHttp, isAddress, isZero, getContract } from '@cowprotocol/common-utils' +import { BigNumber } from '@ethersproject/bignumber' +import { hexZeroPad } from '@ethersproject/bytes' +import { namehash } from '@ethersproject/hash' + +import { useENSName } from './useENSName' +import { useENSResolverContract } from './useENSResolverContract' +import useSWR from 'swr' +import { useENSResolver } from './useENSResolver' +import { useWeb3React } from '@web3-react/core' +import { Erc1155, Erc1155Abi, Erc721, Erc721Abi } from '@cowprotocol/abis' + +/** + * Returns the ENS avatar URI, if available. + * Spec: https://gist.github.com/Arachnid/9db60bd75277969ee1689c8742b75182. + */ +export function useENSAvatar( + account: string | undefined, + enforceOwnership = true +): { avatar: string | null; loading: boolean } { + const node = useMemo(() => { + if (!account || !isAddress(account)) return undefined + return namehash(`${account.toLowerCase().substr(2)}.addr.reverse`) + }, [account]) + + const addressAvatar = useAvatarFromNode(node) + const ENSName = useENSName(account).ENSName + const nameAvatar = useAvatarFromNode(ENSName === null ? undefined : safeNamehash(ENSName)) + let avatar = addressAvatar.avatar || nameAvatar.avatar + + const nftAvatar = useAvatarFromNFT(account, avatar, enforceOwnership) + avatar = nftAvatar.avatar || avatar + + const http = avatar && uriToHttp(avatar)[0] + + return useMemo( + () => ({ + avatar: http ?? null, + loading: addressAvatar.loading || nameAvatar.loading || nftAvatar.loading, + }), + [addressAvatar.loading, http, nameAvatar.loading, nftAvatar.loading] + ) +} + +function useAvatarFromNode(node?: string): { avatar?: string; loading: boolean } { + const { data: resolverAddress } = useENSResolver(node) + + const resolverContract = useENSResolverContract( + resolverAddress && !isZero(resolverAddress) ? resolverAddress : undefined + ) + + const { data: avatar, isLoading } = useSWR(['useAvatarFromNode', node], async () => { + if (!resolverContract || !node) return undefined + + return resolverContract.callStatic.text(node, 'avatar') + }) + + return useMemo( + () => ({ + avatar: avatar, + loading: isLoading, + }), + [avatar, isLoading] + ) +} + +function useAvatarFromNFT( + account: string | undefined, + nftUri = '', + enforceOwnership: boolean +): { avatar?: string; loading: boolean } { + const parts = nftUri.toLowerCase().split(':') + const protocol = parts[0] + // ignore the chain from eip155 + // TODO: when we are able, pull only from the specified chain + const [, erc] = parts[1]?.split('/') ?? [] + const [contractAddress, id] = parts[2]?.split('/') ?? [] + const isERC721 = protocol === 'eip155' && erc === 'erc721' + const isERC1155 = protocol === 'eip155' && erc === 'erc1155' + const erc721 = useERC721Uri(account, isERC721 ? contractAddress : undefined, id, enforceOwnership) + const erc1155 = useERC1155Uri(account, isERC1155 ? contractAddress : undefined, id, enforceOwnership) + const uri = erc721.uri || erc1155.uri + const http = uri && uriToHttp(uri)[0] + + const [loading, setLoading] = useState(false) + const [avatar, setAvatar] = useState(undefined) + useEffect(() => { + setAvatar(undefined) + if (http) { + setLoading(true) + fetch(http) + .then((res) => res.json()) + .then(({ image }) => { + setAvatar(image) + }) + .catch((e) => console.warn(e)) + .finally(() => { + setLoading(false) + }) + } + }, [http]) + + return useMemo( + () => ({ avatar, loading: erc721.loading || erc1155.loading || loading }), + [avatar, erc1155.loading, erc721.loading, loading] + ) +} + +function useERC721Uri( + account: string | undefined, + contractAddress: string | undefined, + id: string | undefined, + enforceOwnership: boolean +): { uri?: string; loading: boolean } { + const contract = useERC721Contract(contractAddress) + + const { data, isLoading } = useSWR(['useERC721Uri', contract, id], async () => { + if (!contract || !account || !id) return undefined + + const [owner, uri] = await Promise.all([contract.callStatic.ownerOf(id), contract.callStatic.tokenURI(id)]) + + return { owner, uri } + }) + + return useMemo( + () => ({ + uri: !enforceOwnership || account === data?.owner ? data?.uri : undefined, + loading: isLoading, + }), + [account, enforceOwnership, data, isLoading] + ) +} + +function useERC1155Uri( + account: string | undefined, + contractAddress: string | undefined, + id: string | undefined, + enforceOwnership: boolean +): { uri?: string; loading: boolean } { + const contract = useERC1155Contract(contractAddress) + + const { data, isLoading } = useSWR(['useERC1155Uri', contract, id, account], async () => { + if (!contract || !account || !id) return undefined + + const [balance, uri] = await Promise.all([contract.callStatic.balanceOf(account, id), contract.callStatic.uri(id)]) + + return { balance, uri } + }) + + // ERC-1155 allows a generic {id} in the URL, so prepare to replace if relevant, + // in lowercase hexadecimal (with no 0x prefix) and leading zero padded to 64 hex characters. + const idHex = getIdHex(id) || '' + + return useMemo(() => { + return { + uri: + (!enforceOwnership || data?.balance?.gt(0) ? (data?.uri || '').replace(/{id}/g, idHex) : undefined) || + undefined, + loading: isLoading, + } + }, [enforceOwnership, idHex, data, isLoading]) +} + +function useERC721Contract(address: string | undefined): Erc721 | undefined { + const { provider, chainId } = useWeb3React() + + const { data } = useSWR(['useERC721Contract', provider, chainId, address], () => { + if (!chainId || !provider || !address) return undefined + + return getContract(address, Erc721Abi, provider) as Erc721 + }) + + return data +} + +function useERC1155Contract(address: string | undefined): Erc1155 | undefined { + const { provider, chainId } = useWeb3React() + + const { data } = useSWR(['useERC1155Contract', provider, chainId, address], () => { + if (!chainId || !provider || !address) return undefined + + return getContract(address, Erc1155Abi, provider) as Erc1155 + }) + + return data +} + +function getIdHex(id: string | undefined): string | undefined { + try { + return id ? hexZeroPad(BigNumber.from(id).toHexString(), 32).substring(2) : id + } catch (e) { + console.log(`Couldn't get id hex from id: ${id}`, e) + + return undefined + } +} diff --git a/libs/ens/src/hooks/useENSContentHash.ts b/libs/ens/src/hooks/useENSContentHash.ts new file mode 100644 index 0000000000..b239caba06 --- /dev/null +++ b/libs/ens/src/hooks/useENSContentHash.ts @@ -0,0 +1,21 @@ +import { useMemo } from 'react' + +import { safeNamehash } from '@cowprotocol/common-utils' +import { useENSResolverMethod } from './useENSResolverMethod' + +/** + * Does a lookup for an ENS name to find its contenthash. + */ +export function useENSContentHash(ensName?: string | null): { loading: boolean; contenthash: string | null } { + const ensNodeArgument = useMemo(() => (ensName === null ? undefined : safeNamehash(ensName)), [ensName]) + + const { data: contenthash, isLoading: hashLoading } = useENSResolverMethod('contenthash', ensNodeArgument) + + return useMemo( + () => ({ + contenthash: contenthash ?? null, + loading: hashLoading, + }), + [hashLoading, contenthash] + ) +} diff --git a/libs/ens/src/hooks/useENSName.ts b/libs/ens/src/hooks/useENSName.ts new file mode 100644 index 0000000000..eceb8cd295 --- /dev/null +++ b/libs/ens/src/hooks/useENSName.ts @@ -0,0 +1,36 @@ +import { useMemo } from 'react' + +import { isAddress } from '@cowprotocol/common-utils' +import { namehash } from '@ethersproject/hash' + +import { useENSAddress } from './useENSAddress' +import { useENSResolverMethod } from './useENSResolverMethod' + +/** + * Does a reverse lookup for an address to find its ENS name. + * Note this is not the same as looking up an ENS name to find an address. + */ +export function useENSName(address?: string): { ENSName: string | null; loading: boolean } { + const ensNodeArgument = useMemo(() => { + if (!address || !isAddress(address)) return undefined + + return namehash(`${address.toLowerCase().substr(2)}.addr.reverse`) + }, [address]) + + const { data: name, isLoading: nameLoading } = useENSResolverMethod('name', ensNodeArgument) + + /* ENS does not enforce that an address owns a .eth domain before setting it as a reverse proxy + and recommends that you perform a match on the forward resolution + see: https://docs.ens.domains/dapp-developer-guide/resolving-names#reverse-resolution + */ + const fwdAddr = useENSAddress(name) + const checkedName = address === fwdAddr?.address ? name : null + + return useMemo( + () => ({ + ENSName: checkedName ?? null, + loading: nameLoading, + }), + [checkedName, nameLoading] + ) +} diff --git a/libs/ens/src/hooks/useENSRegistrarContract.ts b/libs/ens/src/hooks/useENSRegistrarContract.ts new file mode 100644 index 0000000000..0788e0b3a7 --- /dev/null +++ b/libs/ens/src/hooks/useENSRegistrarContract.ts @@ -0,0 +1,21 @@ +import { getContract } from '@cowprotocol/common-utils' +import { ENS_REGISTRAR_ADDRESSES } from '@cowprotocol/common-const' +import { EnsAbi, EnsRegistrar } from '@cowprotocol/abis' +import { useWeb3React } from '@web3-react/core' +import useSWR from 'swr' + +export function useENSRegistrarContract(): EnsRegistrar | undefined { + const { provider, chainId } = useWeb3React() + + const { data } = useSWR(['useENSRegistrarContract', provider, chainId], () => { + if (!chainId || !provider) return undefined + + const address = ENS_REGISTRAR_ADDRESSES[chainId] + + if (!address) return undefined + + return getContract(address, EnsAbi, provider) as EnsRegistrar + }) + + return data +} diff --git a/libs/ens/src/hooks/useENSResolver.ts b/libs/ens/src/hooks/useENSResolver.ts new file mode 100644 index 0000000000..92baf08774 --- /dev/null +++ b/libs/ens/src/hooks/useENSResolver.ts @@ -0,0 +1,12 @@ +import useSWR, { SWRResponse } from 'swr' +import { useENSRegistrarContract } from './useENSRegistrarContract' + +export function useENSResolver(node: string | undefined): SWRResponse { + const registrarContract = useENSRegistrarContract() + + return useSWR(['useENSResolver', node], async () => { + if (!registrarContract || !node) return undefined + + return registrarContract.callStatic.resolver(node) + }) +} diff --git a/libs/ens/src/hooks/useENSResolverContract.ts b/libs/ens/src/hooks/useENSResolverContract.ts new file mode 100644 index 0000000000..47ae7aada8 --- /dev/null +++ b/libs/ens/src/hooks/useENSResolverContract.ts @@ -0,0 +1,16 @@ +import { getContract } from '@cowprotocol/common-utils' +import { EnsPublicResolver, EnsPublicResolverAbi } from '@cowprotocol/abis' +import { useWeb3React } from '@web3-react/core' +import useSWR from 'swr' + +export function useENSResolverContract(address: string | undefined): EnsPublicResolver | undefined { + const { provider, chainId } = useWeb3React() + + const { data } = useSWR(['useENSResolverContract', provider, chainId, address], () => { + if (!chainId || !provider || !address) return undefined + + return getContract(address, EnsPublicResolverAbi, provider) as EnsPublicResolver + }) + + return data +} diff --git a/libs/ens/src/hooks/useENSResolverMethod.ts b/libs/ens/src/hooks/useENSResolverMethod.ts new file mode 100644 index 0000000000..edbcb8b467 --- /dev/null +++ b/libs/ens/src/hooks/useENSResolverMethod.ts @@ -0,0 +1,29 @@ +import useSWR from 'swr' +import { useENSResolver } from './useENSResolver' +import { useENSResolverContract } from './useENSResolverContract' +import { isZero } from '@cowprotocol/common-utils' +import { useMemo } from 'react' + +export function useENSResolverMethod( + method: 'addr' | 'name' | 'contenthash', + ensNodeArgument: string | undefined +): { data: string | undefined; isLoading: boolean } { + const { data: resolverAddress, isLoading: resolverAddressLoading } = useENSResolver(ensNodeArgument) + + const resolverContract = useENSResolverContract( + resolverAddress && !isZero(resolverAddress) ? resolverAddress : undefined + ) + + const { data, isLoading } = useSWR(['useENSResolverMethod' + method, resolverContract, ensNodeArgument], async () => { + if (!resolverContract || !ensNodeArgument) return undefined + + return resolverContract.callStatic[method](ensNodeArgument) + }) + + return useMemo(() => { + return { + data, + isLoading: resolverAddressLoading || isLoading, + } + }, [data, resolverAddressLoading, isLoading]) +} diff --git a/libs/ens/src/index.ts b/libs/ens/src/index.ts new file mode 100644 index 0000000000..827a599b5b --- /dev/null +++ b/libs/ens/src/index.ts @@ -0,0 +1,5 @@ +export * from './hooks/useENS' +export * from './hooks/useENSAddress' +export * from './hooks/useENSAvatar' +export * from './hooks/useENSContentHash' +export * from './hooks/useENSName' diff --git a/libs/ens/tsconfig.json b/libs/ens/tsconfig.json new file mode 100644 index 0000000000..bab74ff2e6 --- /dev/null +++ b/libs/ens/tsconfig.json @@ -0,0 +1,21 @@ +{ + "compilerOptions": { + "jsx": "react-jsx", + "allowJs": false, + "esModuleInterop": false, + "allowSyntheticDefaultImports": true, + "strict": true, + "types": ["vite/client"] + }, + "files": [], + "include": [], + "references": [ + { + "path": "./tsconfig.lib.json" + }, + { + "path": "./tsconfig.spec.json" + } + ], + "extends": "../../tsconfig.base.json" +} diff --git a/libs/ens/tsconfig.lib.json b/libs/ens/tsconfig.lib.json new file mode 100644 index 0000000000..1b2b0c12df --- /dev/null +++ b/libs/ens/tsconfig.lib.json @@ -0,0 +1,19 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "../../dist/out-tsc", + "types": ["node", "vite/client"] + }, + "files": ["../../node_modules/@nx/react/typings/cssmodule.d.ts", "../../node_modules/@nx/react/typings/image.d.ts"], + "exclude": [ + "**/*.spec.ts", + "**/*.test.ts", + "**/*.spec.tsx", + "**/*.test.tsx", + "**/*.spec.js", + "**/*.test.js", + "**/*.spec.jsx", + "**/*.test.jsx" + ], + "include": ["**/*.js", "**/*.jsx", "**/*.ts", "**/*.tsx"] +} diff --git a/libs/ens/tsconfig.spec.json b/libs/ens/tsconfig.spec.json new file mode 100644 index 0000000000..26ef046ac5 --- /dev/null +++ b/libs/ens/tsconfig.spec.json @@ -0,0 +1,20 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "../../dist/out-tsc", + "module": "commonjs", + "types": ["jest", "node"] + }, + "include": [ + "jest.config.ts", + "src/**/*.test.ts", + "src/**/*.spec.ts", + "src/**/*.test.tsx", + "src/**/*.spec.tsx", + "src/**/*.test.js", + "src/**/*.spec.js", + "src/**/*.test.jsx", + "src/**/*.spec.jsx", + "src/**/*.d.ts" + ] +} diff --git a/libs/ens/vite.config.ts b/libs/ens/vite.config.ts new file mode 100644 index 0000000000..59415ff872 --- /dev/null +++ b/libs/ens/vite.config.ts @@ -0,0 +1,49 @@ +/// +import { defineConfig } from 'vite' +import react from '@vitejs/plugin-react-swc' +import viteTsConfigPaths from 'vite-tsconfig-paths' +import dts from 'vite-plugin-dts' +import * as path from 'path' + +export default defineConfig({ + cacheDir: '../../node_modules/.vite/ens', + + plugins: [ + dts({ + entryRoot: 'src', + tsConfigFilePath: path.join(__dirname, 'tsconfig.lib.json'), + skipDiagnostics: true, + }), + react(), + viteTsConfigPaths({ + root: '../../', + }), + ], + + // Uncomment this if you are using workers. + // worker: { + // plugins: [ + // viteTsConfigPaths({ + // root: '../../', + // }), + // ], + // }, + + // Configuration for building your library. + // See: https://vitejs.dev/guide/build.html#library-mode + build: { + lib: { + // Could also be a dictionary or array of multiple entry points. + entry: 'src/index.ts', + name: 'ens', + fileName: 'index', + // Change this to the formats you want to support. + // Don't forget to update your package.json as well. + formats: ['es', 'cjs'], + }, + rollupOptions: { + // External packages that should not be bundled into your library. + external: ['react', 'react-dom', 'react/jsx-runtime'], + }, + }, +}) diff --git a/libs/snackbars/README.md b/libs/snackbars/README.md index f80124370c..19aa96ff19 100644 --- a/libs/snackbars/README.md +++ b/libs/snackbars/README.md @@ -7,7 +7,7 @@ ```tsx // Add the widget in the root component -import { SnackbarsWidget } from '@cowswap/snackbars' +import { SnackbarsWidget } from '@cowprotocol/snackbars' export function App() { return ( @@ -22,7 +22,7 @@ export function App() { ```tsx // Use the hook to add a snackbar -import { useAddSnackbar } from '@cowswap/snackbars' +import { useAddSnackbar } from '@cowprotocol/snackbars' export function MyComponent() { const addSnackbar = useAddSnackbar() diff --git a/libs/snackbars/package.json b/libs/snackbars/package.json index ada384c9d3..9c5660059c 100644 --- a/libs/snackbars/package.json +++ b/libs/snackbars/package.json @@ -1,5 +1,5 @@ { - "name": "@cowswap/snackbars", + "name": "@cowprotocol/snackbars", "version": "0.0.1", "main": "./index.js", "types": "./index.d.ts", diff --git a/libs/snackbars/project.json b/libs/snackbars/project.json index 748a6c5a84..c816183936 100644 --- a/libs/snackbars/project.json +++ b/libs/snackbars/project.json @@ -1,5 +1,5 @@ { - "name": "@cowswap/snackbars", + "name": "@cowprotocol/snackbars", "$schema": "../../node_modules/nx/schemas/project-schema.json", "sourceRoot": "libs/snackbars/src", "projectType": "library", diff --git a/libs/snackbars/vite.config.ts b/libs/snackbars/vite.config.ts index 9238b65a24..ca362ed6c5 100644 --- a/libs/snackbars/vite.config.ts +++ b/libs/snackbars/vite.config.ts @@ -1,6 +1,6 @@ /// import { defineConfig } from 'vite' -import react from '@vitejs/plugin-react' +import react from '@vitejs/plugin-react-swc' import viteTsConfigPaths from 'vite-tsconfig-paths' import dts from 'vite-plugin-dts' import * as path from 'path' diff --git a/libs/ui/.eslintrc.json b/libs/ui/.eslintrc.json index 64b3b1932f..5b5e742133 100644 --- a/libs/ui/.eslintrc.json +++ b/libs/ui/.eslintrc.json @@ -3,6 +3,9 @@ // "extends": ["plugin:@nx/react"], "extends": ["../../.eslintrc.json"], "ignorePatterns": ["!**/*"], + "rules": { + "@typescript-eslint/no-explicit-any": "off" + }, "overrides": [ { "files": ["*.ts", "*.tsx", "*.js", "*.jsx"], diff --git a/libs/ui/project.json b/libs/ui/project.json index 852b95fb5f..e9d0b37aaf 100644 --- a/libs/ui/project.json +++ b/libs/ui/project.json @@ -1,5 +1,5 @@ { - "name": "ui", + "name": "@cowprotocol/ui", "$schema": "../../node_modules/nx/schemas/project-schema.json", "sourceRoot": "libs/ui/src", "projectType": "library", diff --git a/libs/ui/src/consts.ts b/libs/ui/src/consts.ts new file mode 100644 index 0000000000..2ff084b7c6 --- /dev/null +++ b/libs/ui/src/consts.ts @@ -0,0 +1 @@ +export const AMOUNTS_FORMATTING_FEATURE_FLAG = 'highlight-amounts-formatting' diff --git a/apps/cowswap-frontend/src/legacy/theme/enum.ts b/libs/ui/src/enum.ts similarity index 100% rename from apps/cowswap-frontend/src/legacy/theme/enum.ts rename to libs/ui/src/enum.ts diff --git a/libs/ui/src/index.ts b/libs/ui/src/index.ts index c8ce325a11..f4df9da04b 100644 --- a/libs/ui/src/index.ts +++ b/libs/ui/src/index.ts @@ -1 +1,12 @@ -export * from './lib/ui' +export * from './pure/Button' +export * from './pure/Loader' +export { loadingOpacityMixin, LoadingRows } from './pure/Loader/styled' +export * from './pure/Row' +export * from './pure/FiatAmount' +export * from './pure/TokenSymbol' +export * from './pure/TokenAmount' +export * from './pure/SelectDropdown' +export * from './pure/Tooltip' +export * from './pure/Popover' +export * from './pure/ExternalLink' +export * from './enum' diff --git a/libs/ui/src/lib/ui.spec.tsx b/libs/ui/src/lib/ui.spec.tsx deleted file mode 100644 index a5690cf131..0000000000 --- a/libs/ui/src/lib/ui.spec.tsx +++ /dev/null @@ -1,10 +0,0 @@ -import { render } from '@testing-library/react' - -import { PinkTitle } from './ui' - -describe('Ui', () => { - it('should render successfully', () => { - const { baseElement } = render() - expect(baseElement).toBeTruthy() - }) -}) diff --git a/libs/ui/src/lib/ui.tsx b/libs/ui/src/lib/ui.tsx deleted file mode 100644 index d3bb871bd5..0000000000 --- a/libs/ui/src/lib/ui.tsx +++ /dev/null @@ -1,16 +0,0 @@ -import { PropsWithChildren } from 'react' - -import { return5 } from '@cowswap/ui-utils' - -/* eslint-disable-next-line */ -export interface UiProps extends PropsWithChildren {} - -export function PinkTitle(props: UiProps) { - return ( -
-

- {props.children} (return5 = {return5()}) -

-
- ) -} diff --git a/apps/cowswap-frontend/src/legacy/components/Button/ButtonMod.tsx b/libs/ui/src/pure/Button/ButtonMod.tsx similarity index 83% rename from apps/cowswap-frontend/src/legacy/components/Button/ButtonMod.tsx rename to libs/ui/src/pure/Button/ButtonMod.tsx index ea5f8c448a..b3cc7e1a1b 100644 --- a/apps/cowswap-frontend/src/legacy/components/Button/ButtonMod.tsx +++ b/libs/ui/src/pure/Button/ButtonMod.tsx @@ -1,11 +1,10 @@ import { darken } from 'polished' -import { Check, ChevronDown } from 'react-feather' +import { ChevronDown } from 'react-feather' import { Button as RebassButton, ButtonProps as ButtonPropsOriginal } from 'rebass/styled-components' -import styled from 'styled-components/macro' +import styled from 'styled-components' -import { RowBetween } from 'legacy/components/Row' -import useTheme from 'legacy/hooks/useTheme' -import { ButtonSize } from 'legacy/theme/enum' +import { RowBetween } from '../Row' +import { ButtonSize } from '../../enum' type ButtonProps = Omit @@ -103,7 +102,7 @@ export const ButtonLight = styled(BaseButton)` export const ButtonGray = styled(BaseButton)` background-color: ${({ theme }) => theme.bg3}; - color: ${({ theme }) => theme.text2}; + color: var(--cow-color-text2); font-size: 16px; // font-weight: 500; @@ -151,7 +150,7 @@ export const ButtonSecondary = styled(BaseButton)` export const ButtonOutlined = styled(BaseButton)` border: 1px solid ${({ theme }) => theme.bg2}; background-color: transparent; - color: ${({ theme }) => theme.text1}; + color: var(--cow-color-text1); &:focus { box-shadow: 0 0 0 1px ${({ theme }) => theme.bg4}; } @@ -234,13 +233,13 @@ export const ButtonText = styled(BaseButton)` export const ButtonConfirmedStyle = styled(BaseButton)` background-color: ${({ theme }) => theme.bg3}; - color: ${({ theme }) => theme.text1}; + color: var(--cow-color-text1); /* border: 1px solid ${({ theme }) => theme.green1}; */ &:disabled { /* opacity: 50%; */ background-color: ${({ theme }) => theme.bg2}; - color: ${({ theme }) => theme.text2}; + color: var(--cow-color-text2); cursor: auto; } ` @@ -310,57 +309,3 @@ export function ButtonDropdownLight({ disabled = false, children, ...rest }: { d ) } - -const ActiveOutlined = styled(ButtonOutlined)` - border: 1px solid; - border-color: ${({ theme }) => theme.primary1}; -` - -const Circle = styled.div` - height: 20px; - width: 20px; - border-radius: 50%; - background-color: ${({ theme }) => theme.primary1}; - display: flex; - align-items: center; - justify-content: center; -` - -const CheckboxWrapper = styled.div` - width: 30px; - padding: 0 10px; - position: absolute; - top: 10px; - right: 10px; -` - -const ResponsiveCheck = styled(Check)` - size: 13px; -` - -export function ButtonRadioChecked({ active = false, children, ...rest }: { active?: boolean } & ButtonProps) { - const theme = useTheme() - - if (!active) { - return ( - - {{children}} - - ) - } else { - return ( - - { - - {children} - - - - - - - } - - ) - } -} diff --git a/apps/cowswap-frontend/src/legacy/components/Button/__fixtures__/Button.tsx b/libs/ui/src/pure/Button/__fixtures__/Button.tsx similarity index 100% rename from apps/cowswap-frontend/src/legacy/components/Button/__fixtures__/Button.tsx rename to libs/ui/src/pure/Button/__fixtures__/Button.tsx diff --git a/apps/cowswap-frontend/src/legacy/components/Button/__fixtures__/ButtonConfirmed.tsx b/libs/ui/src/pure/Button/__fixtures__/ButtonConfirmed.tsx similarity index 100% rename from apps/cowswap-frontend/src/legacy/components/Button/__fixtures__/ButtonConfirmed.tsx rename to libs/ui/src/pure/Button/__fixtures__/ButtonConfirmed.tsx diff --git a/apps/cowswap-frontend/src/legacy/components/Button/__fixtures__/ButtonDropdown.tsx b/libs/ui/src/pure/Button/__fixtures__/ButtonDropdown.tsx similarity index 100% rename from apps/cowswap-frontend/src/legacy/components/Button/__fixtures__/ButtonDropdown.tsx rename to libs/ui/src/pure/Button/__fixtures__/ButtonDropdown.tsx diff --git a/apps/cowswap-frontend/src/legacy/components/Button/__fixtures__/ButtonDropdownLight.tsx b/libs/ui/src/pure/Button/__fixtures__/ButtonDropdownLight.tsx similarity index 100% rename from apps/cowswap-frontend/src/legacy/components/Button/__fixtures__/ButtonDropdownLight.tsx rename to libs/ui/src/pure/Button/__fixtures__/ButtonDropdownLight.tsx diff --git a/apps/cowswap-frontend/src/legacy/components/Button/__fixtures__/ButtonError.tsx b/libs/ui/src/pure/Button/__fixtures__/ButtonError.tsx similarity index 100% rename from apps/cowswap-frontend/src/legacy/components/Button/__fixtures__/ButtonError.tsx rename to libs/ui/src/pure/Button/__fixtures__/ButtonError.tsx diff --git a/apps/cowswap-frontend/src/legacy/components/Button/__fixtures__/cosmos.decorator.tsx b/libs/ui/src/pure/Button/__fixtures__/cosmos.decorator.tsx similarity index 92% rename from apps/cowswap-frontend/src/legacy/components/Button/__fixtures__/cosmos.decorator.tsx rename to libs/ui/src/pure/Button/__fixtures__/cosmos.decorator.tsx index 8d7181c304..07c95662b4 100644 --- a/apps/cowswap-frontend/src/legacy/components/Button/__fixtures__/cosmos.decorator.tsx +++ b/libs/ui/src/pure/Button/__fixtures__/cosmos.decorator.tsx @@ -2,7 +2,7 @@ import { ReactNode } from 'react' import { Box } from 'rebass' -import styled from 'styled-components/macro' +import styled from 'styled-components' type WrapperParams = { background?: string; children: ReactNode } diff --git a/apps/cowswap-frontend/src/legacy/components/Button/index.tsx b/libs/ui/src/pure/Button/index.tsx similarity index 93% rename from apps/cowswap-frontend/src/legacy/components/Button/index.tsx rename to libs/ui/src/pure/Button/index.tsx index 9749f9bbb0..c1641b2a4e 100644 --- a/apps/cowswap-frontend/src/legacy/components/Button/index.tsx +++ b/libs/ui/src/pure/Button/index.tsx @@ -3,11 +3,10 @@ import { HTMLAttributes } from 'react' import { transparentize, darken, lighten } from 'polished' import { ChevronDown, Star } from 'react-feather' import { ButtonProps } from 'rebass/styled-components' -import styled from 'styled-components/macro' +import styled from 'styled-components' -import { RowBetween } from 'legacy/components/Row' -import useTheme from 'legacy/hooks/useTheme' -import { ButtonSize } from 'legacy/theme/enum' +import { RowBetween } from '../Row' +import { ButtonSize } from '../../enum' import { // Import only the basic buttons @@ -49,7 +48,7 @@ export const ButtonPrimary = styled(ButtonPrimaryMod)` } &:disabled { - background-color: ${({ theme }) => theme.grey1}; + background-color: var(--cow-color-grey); color: ${({ theme }) => transparentize(0.4, theme.text1)}; background-image: none; border: 0; @@ -166,7 +165,7 @@ export const ButtonOutlined = styled(ButtonOutlinedMod)` export const ButtonConfirmedStyle = styled(ButtonConfirmedStyleMod)` // CSS overrides background-color: ${({ theme }) => theme.disabled}; - color: ${({ theme }) => theme.text1}; + color: var(--cow-color-text1); background-image: none; border: 0; cursor: auto; @@ -178,14 +177,14 @@ export const ButtonConfirmedStyle = styled(ButtonConfirmedStyleMod)` export const ButtonErrorStyle = styled(ButtonPrimary)` // CSS overrides background: ${({ theme }) => theme.red1}; - color: ${({ theme }) => theme.bg1}; + color: var(--cow-container-bg-01); transition: background 0.15s ease-in-out; &:focus, &:hover, &:active { background: ${({ theme }) => theme.red1}; - color: ${({ theme }) => theme.bg1}; + color: var(--cow-container-bg-01); } &:hover { @@ -268,10 +267,9 @@ export const ButtonStar = ({ stroke, ...rest }: { fill?: string; size?: string; stroke: string } & HTMLAttributes) => { - const theme = useTheme() return ( - + ) } diff --git a/libs/ui/src/pure/ExternalLink/index.tsx b/libs/ui/src/pure/ExternalLink/index.tsx new file mode 100644 index 0000000000..fcbc9e5574 --- /dev/null +++ b/libs/ui/src/pure/ExternalLink/index.tsx @@ -0,0 +1,112 @@ +import React, { HTMLProps } from 'react' +import { anonymizeLink } from '@cowprotocol/common-utils' +import { externalLinkAnalytics, outboundLink } from '@cowprotocol/analytics' +import styled from 'styled-components' +import { ExternalLink as LinkIconFeather } from 'react-feather' + +export const StyledLink = styled.a` + text-decoration: none; + cursor: pointer; + color: ${({ theme }) => theme.text3}; + font-weight: 500; + + :hover { + text-decoration: underline; + } + + :focus { + outline: none; + text-decoration: none; + } + + :active { + text-decoration: none; + } +` +const LinkIconWrapper = styled.a` + text-decoration: none; + cursor: pointer; + align-items: center; + justify-content: center; + display: flex; + + :hover { + text-decoration: none; + opacity: 0.7; + } + + :focus { + outline: none; + text-decoration: none; + } + + :active { + text-decoration: none; + } +` +export const LinkIcon = styled(LinkIconFeather)` + height: 16px; + width: 18px; + margin-left: 10px; + stroke: ${({ theme }) => theme.text3}; +` + +export function handleClickExternalLink(event: React.MouseEvent) { + const { target, href } = event.currentTarget + + const anonymizedHref = anonymizeLink(href) + + // don't prevent default, don't redirect if it's a new tab + if (target === '_blank' || event.ctrlKey || event.metaKey) { + outboundLink({ label: anonymizedHref }, () => { + console.debug('Fired outbound link event', anonymizedHref) + }) + } else { + event.preventDefault() + // send a ReactGA event and then trigger a location change + outboundLink({ label: anonymizedHref }, () => { + window.location.href = anonymizedHref + }) + } +} + +/** + * Outbound link that handles firing google analytics events + */ +export function ExternalLink({ + target = '_blank', + href, + rel = 'noopener noreferrer', + onClickOptional, + ...rest +}: Omit, 'as' | 'ref' | 'onClick'> & { + href: string + onClickOptional?: React.MouseEventHandler +}) { + return ( + { + if (onClickOptional) onClickOptional(event) + handleClickExternalLink(event) + externalLinkAnalytics(href) + }} + {...rest} + /> + ) +} + +export function ExternalLinkIcon({ + target = '_blank', + href, + rel = 'noopener noreferrer', + ...rest +}: Omit, 'as' | 'ref' | 'onClick'> & { href: string }) { + return ( + + + + ) +} diff --git a/apps/cowswap-frontend/src/common/pure/FiatAmount/index.tsx b/libs/ui/src/pure/FiatAmount/index.tsx similarity index 68% rename from apps/cowswap-frontend/src/common/pure/FiatAmount/index.tsx rename to libs/ui/src/pure/FiatAmount/index.tsx index eeefd629b4..197b0a1741 100644 --- a/apps/cowswap-frontend/src/common/pure/FiatAmount/index.tsx +++ b/libs/ui/src/pure/FiatAmount/index.tsx @@ -1,13 +1,8 @@ -import styled from 'styled-components/macro' -import { FractionLike, Nullish } from 'types' - -import { LONG_PRECISION } from 'legacy/constants' - -import { AMOUNTS_FORMATTING_FEATURE_FLAG } from 'common/constants/featureFlags' -import { formatFiatAmount } from 'utils/amountFormat' -import { FeatureFlag } from 'utils/featureFlags' -import { FractionUtils } from 'utils/fractionUtils' - +import styled from 'styled-components' +import { FeatureFlag, formatFiatAmount, FractionUtils } from '@cowprotocol/common-utils' +import { AMOUNTS_FORMATTING_FEATURE_FLAG } from '../../consts' +import { FractionLike, Nullish } from '../../types' +import { LONG_PRECISION } from '@cowprotocol/common-const' export interface FiatAmountProps { amount: Nullish accurate?: boolean diff --git a/apps/cowswap-frontend/src/legacy/components/Loader/index.tsx b/libs/ui/src/pure/Loader/index.tsx similarity index 82% rename from apps/cowswap-frontend/src/legacy/components/Loader/index.tsx rename to libs/ui/src/pure/Loader/index.tsx index e881d36747..35a2682f24 100644 --- a/apps/cowswap-frontend/src/legacy/components/Loader/index.tsx +++ b/libs/ui/src/pure/Loader/index.tsx @@ -1,4 +1,4 @@ -import styled, { keyframes } from 'styled-components/macro' +import styled, { keyframes } from 'styled-components' const rotate = keyframes` from { @@ -22,15 +22,7 @@ export const StyledSVG = styled.svg<{ size: string; stroke?: string }>` * Takes in custom size and stroke for circle color, default to primary color as fill, * need ...rest for layered styles on top */ -export default function Loader({ - size = '16px', - stroke, - ...rest -}: { - size?: string - stroke?: string - [k: string]: any -}) { +export function Loader({ size = '16px', stroke, ...rest }: { size?: string; stroke?: string; [k: string]: any }) { return ( ` visibility: ${(props) => (props.show ? 'visible' : 'hidden')}; opacity: ${(props) => (props.show ? 1 : 0)}; transition: visibility 150ms linear, opacity 150ms linear; - /* color: ${({ theme }) => theme.text2}; */ - /* MOD */ - color: ${({ theme }) => theme.text1}; - background: ${({ theme }) => theme.bg1}; + color: var(--cow-color-text1); + background: var(--cow-container-bg-01); border: 1px solid ${({ theme }) => theme.bg3}; box-shadow: 0 4px 8px 0 ${({ theme }) => transparentize(0.9, theme.shadow1)}; border-radius: 8px; @@ -44,7 +38,7 @@ export const Arrow = styled.div` content: ''; border: 1px solid ${({ theme }) => theme.bg3}; transform: rotate(45deg); - background: ${({ theme }) => theme.bg1}; + background: var(--cow-container-bg-01); } &.arrow-top { @@ -91,6 +85,32 @@ export interface PopoverProps extends PopoverContainerProps, Omit, never> // gp mod } +// TODO: reuse hook from @cowprotocol/common-hooks +// Currently it's not possible because of dependency inversion +function useInterval(callback: () => void, delay: null | number, leading = true) { + const savedCallback = useRef<() => void>() + + // Remember the latest callback. + useEffect(() => { + savedCallback.current = callback + }, [callback]) + + // Set up the interval. + useEffect(() => { + function tick() { + const { current } = savedCallback + current && current() + } + + if (delay !== null) { + if (leading) tick() + const id = setInterval(tick, delay) + return () => clearInterval(id) + } + return + }, [delay, leading]) +} + export default function Popover({ content, show, @@ -124,6 +144,7 @@ export default function Popover({ const updateCallback = useCallback(() => { update && update() }, [update]) + useInterval(updateCallback, show ? 100 : null) return ( diff --git a/apps/cowswap-frontend/src/legacy/components/Popover/index.tsx b/libs/ui/src/pure/Popover/index.tsx similarity index 96% rename from apps/cowswap-frontend/src/legacy/components/Popover/index.tsx rename to libs/ui/src/pure/Popover/index.tsx index 2ed7e6582e..9142cc2a6a 100644 --- a/apps/cowswap-frontend/src/legacy/components/Popover/index.tsx +++ b/libs/ui/src/pure/Popover/index.tsx @@ -1,5 +1,5 @@ import { transparentize } from 'polished' -import styled from 'styled-components/macro' +import styled from 'styled-components' import PopoverMod, { Arrow as ArrowMod, PopoverContainer as PopoverContainerMod } from './PopoverMod' import { PopoverProps } from './PopoverMod' diff --git a/apps/cowswap-frontend/src/legacy/components/Row/index.tsx b/libs/ui/src/pure/Row/index.tsx similarity index 91% rename from apps/cowswap-frontend/src/legacy/components/Row/index.tsx rename to libs/ui/src/pure/Row/index.tsx index e84ba5abce..d2412393a5 100644 --- a/apps/cowswap-frontend/src/legacy/components/Row/index.tsx +++ b/libs/ui/src/pure/Row/index.tsx @@ -1,7 +1,7 @@ import { Box } from 'rebass/styled-components' -import styled from 'styled-components/macro' +import styled from 'styled-components' -const Row = styled(Box)<{ +export const Row = styled(Box)<{ width?: string align?: string justify?: string @@ -42,5 +42,3 @@ export const RowFixed = styled(Row)<{ gap?: string; justify?: string }>` width: fit-content; margin: ${({ gap }) => gap && `-${gap}`}; ` - -export default Row diff --git a/apps/cowswap-frontend/src/common/pure/SelectDropdown/index.tsx b/libs/ui/src/pure/SelectDropdown/index.tsx similarity index 96% rename from apps/cowswap-frontend/src/common/pure/SelectDropdown/index.tsx rename to libs/ui/src/pure/SelectDropdown/index.tsx index 4782f378d4..a3dca19c9c 100644 --- a/apps/cowswap-frontend/src/common/pure/SelectDropdown/index.tsx +++ b/libs/ui/src/pure/SelectDropdown/index.tsx @@ -1,4 +1,4 @@ -import styled from 'styled-components/macro' +import styled from 'styled-components' export const SelectDropdown = styled.select` border-radius: 12px; diff --git a/apps/cowswap-frontend/src/common/pure/TokenAmount/index.tsx b/libs/ui/src/pure/TokenAmount/index.tsx similarity index 76% rename from apps/cowswap-frontend/src/common/pure/TokenAmount/index.tsx rename to libs/ui/src/pure/TokenAmount/index.tsx index 0709e42ad8..c6e9917427 100644 --- a/apps/cowswap-frontend/src/common/pure/TokenAmount/index.tsx +++ b/libs/ui/src/pure/TokenAmount/index.tsx @@ -1,14 +1,11 @@ -import { darken, transparentize } from 'polished' -import styled from 'styled-components/macro' -import { FractionLike, Nullish } from 'types' - -import { LONG_PRECISION } from 'legacy/constants' +import { LONG_PRECISION } from '@cowprotocol/common-const' +import { FeatureFlag, formatTokenAmount, FractionUtils } from '@cowprotocol/common-utils' -import { AMOUNTS_FORMATTING_FEATURE_FLAG } from 'common/constants/featureFlags' -import { TokenSymbol, TokenSymbolProps } from 'common/pure/TokenSymbol' -import { formatTokenAmount } from 'utils/amountFormat' -import { FeatureFlag } from 'utils/featureFlags' -import { FractionUtils } from 'utils/fractionUtils' +import { darken, transparentize } from 'polished' +import styled from 'styled-components' +import { FractionLike, Nullish } from '../../types' +import { TokenSymbol, TokenSymbolProps } from '../TokenSymbol' +import { AMOUNTS_FORMATTING_FEATURE_FLAG } from '../../consts' export const Wrapper = styled.span<{ highlight: boolean; lowVolumeWarning?: boolean }>` background: ${({ highlight }) => (highlight ? 'rgba(196,18,255,0.4)' : '')}; @@ -24,7 +21,7 @@ export const SymbolElement = styled.span<{ opacitySymbol?: boolean }>` export interface TokenAmountProps { amount: Nullish defaultValue?: string - tokenSymbol?: Nullish + tokenSymbol?: TokenSymbolProps['token'] className?: string hideTokenSymbol?: boolean round?: boolean diff --git a/apps/cowswap-frontend/src/common/pure/TokenSymbol/index.tsx b/libs/ui/src/pure/TokenSymbol/index.tsx similarity index 86% rename from apps/cowswap-frontend/src/common/pure/TokenSymbol/index.tsx rename to libs/ui/src/pure/TokenSymbol/index.tsx index 0ee331b0d0..9c18a579e9 100644 --- a/apps/cowswap-frontend/src/common/pure/TokenSymbol/index.tsx +++ b/libs/ui/src/pure/TokenSymbol/index.tsx @@ -1,8 +1,7 @@ import { Currency } from '@uniswap/sdk-core' -import { Nullish } from 'types' - -import { formatSymbol } from 'utils/format' +import { Nullish } from '../../types' +import { formatSymbol } from '@cowprotocol/common-utils' export type TokenSymbolProps = { token: Nullish> diff --git a/apps/cowswap-frontend/src/legacy/components/Tooltip/index.tsx b/libs/ui/src/pure/Tooltip/index.tsx similarity index 91% rename from apps/cowswap-frontend/src/legacy/components/Tooltip/index.tsx rename to libs/ui/src/pure/Tooltip/index.tsx index c93f8b714f..c5d1b41a1d 100644 --- a/apps/cowswap-frontend/src/legacy/components/Tooltip/index.tsx +++ b/libs/ui/src/pure/Tooltip/index.tsx @@ -1,8 +1,8 @@ import { ReactNode, useCallback, useState } from 'react' -import styled from 'styled-components/macro' +import styled from 'styled-components' -import Popover, { PopoverProps } from 'legacy/components/Popover' +import Popover, { PopoverProps } from '../Popover' export const TooltipContainer = styled.div` max-width: 300px; @@ -23,7 +23,7 @@ interface TooltipContentProps extends Omit{text}} {...rest} /> } diff --git a/libs/ui/src/types.ts b/libs/ui/src/types.ts new file mode 100644 index 0000000000..d607182ed4 --- /dev/null +++ b/libs/ui/src/types.ts @@ -0,0 +1,14 @@ +import { Currency, CurrencyAmount, Fraction, Price } from '@uniswap/sdk-core' + +export type Writeable = { -readonly [P in keyof T]: T[P] } + +export type Nullish = T | null | undefined + +export type FractionLike = Fraction | Price | CurrencyAmount + +export type ComposableCowInfo = { + id?: string + parentId?: string + isVirtualPart?: boolean + isTheLastPart?: boolean +} diff --git a/libs/ui/vite.config.ts b/libs/ui/vite.config.ts index 8f939a4cb4..15b6616ffe 100644 --- a/libs/ui/vite.config.ts +++ b/libs/ui/vite.config.ts @@ -1,14 +1,16 @@ /// import { joinPathFragments } from '@nx/devkit' -import react from '@vitejs/plugin-react' +import react from '@vitejs/plugin-react-swc' import { defineConfig } from 'vite' import dts from 'vite-plugin-dts' import viteTsConfigPaths from 'vite-tsconfig-paths' +import macrosPlugin from 'vite-plugin-babel-macros' export default defineConfig({ cacheDir: '../../../node_modules/.vite/ui', plugins: [ + macrosPlugin(), dts({ entryRoot: 'src', tsConfigFilePath: joinPathFragments(__dirname, 'tsconfig.lib.json'), diff --git a/libs/wallet/.babelrc b/libs/wallet/.babelrc new file mode 100644 index 0000000000..ef4889c1ab --- /dev/null +++ b/libs/wallet/.babelrc @@ -0,0 +1,20 @@ +{ + "presets": [ + [ + "@nx/react/babel", + { + "runtime": "automatic", + "useBuiltIns": "usage" + } + ] + ], + "plugins": [ + [ + "styled-components", + { + "pure": true, + "ssr": true + } + ] + ] +} diff --git a/libs/wallet/.eslintrc.json b/libs/wallet/.eslintrc.json new file mode 100644 index 0000000000..231aaa5f83 --- /dev/null +++ b/libs/wallet/.eslintrc.json @@ -0,0 +1,21 @@ +{ + "extends": ["plugin:@nx/react", "../../.eslintrc.json"], + "ignorePatterns": ["!**/*"], + "rules": { + "@typescript-eslint/no-explicit-any": "off" + }, + "overrides": [ + { + "files": ["*.ts", "*.tsx", "*.js", "*.jsx"], + "rules": {} + }, + { + "files": ["*.ts", "*.tsx"], + "rules": {} + }, + { + "files": ["*.js", "*.jsx"], + "rules": {} + } + ] +} diff --git a/libs/wallet/README.md b/libs/wallet/README.md new file mode 100644 index 0000000000..456644fc55 --- /dev/null +++ b/libs/wallet/README.md @@ -0,0 +1 @@ +# Wallet diff --git a/libs/wallet/jest.config.ts b/libs/wallet/jest.config.ts new file mode 100644 index 0000000000..aa0b14146f --- /dev/null +++ b/libs/wallet/jest.config.ts @@ -0,0 +1,11 @@ +/* eslint-disable */ +export default { + displayName: 'wallet', + preset: '../../jest.preset.js', + transform: { + '^(?!.*\\.(js|jsx|ts|tsx|css|json)$)': '@nx/react/plugins/jest', + '^.+\\.[tj]sx?$': ['babel-jest', { presets: ['@nx/react/babel'] }], + }, + moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx'], + coverageDirectory: '../../coverage/libs/wallet', +} diff --git a/libs/wallet/package.json b/libs/wallet/package.json new file mode 100644 index 0000000000..009a1fcbf3 --- /dev/null +++ b/libs/wallet/package.json @@ -0,0 +1,12 @@ +{ + "name": "@cowprotocol/wallet", + "version": "0.0.1", + "main": "./index.js", + "types": "./index.d.ts", + "exports": { + ".": { + "import": "./index.mjs", + "require": "./index.js" + } + } +} diff --git a/libs/wallet/project.json b/libs/wallet/project.json new file mode 100644 index 0000000000..f5415c7955 --- /dev/null +++ b/libs/wallet/project.json @@ -0,0 +1,46 @@ +{ + "name": "@cowprotocol/wallet", + "$schema": "../../node_modules/nx/schemas/project-schema.json", + "sourceRoot": "libs/wallet/src", + "projectType": "library", + "tags": [], + "targets": { + "lint": { + "executor": "@nx/linter:eslint", + "outputs": ["{options.outputFile}"], + "options": { + "lintFilePatterns": ["libs/wallet/**/*.{ts,tsx,js,jsx}"] + } + }, + "build": { + "executor": "@nx/vite:build", + "outputs": ["{options.outputPath}"], + "defaultConfiguration": "production", + "options": { + "outputPath": "dist/libs/wallet" + }, + "configurations": { + "development": { + "mode": "development" + }, + "production": { + "mode": "production" + } + } + }, + "test": { + "executor": "@nx/jest:jest", + "outputs": ["{workspaceRoot}/coverage/{projectRoot}"], + "options": { + "jestConfig": "libs/wallet/jest.config.ts", + "passWithNoTests": true + }, + "configurations": { + "ci": { + "ci": true, + "codeCoverage": true + } + } + } + } +} diff --git a/apps/cowswap-frontend/src/modules/wallet/api/assets/alpha.svg b/libs/wallet/src/api/assets/alpha.svg similarity index 100% rename from apps/cowswap-frontend/src/modules/wallet/api/assets/alpha.svg rename to libs/wallet/src/api/assets/alpha.svg diff --git a/apps/cowswap-frontend/src/modules/wallet/api/assets/ambire.svg b/libs/wallet/src/api/assets/ambire.svg similarity index 100% rename from apps/cowswap-frontend/src/modules/wallet/api/assets/ambire.svg rename to libs/wallet/src/api/assets/ambire.svg diff --git a/apps/cowswap-frontend/src/modules/wallet/api/assets/arrow-right-white.png b/libs/wallet/src/api/assets/arrow-right-white.png similarity index 100% rename from apps/cowswap-frontend/src/modules/wallet/api/assets/arrow-right-white.png rename to libs/wallet/src/api/assets/arrow-right-white.png diff --git a/apps/cowswap-frontend/src/modules/wallet/api/assets/arrow-right.svg b/libs/wallet/src/api/assets/arrow-right.svg similarity index 100% rename from apps/cowswap-frontend/src/modules/wallet/api/assets/arrow-right.svg rename to libs/wallet/src/api/assets/arrow-right.svg diff --git a/apps/cowswap-frontend/src/modules/wallet/api/assets/coinbase.svg b/libs/wallet/src/api/assets/coinbase.svg similarity index 100% rename from apps/cowswap-frontend/src/modules/wallet/api/assets/coinbase.svg rename to libs/wallet/src/api/assets/coinbase.svg diff --git a/apps/cowswap-frontend/src/modules/wallet/api/assets/keystone.svg b/libs/wallet/src/api/assets/keystone.svg similarity index 100% rename from apps/cowswap-frontend/src/modules/wallet/api/assets/keystone.svg rename to libs/wallet/src/api/assets/keystone.svg diff --git a/apps/cowswap-frontend/src/modules/wallet/api/assets/ledger.svg b/libs/wallet/src/api/assets/ledger.svg similarity index 100% rename from apps/cowswap-frontend/src/modules/wallet/api/assets/ledger.svg rename to libs/wallet/src/api/assets/ledger.svg diff --git a/apps/cowswap-frontend/src/modules/wallet/api/assets/metamask.png b/libs/wallet/src/api/assets/metamask.png similarity index 100% rename from apps/cowswap-frontend/src/modules/wallet/api/assets/metamask.png rename to libs/wallet/src/api/assets/metamask.png diff --git a/libs/wallet/src/api/assets/safe-logo.svg b/libs/wallet/src/api/assets/safe-logo.svg new file mode 100644 index 0000000000..9044e15fc0 --- /dev/null +++ b/libs/wallet/src/api/assets/safe-logo.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/apps/cowswap-frontend/src/modules/wallet/api/assets/tally.svg b/libs/wallet/src/api/assets/tally.svg similarity index 100% rename from apps/cowswap-frontend/src/modules/wallet/api/assets/tally.svg rename to libs/wallet/src/api/assets/tally.svg diff --git a/apps/cowswap-frontend/src/modules/wallet/api/assets/trezor.svg b/libs/wallet/src/api/assets/trezor.svg similarity index 100% rename from apps/cowswap-frontend/src/modules/wallet/api/assets/trezor.svg rename to libs/wallet/src/api/assets/trezor.svg diff --git a/apps/cowswap-frontend/src/modules/wallet/api/assets/trust.svg b/libs/wallet/src/api/assets/trust.svg similarity index 100% rename from apps/cowswap-frontend/src/modules/wallet/api/assets/trust.svg rename to libs/wallet/src/api/assets/trust.svg diff --git a/apps/cowswap-frontend/src/modules/wallet/api/assets/wallet-connect-v2.png b/libs/wallet/src/api/assets/wallet-connect-v2.png similarity index 100% rename from apps/cowswap-frontend/src/modules/wallet/api/assets/wallet-connect-v2.png rename to libs/wallet/src/api/assets/wallet-connect-v2.png diff --git a/apps/cowswap-frontend/src/modules/wallet/api/assets/walletConnectIcon.svg b/libs/wallet/src/api/assets/walletConnectIcon.svg similarity index 100% rename from apps/cowswap-frontend/src/modules/wallet/api/assets/walletConnectIcon.svg rename to libs/wallet/src/api/assets/walletConnectIcon.svg diff --git a/apps/cowswap-frontend/src/modules/wallet/api/assets/zengo.svg b/libs/wallet/src/api/assets/zengo.svg similarity index 100% rename from apps/cowswap-frontend/src/modules/wallet/api/assets/zengo.svg rename to libs/wallet/src/api/assets/zengo.svg diff --git a/apps/cowswap-frontend/src/modules/wallet/api/container/Identicon/index.tsx b/libs/wallet/src/api/container/Identicon/index.tsx similarity index 86% rename from apps/cowswap-frontend/src/modules/wallet/api/container/Identicon/index.tsx rename to libs/wallet/src/api/container/Identicon/index.tsx index e395c71c2f..0affb6aac9 100644 --- a/apps/cowswap-frontend/src/modules/wallet/api/container/Identicon/index.tsx +++ b/libs/wallet/src/api/container/Identicon/index.tsx @@ -1,12 +1,11 @@ import React from 'react' import { useLayoutEffect, useMemo, useRef, useState } from 'react' -import jazzicon from '@metamask/jazzicon' - -import useENSAvatar from 'legacy/hooks/useENSAvatar' +import { useWalletInfo } from '../../hooks' +import { Identicon as IdenticonPure } from '../../pure/Identicon' +import { useENSAvatar } from '@cowprotocol/ens' -import { useWalletInfo } from 'modules/wallet' -import { Identicon as IdenticonPure } from 'modules/wallet/api/pure/Identicon' +import jazzicon from '@metamask/jazzicon' export interface IdenticonProps { size?: number diff --git a/apps/cowswap-frontend/src/modules/wallet/api/hooks.ts b/libs/wallet/src/api/hooks.ts similarity index 85% rename from apps/cowswap-frontend/src/modules/wallet/api/hooks.ts rename to libs/wallet/src/api/hooks.ts index a39f16ae0e..d1a0f3d90d 100644 --- a/apps/cowswap-frontend/src/modules/wallet/api/hooks.ts +++ b/libs/wallet/src/api/hooks.ts @@ -1,8 +1,9 @@ import { useAtomValue } from 'jotai' -import { GnosisSafeInfo, useIsSafeApp, WalletDetails, WalletInfo } from 'modules/wallet' - import { gnosisSafeInfoAtom, walletDetailsAtom, walletDisplayedAddress, walletInfoAtom } from './state' +import { GnosisSafeInfo, WalletDetails, WalletInfo } from './types' + +import { useIsSafeApp } from '../web3-react/hooks/useWalletMetadata' export function useWalletInfo(): WalletInfo { return useAtomValue(walletInfoAtom) diff --git a/apps/cowswap-frontend/src/modules/wallet/api/pure/ConnectWalletOption/index.tsx b/libs/wallet/src/api/pure/ConnectWalletOption/index.tsx similarity index 96% rename from apps/cowswap-frontend/src/modules/wallet/api/pure/ConnectWalletOption/index.tsx rename to libs/wallet/src/api/pure/ConnectWalletOption/index.tsx index 3968af2a35..8930e6def5 100644 --- a/apps/cowswap-frontend/src/modules/wallet/api/pure/ConnectWalletOption/index.tsx +++ b/libs/wallet/src/api/pure/ConnectWalletOption/index.tsx @@ -3,8 +3,7 @@ import React from 'react' import { darken, lighten } from 'polished' import styled from 'styled-components/macro' -import { MouseoverTooltip } from 'legacy/components/Tooltip' -import { ExternalLink } from 'legacy/theme' +import { MouseoverTooltip, ExternalLink } from '@cowprotocol/ui' const InfoCard = styled.button<{ isActive?: boolean }>` background-color: ${({ theme, isActive }) => (isActive ? theme.bg3 : theme.bg2)}; @@ -84,7 +83,7 @@ export const HeaderText = styled.div` ` const SubHeader = styled.div` - color: ${({ theme }) => theme.text1}; + color: var(--cow-color-text1); margin-top: 10px; font-size: 12px; ` diff --git a/apps/cowswap-frontend/src/modules/wallet/api/pure/Identicon/index.tsx b/libs/wallet/src/api/pure/Identicon/index.tsx similarity index 95% rename from apps/cowswap-frontend/src/modules/wallet/api/pure/Identicon/index.tsx rename to libs/wallet/src/api/pure/Identicon/index.tsx index 2928b03243..cc9fe088f9 100644 --- a/apps/cowswap-frontend/src/modules/wallet/api/pure/Identicon/index.tsx +++ b/libs/wallet/src/api/pure/Identicon/index.tsx @@ -7,7 +7,7 @@ export const StyledIdenticon = styled.div` width: 1rem; border-radius: 1.125rem; // background-color: ${({ theme }) => theme.bg4}; - background-color: ${({ theme }) => theme.bg1}; // MOD + background-color: var(--cow-container-bg-01); // MOD font-size: initial; ` diff --git a/apps/cowswap-frontend/src/modules/wallet/api/state.ts b/libs/wallet/src/api/state.ts similarity index 87% rename from apps/cowswap-frontend/src/modules/wallet/api/state.ts rename to libs/wallet/src/api/state.ts index 3246caa096..e0d6251bf0 100644 --- a/apps/cowswap-frontend/src/modules/wallet/api/state.ts +++ b/libs/wallet/src/api/state.ts @@ -1,11 +1,8 @@ import { atom } from 'jotai' import { atomWithStorage } from 'jotai/utils' -import { shortenAddress } from 'legacy/utils' - -import { getCurrentChainIdFromUrl } from 'utils/getCurrentChainIdFromUrl' - import { GnosisSafeInfo, WalletDetails, WalletInfo } from './types' +import { getCurrentChainIdFromUrl, shortenAddress } from '@cowprotocol/common-utils' export const walletInfoAtom = atom({ chainId: getCurrentChainIdFromUrl() }) diff --git a/apps/cowswap-frontend/src/modules/wallet/api/types.ts b/libs/wallet/src/api/types.ts similarity index 86% rename from apps/cowswap-frontend/src/modules/wallet/api/types.ts rename to libs/wallet/src/api/types.ts index c0e936ce63..1eef0f0315 100644 --- a/apps/cowswap-frontend/src/modules/wallet/api/types.ts +++ b/libs/wallet/src/api/types.ts @@ -5,9 +5,7 @@ export enum ConnectionType { INJECTED = 'INJECTED', INJECTED_WIDGET = 'INJECTED_WIDGET', COINBASE_WALLET = 'COINBASE_WALLET', - WALLET_CONNECT = 'WALLET_CONNECT', WALLET_CONNECT_V2 = 'WALLET_CONNECT_V2', - FORTMATIC = 'FORTMATIC', NETWORK = 'NETWORK', GNOSIS_SAFE = 'GNOSIS_SAFE', ZENGO = 'ZENGO', @@ -20,7 +18,7 @@ export enum ConnectionType { TREZOR = 'TREZOR', } -export const BACKFILLABLE_WALLETS = [ConnectionType.INJECTED, ConnectionType.WALLET_CONNECT] +export const BACKFILLABLE_WALLETS = [ConnectionType.INJECTED] export interface WalletInfo { chainId: SupportedChainId diff --git a/apps/cowswap-frontend/src/modules/wallet/web3-react/containers/AccountSelectorModal/accountsLoaders.ts b/libs/wallet/src/api/utils/accountsLoaders.ts similarity index 66% rename from apps/cowswap-frontend/src/modules/wallet/web3-react/containers/AccountSelectorModal/accountsLoaders.ts rename to libs/wallet/src/api/utils/accountsLoaders.ts index b25ed641fb..d31813c446 100644 --- a/apps/cowswap-frontend/src/modules/wallet/web3-react/containers/AccountSelectorModal/accountsLoaders.ts +++ b/libs/wallet/src/api/utils/accountsLoaders.ts @@ -1,6 +1,6 @@ -import { ConnectionType } from '../../../api/types' -import { HardWareWallet } from '../../connection' -import { trezorConnection } from '../../connection/trezor' +import { trezorConnection } from '../../web3-react/connection/trezor' +import { HardWareWallet } from '../../web3-react/utils/getIsHardWareWallet' +import { ConnectionType } from '../../api/types' interface WalletAccountsLoader { getAccounts(): string[] | null diff --git a/apps/cowswap-frontend/src/modules/wallet/api/utils/connection.ts b/libs/wallet/src/api/utils/connection.ts similarity index 91% rename from apps/cowswap-frontend/src/modules/wallet/api/utils/connection.ts rename to libs/wallet/src/api/utils/connection.ts index 3c8396afe5..8d7543726f 100644 --- a/apps/cowswap-frontend/src/modules/wallet/api/utils/connection.ts +++ b/libs/wallet/src/api/utils/connection.ts @@ -1,5 +1,4 @@ import CoinbaseWalletIcon from '../assets/coinbase.svg' -import FortmaticIcon from '../assets/formatic.png' import KeystoneImage from '../assets/keystone.svg' import LedgerIcon from '../assets/ledger.svg' import TallyIcon from '../assets/tally.svg' @@ -12,9 +11,7 @@ const connectionTypeToName: Record = { [ConnectionType.INJECTED]: 'injected', [ConnectionType.INJECTED_WIDGET]: 'CowSwap widget', [ConnectionType.COINBASE_WALLET]: 'Coinbase Wallet', - [ConnectionType.WALLET_CONNECT]: 'WalletConnect', [ConnectionType.WALLET_CONNECT_V2]: 'WalletConnect v2', - [ConnectionType.FORTMATIC]: 'Fortmatic', [ConnectionType.NETWORK]: 'Network', [ConnectionType.GNOSIS_SAFE]: 'Safe', [ConnectionType.ZENGO]: 'Zengo', @@ -38,13 +35,11 @@ const connectionTypeToIcon: Record = { [ConnectionType.AMBIRE]: IDENTICON_KEY, [ConnectionType.ALPHA]: IDENTICON_KEY, [ConnectionType.COINBASE_WALLET]: CoinbaseWalletIcon, - [ConnectionType.FORTMATIC]: FortmaticIcon, [ConnectionType.TRUST]: TrustIcon, [ConnectionType.TALLY]: TallyIcon, [ConnectionType.LEDGER]: LedgerIcon, [ConnectionType.TREZOR]: TrezorIcon, [ConnectionType.KEYSTONE]: KeystoneImage, - [ConnectionType.WALLET_CONNECT]: WalletConnectIcon, [ConnectionType.WALLET_CONNECT_V2]: WalletConnectIcon, } @@ -66,7 +61,7 @@ export function getIsMetaMask(): boolean { } export function getIsCoinbaseWallet(): boolean { - return window.ethereum?.isCoinbaseWallet ?? false + return (window.ethereum as { isCoinbaseWallet: boolean })?.isCoinbaseWallet ?? false } export function getIsAmbireWallet(name: string | undefined): boolean { diff --git a/apps/cowswap-frontend/src/modules/wallet/api/utils/getHwAccount.ts b/libs/wallet/src/api/utils/getHwAccount.ts similarity index 86% rename from apps/cowswap-frontend/src/modules/wallet/api/utils/getHwAccount.ts rename to libs/wallet/src/api/utils/getHwAccount.ts index 9c61de9b53..37780bfa50 100644 --- a/apps/cowswap-frontend/src/modules/wallet/api/utils/getHwAccount.ts +++ b/libs/wallet/src/api/utils/getHwAccount.ts @@ -1,4 +1,4 @@ -import { jotaiStore } from 'jotaiStore' +import { jotaiStore } from '@cowprotocol/core' import { hwAccountIndexAtom } from '../state' diff --git a/apps/cowswap-frontend/src/modules/wallet/api/utils/getWalletType.ts b/libs/wallet/src/api/utils/getWalletType.ts similarity index 100% rename from apps/cowswap-frontend/src/modules/wallet/api/utils/getWalletType.ts rename to libs/wallet/src/api/utils/getWalletType.ts diff --git a/apps/cowswap-frontend/src/modules/wallet/api/utils/getWalletTypeLabel.ts b/libs/wallet/src/api/utils/getWalletTypeLabel.ts similarity index 100% rename from apps/cowswap-frontend/src/modules/wallet/api/utils/getWalletTypeLabel.ts rename to libs/wallet/src/api/utils/getWalletTypeLabel.ts diff --git a/libs/wallet/src/assets.ts b/libs/wallet/src/assets.ts new file mode 100644 index 0000000000..086a83a452 --- /dev/null +++ b/libs/wallet/src/assets.ts @@ -0,0 +1,5 @@ +import CoinbaseWalletIcon from './api/assets/coinbase.svg' +import WalletConnectIcon from './api/assets/walletConnectIcon.svg' +import MetaMaskLogo from './api/assets/metamask.png' + +export { CoinbaseWalletIcon, WalletConnectIcon, MetaMaskLogo } diff --git a/apps/cowswap-frontend/src/modules/wallet/constants.ts b/libs/wallet/src/constants.ts similarity index 100% rename from apps/cowswap-frontend/src/modules/wallet/constants.ts rename to libs/wallet/src/constants.ts diff --git a/libs/wallet/src/index.ts b/libs/wallet/src/index.ts new file mode 100644 index 0000000000..119ff2def4 --- /dev/null +++ b/libs/wallet/src/index.ts @@ -0,0 +1,58 @@ +import './types.d.ts' + +export * from './api/types' +export * from './web3-react/types' +export * from './assets' + +// Hooks +export * from './api/hooks' +export * from './web3-react/hooks/useWalletMetadata' +export * from './web3-react/hooks/useIsWalletConnect' +export * from './web3-react/hooks/useSafeAppsSdk' +export * from './web3-react/hooks/useIsSmartContractWallet' + +// Updater +export * from './web3-react/updater' + +// Components +export * from './api/container/Identicon' +export * from './web3-react/pure/AccountIndexSelect' + +// Utils +export * from './api/utils/connection' +export * from './web3-react/utils/getIsHardWareWallet' +export { accountsLoaders } from './api/utils/accountsLoaders' +export { isChainAllowed } from './web3-react/utils/isChainAllowed' +export { getWeb3ReactConnection } from './web3-react/utils/getWeb3ReactConnection' +export { switchChain } from './web3-react/utils/switchChain' + +// Connectors +export { injectedWidgetConnection } from './web3-react/connection/injectedWidget' +export { networkConnection } from './web3-react/connection/network' +export { gnosisSafeConnection } from './web3-react/connection/safe' + +// Connect options +export { + InjectedOption, + InstallMetaMaskOption, + MetaMaskOption, + OpenMetaMaskMobileOption, +} from './web3-react/connection/injected' + +export { InstallKeystoneOption, KeystoneOption } from './web3-react/connection/keystone' +export { LedgerOption } from './web3-react/connection/ledger' +export { TrezorOption } from './web3-react/connection/trezor' +export { TrustWalletOption } from './web3-react/connection/trust' +export { WalletConnectV2Option } from './web3-react/connection/walletConnectV2' +export { AlphaOption } from './web3-react/connection/alpha' +export { AmbireOption } from './web3-react/connection/ambire' +export { CoinbaseWalletOption } from './web3-react/connection/coinbase' + +// State +// TODO: this export is discussable, however it's already used outside +export * from './api/state' +export * from './api/state' + +// Connections +export { injectedConnection } from './web3-react/connection/injected' +export { walletConnectConnectionV2 } from './web3-react/connection/walletConnectV2' diff --git a/libs/wallet/src/types.d.ts b/libs/wallet/src/types.d.ts new file mode 100644 index 0000000000..a3faf97029 --- /dev/null +++ b/libs/wallet/src/types.d.ts @@ -0,0 +1,3 @@ +declare module '@metamask/jazzicon' { + export default function (diameter: number, seed: number): HTMLElement +} diff --git a/apps/cowswap-frontend/src/modules/wallet/web3-react/connection/alpha.tsx b/libs/wallet/src/web3-react/connection/alpha.tsx similarity index 58% rename from apps/cowswap-frontend/src/modules/wallet/web3-react/connection/alpha.tsx rename to libs/wallet/src/web3-react/connection/alpha.tsx index f876343bdf..6226b8ad17 100644 --- a/apps/cowswap-frontend/src/modules/wallet/web3-react/connection/alpha.tsx +++ b/libs/wallet/src/web3-react/connection/alpha.tsx @@ -1,10 +1,8 @@ -import { default as AlphaImage } from 'modules/wallet/api/assets/alpha.svg' -import { getIsAlphaWallet } from 'modules/wallet/api/utils/connection' - +import { default as AlphaImage } from '../../api/assets/alpha.svg' import { ConnectionType } from '../../api/types' +import { getIsAlphaWallet } from '../../api/utils/connection' import { WalletConnectLabeledOption } from '../containers/WalletConnectLabeledOption' - -import { TryActivation } from '.' +import { ConnectionOptionProps } from '../types' const alphaOption = { color: '#4196FC', @@ -12,9 +10,10 @@ const alphaOption = { id: 'alpha', } -export function AlphaOption({ tryActivation }: { tryActivation: TryActivation }) { +export function AlphaOption({ selectedWallet, tryActivation }: ConnectionOptionProps) { return ( { + initCustomProvider(self, connector, +chainIdHex) + }) +} + +/** + * To avoid including external libs for wallet connection in the bundle + * We load them in runtime by demand + */ +export class AsyncConnector extends Connector { + readonly events = new EventEmitter() + + constructor(private loader: () => Promise, actions: Actions, onError?: (error: Error) => void) { + super(actions, onError) + } + + activate(chainId: number): Promise | void { + return this.loader().then((connector) => { + // There is a magic - we change async-connector prototype to the loaded connector + ;(this as any).__proto__ = connector + + return (connector.activate(chainId) || Promise.resolve()).then(() => { + initCustomProvider(this, connector, chainId) + }) + }) + } + + async connectEagerly(chainId: number) { + return this.loader().then((connector) => { + // There is a magic - we change async-connector prototype to the loaded connector + ;(this as any).__proto__ = connector + + const activation = connector.connectEagerly?.(chainId) || Promise.resolve() + + return activation.then(() => { + initCustomProvider(this, connector, chainId) + }) + }) + } +} diff --git a/apps/cowswap-frontend/src/modules/wallet/web3-react/connection/coinbase.tsx b/libs/wallet/src/web3-react/connection/coinbase.tsx similarity index 55% rename from apps/cowswap-frontend/src/modules/wallet/web3-react/connection/coinbase.tsx rename to libs/wallet/src/web3-react/connection/coinbase.tsx index 3bdd198782..408431769e 100644 --- a/apps/cowswap-frontend/src/modules/wallet/web3-react/connection/coinbase.tsx +++ b/libs/wallet/src/web3-react/connection/coinbase.tsx @@ -1,21 +1,18 @@ import { SupportedChainId } from '@cowprotocol/cow-sdk' import { initializeConnector } from '@web3-react/core' -import CowImage from 'legacy/assets/cow-swap/cow_v2.svg' -import { RPC_URLS } from 'legacy/constants/networks' -import { useIsActiveWallet } from 'legacy/hooks/useIsActiveWallet' -import { useSelectedWallet } from 'legacy/state/user/hooks' - -import { ConnectionType } from 'modules/wallet' -import { ConnectWalletOption } from 'modules/wallet/api/pure/ConnectWalletOption' -import { getConnectionName } from 'modules/wallet/api/utils/connection' - +import CowImage from '@cowprotocol/assets/cow-swap/cow_v2.svg' +import { RPC_URLS } from '@cowprotocol/common-const' import { AsyncConnector } from './asyncConnector' import { default as CoinbaseImage } from '../../api/assets/coinbase.svg' -import { Web3ReactConnection } from '../types' +import { ConnectWalletOption } from '../../api/pure/ConnectWalletOption' +import { ConnectionType } from '../../api/types' +import { getConnectionName } from '../../api/utils/connection' +import { ConnectionOptionProps, Web3ReactConnection } from '../types' -import { TryActivation, onError } from '.' +import { useIsActiveConnection } from '../hooks/useIsActiveConnection' +import { onError } from './onError' const coinbaseInjectedOption = { color: '#315CF5', @@ -23,12 +20,6 @@ const coinbaseInjectedOption = { id: 'coinbase-wallet', } -const coinbaseMobileOption = { - ...coinbaseInjectedOption, - header: 'Open in Coinbase Wallet', - link: 'https://go.cb-w.com/mtUDhEZPy1', -} - const [web3CoinbaseWallet, web3CoinbaseWalletHooks] = initializeConnector( (actions) => new AsyncConnector( @@ -57,14 +48,8 @@ export const coinbaseWalletConnection: Web3ReactConnection = { type: ConnectionType.COINBASE_WALLET, } -export function OpenCoinbaseWalletOption() { - const selectedWallet = useSelectedWallet() - const isActive = selectedWallet === ConnectionType.COINBASE_WALLET - return -} - -export function CoinbaseWalletOption({ tryActivation }: { tryActivation: TryActivation }) { - const isActive = useIsActiveWallet(coinbaseWalletConnection) +export function CoinbaseWalletOption({ tryActivation, selectedWallet }: ConnectionOptionProps) { + const isActive = useIsActiveConnection(selectedWallet, coinbaseWalletConnection) return ( MetaMask} - link={METAMASK_DEEP_LINK + window.location} - /> + ) } -export function MetaMaskOption({ tryActivation }: { tryActivation: TryActivation }) { - // const isActive = injectedConnection.hooks.useIsActive() - const isActive = useIsActiveWallet(injectedConnection) // MOD +export function MetaMaskOption({ selectedWallet, tryActivation }: ConnectionOptionProps) { + const isActive = useIsActiveConnection(selectedWallet, injectedConnection) return ( } -export function KeystoneOption({ tryActivation }: { tryActivation: TryActivation }) { - const isActive = useIsActiveWallet(keystoneConnection) +export function KeystoneOption({ selectedWallet, tryActivation }: ConnectionOptionProps) { + const isActive = useIsActiveConnection(selectedWallet, keystoneConnection) return ( void }) { - const isActive = useIsActiveWallet(ledgerConnection) +export function LedgerOption({ selectedWallet, tryActivation }: ConnectionOptionProps) { + const isActive = useIsActiveConnection(selectedWallet, ledgerConnection) return ( ( diff --git a/apps/cowswap-frontend/src/modules/wallet/web3-react/connection/tally.tsx b/libs/wallet/src/web3-react/connection/tally.tsx similarity index 58% rename from apps/cowswap-frontend/src/modules/wallet/web3-react/connection/tally.tsx rename to libs/wallet/src/web3-react/connection/tally.tsx index 614ce529c5..2692c041da 100644 --- a/apps/cowswap-frontend/src/modules/wallet/web3-react/connection/tally.tsx +++ b/libs/wallet/src/web3-react/connection/tally.tsx @@ -1,15 +1,13 @@ import { initializeConnector } from '@web3-react/core' import { Connector } from '@web3-react/types' -import { useIsActiveWallet } from 'legacy/hooks/useIsActiveWallet' - -import { ConnectionType } from 'modules/wallet' -import { default as TallyImage } from 'modules/wallet/api/assets/tally.svg' -import { ConnectWalletOption } from 'modules/wallet/api/pure/ConnectWalletOption' -import { getConnectionName } from 'modules/wallet/api/utils/connection' -import { InjectedWallet } from 'modules/wallet/web3-react/connectors/Injected' - -import { Web3ReactConnection } from '../types' +import { default as TallyImage } from '../../api/assets/tally.svg' +import { ConnectWalletOption } from '../../api/pure/ConnectWalletOption' +import { ConnectionType } from '../../api/types' +import { getConnectionName } from '../../api/utils/connection' +import { InjectedWallet } from '../connectors/Injected' +import { ConnectionOptionProps, Web3ReactConnection } from '../types' +import { useIsActiveConnection } from '../hooks/useIsActiveConnection' const WALLET_LINK = 'https://chrome.google.com/webstore/detail/taho/eajafomhmkipbjmfmhebemolkcicgfmd' const BASE_PROPS = { @@ -32,8 +30,8 @@ export const tallyWalletConnection: Web3ReactConnection = { type: ConnectionType.TALLY, } -export function TallyWalletOption({ tryActivation }: { tryActivation: (connector: Connector) => void }) { - const isActive = useIsActiveWallet(tallyWalletConnection) +export function TallyWalletOption({ selectedWallet, tryActivation }: ConnectionOptionProps) { + const isActive = useIsActiveConnection(selectedWallet, tallyWalletConnection) return ( = { type: ConnectionType.TREZOR, } -export function TrezorOption({ tryActivation }: { tryActivation: (connector: Connector) => void }) { - const isActive = useIsActiveWallet(trezorConnection) +export function TrezorOption({ selectedWallet, tryActivation }: ConnectionOptionProps) { + const isActive = useIsActiveConnection(selectedWallet, trezorConnection) return ( void }) { - const isActive = useIsActiveWallet(trustWalletConnection) +export function TrustWalletInjectedOption({ selectedWallet, tryActivation }: ConnectionOptionProps) { + const isActive = useIsActiveConnection(selectedWallet, trustWalletConnection) return ( void }) { +export function TrustWalletWCOption({ selectedWallet, tryActivation }: ConnectionOptionProps) { return ( ( +function createWalletConnectV2Connector(chainId: SupportedChainId): [AsyncConnector, Web3ReactHooks, Web3ReactStore] { + return initializeConnector( (actions) => - new WalletConnectV2Connector({ + new AsyncConnector( + () => + import('../connectors/WalletConnectV2Connector').then( + (m) => + new m.WalletConnectV2Connector({ + actions, + onError(error) { + console.error('WalletConnect2 ERROR:', error) + }, + options: { + projectId: WC_PROJECT_ID || WC_DEFAULT_PROJECT_ID, + chains: [chainId], + optionalChains: ALL_SUPPORTED_CHAIN_IDS, + showQrModal: true, + rpcMap: RPC_URLS, + }, + }) + ), actions, - onError(error) { - console.error('WalletConnect2 ERROR:', error) - }, - options: { - projectId: WC_PROJECT_ID || WC_DEFAULT_PROJECT_ID, - chains: [chainId], - optionalChains: ALL_SUPPORTED_CHAIN_IDS, - showQrModal: true, - rpcMap: RPC_URLS, - }, - }) + onError + ) ) } @@ -77,6 +81,14 @@ function createWalletConnectV2Connector( function createWc2Connection(chainId = getCurrentChainIdFromUrl()): Web3ReactConnection { let [web3WalletConnectV2, web3WalletConnectV2Hooks] = createWalletConnectV2Connector(chainId) + web3WalletConnectV2Hooks.useProvider = function useProvider() { + const [customProvider, setCustomProvider] = useState(undefined) + + web3WalletConnectV2.events.on(ASYNC_CUSTOM_PROVIDER_EVENT, setCustomProvider) + + return customProvider + } + let onActivate: (() => void) | undefined const proxyConnector = new Proxy( @@ -84,7 +96,7 @@ function createWc2Connection(chainId = getCurrentChainIdFromUrl()): Web3ReactCon { get: (target, p, receiver) => Reflect.get(web3WalletConnectV2, p, receiver), getOwnPropertyDescriptor: (target, p) => Reflect.getOwnPropertyDescriptor(web3WalletConnectV2, p), - getPrototypeOf: () => WalletConnectV2Connector.prototype, + getPrototypeOf: () => AsyncConnector.prototype, set: (target, p, receiver) => Reflect.set(web3WalletConnectV2, p, receiver), } ) as typeof web3WalletConnectV2 @@ -131,10 +143,10 @@ function createWc2Connection(chainId = getCurrentChainIdFromUrl()): Web3ReactCon export const walletConnectConnectionV2 = createWc2Connection() -export function WalletConnectV2Option({ tryActivation }: { tryActivation: TryActivation }) { +export function WalletConnectV2Option({ selectedWallet, tryActivation }: ConnectionOptionProps) { const { walletName } = useWalletMetaData() - const isWalletConnect = useIsActiveWallet(walletConnectConnectionV2) + const isWalletConnect = useIsActiveConnection(selectedWallet, walletConnectConnectionV2) const isActive = isWalletConnect && !getIsZengoWallet(walletName) && @@ -142,7 +154,7 @@ export function WalletConnectV2Option({ tryActivation }: { tryActivation: TryAct !getIsAlphaWallet(walletName) && !getIsTrustWallet(walletName) - const tooltipText = !isActive && isWalletConnect ? WC_DISABLED_TEXT : TOOLTIP_TEXT + const tooltipText = !isActive && isWalletConnect ? WC_DISABLED_TEXT : undefined return ( boolean diff --git a/apps/cowswap-frontend/src/modules/wallet/web3-react/connectors/LedgerConnector.tsx b/libs/wallet/src/web3-react/connectors/LedgerConnector.tsx similarity index 100% rename from apps/cowswap-frontend/src/modules/wallet/web3-react/connectors/LedgerConnector.tsx rename to libs/wallet/src/web3-react/connectors/LedgerConnector.tsx diff --git a/apps/cowswap-frontend/src/modules/wallet/web3-react/connectors/TrezorConnector/TrezorProvider.ts b/libs/wallet/src/web3-react/connectors/TrezorConnector/TrezorProvider.ts similarity index 100% rename from apps/cowswap-frontend/src/modules/wallet/web3-react/connectors/TrezorConnector/TrezorProvider.ts rename to libs/wallet/src/web3-react/connectors/TrezorConnector/TrezorProvider.ts diff --git a/apps/cowswap-frontend/src/modules/wallet/web3-react/connectors/TrezorConnector/getAccountsList.ts b/libs/wallet/src/web3-react/connectors/TrezorConnector/getAccountsList.ts similarity index 97% rename from apps/cowswap-frontend/src/modules/wallet/web3-react/connectors/TrezorConnector/getAccountsList.ts rename to libs/wallet/src/web3-react/connectors/TrezorConnector/getAccountsList.ts index f08d0deae1..be5123c9a3 100644 --- a/apps/cowswap-frontend/src/modules/wallet/web3-react/connectors/TrezorConnector/getAccountsList.ts +++ b/libs/wallet/src/web3-react/connectors/TrezorConnector/getAccountsList.ts @@ -1,7 +1,7 @@ import { publicToAddress } from 'ethereumjs-util' import HDNode from 'hdkey' -import { TREZOR_DERIVATION_PATH } from 'modules/wallet/api/utils/getHwAccount' +import { TREZOR_DERIVATION_PATH } from '../../../api/utils/getHwAccount' import type { TrezorConnect } from '@trezor/connect-web' diff --git a/apps/cowswap-frontend/src/modules/wallet/web3-react/connectors/TrezorConnector/index.ts b/libs/wallet/src/web3-react/connectors/TrezorConnector/index.ts similarity index 97% rename from apps/cowswap-frontend/src/modules/wallet/web3-react/connectors/TrezorConnector/index.ts rename to libs/wallet/src/web3-react/connectors/TrezorConnector/index.ts index 5091f5a351..719b0b33b5 100644 --- a/apps/cowswap-frontend/src/modules/wallet/web3-react/connectors/TrezorConnector/index.ts +++ b/libs/wallet/src/web3-react/connectors/TrezorConnector/index.ts @@ -1,16 +1,14 @@ import { SupportedChainId } from '@cowprotocol/cow-sdk' import { Connector } from '@web3-react/types' -import { RPC_URLS } from 'legacy/constants/networks' - -import { getCurrentChainIdFromUrl } from 'utils/getCurrentChainIdFromUrl' - import { TrezorProvider } from './TrezorProvider' import { getHwAccount } from '../../../api/utils/getHwAccount' import type transformTypedData from '@trezor/connect-plugin-ethereum' import type { TrezorConnect } from '@trezor/connect-web' +import { getCurrentChainIdFromUrl } from '@cowprotocol/common-utils' +import { RPC_URLS } from '@cowprotocol/common-const' const defaultChainId = getCurrentChainIdFromUrl() diff --git a/apps/cowswap-frontend/src/modules/wallet/web3-react/connectors/TrezorConnector/sendTransactionHandler.ts b/libs/wallet/src/web3-react/connectors/TrezorConnector/sendTransactionHandler.ts similarity index 95% rename from apps/cowswap-frontend/src/modules/wallet/web3-react/connectors/TrezorConnector/sendTransactionHandler.ts rename to libs/wallet/src/web3-react/connectors/TrezorConnector/sendTransactionHandler.ts index 4dd13e7c77..a0d0e6f834 100644 --- a/apps/cowswap-frontend/src/modules/wallet/web3-react/connectors/TrezorConnector/sendTransactionHandler.ts +++ b/libs/wallet/src/web3-react/connectors/TrezorConnector/sendTransactionHandler.ts @@ -3,13 +3,10 @@ import { JsonRpcProvider } from '@ethersproject/providers' import { serialize } from '@ethersproject/transactions' import { EthereumTransaction } from '@trezor/connect' -import { jotaiStore } from 'jotaiStore' - -import { gasPriceAtom } from 'modules/gasPirce' - import { getHwAccount } from '../../../api/utils/getHwAccount' import type { TrezorConnect } from '@trezor/connect-web' +import { gasPriceAtom, jotaiStore } from '@cowprotocol/core' // TODO: use API or Oracle for gas price const DEFAULT_GOERLI_GAS_PRICE = 40 * 10 ** 9 // 40 GWEI diff --git a/apps/cowswap-frontend/src/modules/wallet/web3-react/connectors/TrezorConnector/signTypedDataHandler.ts b/libs/wallet/src/web3-react/connectors/TrezorConnector/signTypedDataHandler.ts similarity index 100% rename from apps/cowswap-frontend/src/modules/wallet/web3-react/connectors/TrezorConnector/signTypedDataHandler.ts rename to libs/wallet/src/web3-react/connectors/TrezorConnector/signTypedDataHandler.ts diff --git a/apps/cowswap-frontend/src/modules/wallet/web3-react/connectors/WalletConnectV2Connector/index.tsx b/libs/wallet/src/web3-react/connectors/WalletConnectV2Connector/index.tsx similarity index 100% rename from apps/cowswap-frontend/src/modules/wallet/web3-react/connectors/WalletConnectV2Connector/index.tsx rename to libs/wallet/src/web3-react/connectors/WalletConnectV2Connector/index.tsx diff --git a/apps/cowswap-frontend/src/modules/wallet/web3-react/containers/WalletConnectLabeledOption/index.tsx b/libs/wallet/src/web3-react/containers/WalletConnectLabeledOption/index.tsx similarity index 72% rename from apps/cowswap-frontend/src/modules/wallet/web3-react/containers/WalletConnectLabeledOption/index.tsx rename to libs/wallet/src/web3-react/containers/WalletConnectLabeledOption/index.tsx index 3ad6efbb26..7c913664a4 100644 --- a/apps/cowswap-frontend/src/modules/wallet/web3-react/containers/WalletConnectLabeledOption/index.tsx +++ b/libs/wallet/src/web3-react/containers/WalletConnectLabeledOption/index.tsx @@ -1,20 +1,19 @@ -import { useIsActiveWallet } from 'legacy/hooks/useIsActiveWallet' - -import { useFeatureFlags } from 'common/hooks/featureFlags/useFeatureFlags' - import { ConnectWalletOption } from '../../../api/pure/ConnectWalletOption' import { ConnectionType } from '../../../api/types' import { getConnectionName } from '../../../api/utils/connection' import { WC_DISABLED_TEXT } from '../../../constants' -import { TryActivation } from '../../connection' -import { walletConnectConnection } from '../../connection/walletConnect' import { walletConnectConnectionV2 } from '../../connection/walletConnectV2' import { useWalletMetaData } from '../../hooks/useWalletMetadata' +import { Connector } from '@web3-react/types' +import { useIsActiveConnection } from '../../hooks/useIsActiveConnection' + +type TryActivation = (connector: Connector) => void interface WalletConnectLabeledOptionProps { connectionType: ConnectionType tryActivation: TryActivation checkWalletName(walletName: string | undefined): boolean + selectedWallet: string | undefined options: { color: string icon: string @@ -27,13 +26,13 @@ export function WalletConnectLabeledOption({ tryActivation, checkWalletName, options, + selectedWallet, }: WalletConnectLabeledOptionProps) { const { walletName } = useWalletMetaData() - const { walletConnectV1Enabled } = useFeatureFlags() - const connection = walletConnectV1Enabled ? walletConnectConnection : walletConnectConnectionV2 + const connection = walletConnectConnectionV2 - const isWalletConnect = useIsActiveWallet(connection) + const isWalletConnect = useIsActiveConnection(selectedWallet, connection) const isActive = isWalletConnect && checkWalletName(walletName) const tooltipText = !isActive && isWalletConnect ? WC_DISABLED_TEXT : null diff --git a/libs/wallet/src/web3-react/hooks/useIsActiveConnection.ts b/libs/wallet/src/web3-react/hooks/useIsActiveConnection.ts new file mode 100644 index 0000000000..211429411b --- /dev/null +++ b/libs/wallet/src/web3-react/hooks/useIsActiveConnection.ts @@ -0,0 +1,16 @@ +import { Web3ReactConnection } from '../types' +import { useWeb3React } from '@web3-react/core' + +export const useIsActiveConnection = (selectedWallet: string | undefined, connection: Web3ReactConnection) => { + const { account } = useWeb3React() + + const isActive = connection.hooks.useIsActive() + + if (!isActive) { + return false + } else if (isActive && !selectedWallet && account) { + return true + } else { + return selectedWallet === connection.type + } +} diff --git a/libs/wallet/src/web3-react/hooks/useIsSmartContractWallet.ts b/libs/wallet/src/web3-react/hooks/useIsSmartContractWallet.ts new file mode 100644 index 0000000000..ae423d2e22 --- /dev/null +++ b/libs/wallet/src/web3-react/hooks/useIsSmartContractWallet.ts @@ -0,0 +1,87 @@ +import { useState, useEffect, useMemo } from 'react' + +import { useWeb3React } from '@web3-react/core' + +import useSWR from 'swr' +import { useAsyncMemo } from 'use-async-memo' +import { useWalletInfo } from '../../api/hooks' +import { useWalletMetaData } from './useWalletMetadata' +import { getIsAmbireWallet } from '../../api/utils/connection' +import { Contract } from '@ethersproject/contracts' +import { getProviderOrSigner } from '@cowprotocol/common-utils' +import { ARGENT_WALLET_DETECTOR_ADDRESS } from '@cowprotocol/common-const' +import { ArgentWalletDetectorAbi } from '@cowprotocol/abis' + +function useCheckIsSmartContract(): boolean | undefined { + const { provider } = useWeb3React() + const { account } = useWalletInfo() + + const { data } = useSWR(['isSmartContract', account, provider], async () => { + if (!account || !provider) { + return false + } + + try { + const code = await provider.getCode(account) + return code !== '0x' + } catch (e: any) { + console.debug(`checkIsSmartContractWallet: failed to check address ${account}`, e.message) + return false + } + }) + + return data +} + +export function useIsSmartContractWallet(): boolean { + const [isSmartContractWallet, setIsSmartContractWallet] = useState(false) + + const { account } = useWalletInfo() + + const isArgentWallet = useIsArgentWallet() + const isSmartContract = useCheckIsSmartContract() + const isAmbireWallet = useIsAmbireWallet() + + useEffect(() => { + if (!account) { + setIsSmartContractWallet(false) + return + } + + if (isAmbireWallet || isArgentWallet || isSmartContract) { + setIsSmartContractWallet(true) + } + }, [account, isAmbireWallet, isArgentWallet, isSmartContract]) + + return isSmartContractWallet +} + +function useIsArgentWallet(): boolean { + const { provider } = useWeb3React() + const { account, chainId } = useWalletInfo() + const argentWalletContract = useMemo(() => { + if (!provider) return null + + const address = ARGENT_WALLET_DETECTOR_ADDRESS[chainId] + + if (!address) return null + + return new Contract(address, ArgentWalletDetectorAbi, getProviderOrSigner(provider, account)) + }, [chainId, account, provider]) + + return useAsyncMemo( + () => { + if (!argentWalletContract || !account) return Promise.resolve(false) + + return argentWalletContract.callStatic.isArgentWallet(account) + }, + [argentWalletContract], + false + ) +} + +function useIsAmbireWallet(): boolean { + const { walletName } = useWalletMetaData() + + return getIsAmbireWallet(walletName) +} diff --git a/apps/cowswap-frontend/src/modules/wallet/web3-react/hooks/useIsWalletConnect.ts b/libs/wallet/src/web3-react/hooks/useIsWalletConnect.ts similarity index 75% rename from apps/cowswap-frontend/src/modules/wallet/web3-react/hooks/useIsWalletConnect.ts rename to libs/wallet/src/web3-react/hooks/useIsWalletConnect.ts index 257f02da17..2c35dd1e52 100644 --- a/apps/cowswap-frontend/src/modules/wallet/web3-react/hooks/useIsWalletConnect.ts +++ b/libs/wallet/src/web3-react/hooks/useIsWalletConnect.ts @@ -4,7 +4,7 @@ import { useWeb3React } from '@web3-react/core' import { Connector } from '@web3-react/types' import { ConnectionType } from '../../api/types' -import { getWeb3ReactConnection } from '../connection' +import { getWeb3ReactConnection } from '../utils/getWeb3ReactConnection' export function useIsWalletConnect(): boolean { const { connector } = useWeb3React() @@ -17,5 +17,5 @@ export function useIsWalletConnect(): boolean { export function getIsWalletConnect(connector: Connector): boolean { const connection = getWeb3ReactConnection(connector) - return [ConnectionType.WALLET_CONNECT, ConnectionType.WALLET_CONNECT_V2].includes(connection.type) + return ConnectionType.WALLET_CONNECT_V2 === connection.type } diff --git a/apps/cowswap-frontend/src/modules/wallet/web3-react/hooks/useSafeAppsSdk.ts b/libs/wallet/src/web3-react/hooks/useSafeAppsSdk.ts similarity index 100% rename from apps/cowswap-frontend/src/modules/wallet/web3-react/hooks/useSafeAppsSdk.ts rename to libs/wallet/src/web3-react/hooks/useSafeAppsSdk.ts diff --git a/apps/cowswap-frontend/src/modules/wallet/web3-react/hooks/useSafeAppsSdkInfo.test.tsx b/libs/wallet/src/web3-react/hooks/useSafeAppsSdkInfo.test.tsx similarity index 100% rename from apps/cowswap-frontend/src/modules/wallet/web3-react/hooks/useSafeAppsSdkInfo.test.tsx rename to libs/wallet/src/web3-react/hooks/useSafeAppsSdkInfo.test.tsx diff --git a/apps/cowswap-frontend/src/modules/wallet/web3-react/hooks/useSafeAppsSdkInfo.ts b/libs/wallet/src/web3-react/hooks/useSafeAppsSdkInfo.ts similarity index 87% rename from apps/cowswap-frontend/src/modules/wallet/web3-react/hooks/useSafeAppsSdkInfo.ts rename to libs/wallet/src/web3-react/hooks/useSafeAppsSdkInfo.ts index b13ddedfb9..184f6be051 100644 --- a/apps/cowswap-frontend/src/modules/wallet/web3-react/hooks/useSafeAppsSdkInfo.ts +++ b/libs/wallet/src/web3-react/hooks/useSafeAppsSdkInfo.ts @@ -2,7 +2,7 @@ import { useEffect, useState } from 'react' import type { SafeInfo } from '@safe-global/safe-apps-sdk' -import { useSafeAppsSdk } from 'modules/wallet/web3-react/hooks/useSafeAppsSdk' +import { useSafeAppsSdk } from './useSafeAppsSdk' export type GnosisSafeSdkInfo = SafeInfo diff --git a/apps/cowswap-frontend/src/modules/wallet/web3-react/hooks/useWalletMetadata.ts b/libs/wallet/src/web3-react/hooks/useWalletMetadata.ts similarity index 88% rename from apps/cowswap-frontend/src/modules/wallet/web3-react/hooks/useWalletMetadata.ts rename to libs/wallet/src/web3-react/hooks/useWalletMetadata.ts index c6bb20f608..c18dd20db5 100644 --- a/apps/cowswap-frontend/src/modules/wallet/web3-react/hooks/useWalletMetadata.ts +++ b/libs/wallet/src/web3-react/hooks/useWalletMetadata.ts @@ -2,10 +2,10 @@ import { useMemo } from 'react' import { useWeb3React } from '@web3-react/core' -import { ConnectionType } from 'modules/wallet' -import { default as AlphaImage } from 'modules/wallet/api/assets/alpha.svg' -import { getIsAlphaWallet } from 'modules/wallet/api/utils/connection' -import { getWeb3ReactConnection } from 'modules/wallet/web3-react/connection' +import { default as AlphaImage } from '../../api/assets/alpha.svg' +import { ConnectionType } from '../../api/types' +import { getIsAlphaWallet } from '../../api/utils/connection' +import { getWeb3ReactConnection } from '../utils/getWeb3ReactConnection' const WC_DESKTOP_GNOSIS_SAFE_APP_NAME = 'WalletConnect Safe App' const WC_MOBILE_GNOSIS_SAFE_APP_NAME = 'Safe' @@ -75,7 +75,7 @@ export function useWalletMetaData(): WalletMetaData { return METADATA_DISCONNECTED } - if (connectionType === ConnectionType.WALLET_CONNECT || connectionType === ConnectionType.WALLET_CONNECT_V2) { + if (connectionType === ConnectionType.WALLET_CONNECT_V2) { const wc = provider?.provider if ((wc as any)?.isWalletConnect) { diff --git a/apps/cowswap-frontend/src/modules/wallet/web3-react/pure/AccountIndexSelect/index.cosmos.tsx b/libs/wallet/src/web3-react/pure/AccountIndexSelect/index.cosmos.tsx similarity index 92% rename from apps/cowswap-frontend/src/modules/wallet/web3-react/pure/AccountIndexSelect/index.cosmos.tsx rename to libs/wallet/src/web3-react/pure/AccountIndexSelect/index.cosmos.tsx index 82b5a0fc62..98c54b5463 100644 --- a/apps/cowswap-frontend/src/modules/wallet/web3-react/pure/AccountIndexSelect/index.cosmos.tsx +++ b/libs/wallet/src/web3-react/pure/AccountIndexSelect/index.cosmos.tsx @@ -1,9 +1,8 @@ +import { WETH_GOERLI } from '@cowprotocol/common-const' import { CurrencyAmount } from '@uniswap/sdk-core' import styled from 'styled-components/macro' -import { WETH_GOERLI } from 'legacy/utils/goerli/constants' - import { AccountIndexSelect } from './index' const accountsList = [ @@ -25,7 +24,7 @@ const Wrapper = styled.div` margin: 100px auto; padding: 20px; - background: ${({ theme }) => theme.bg1}; + background: var(--cow-container-bg-01); ` const Fixtures = { diff --git a/apps/cowswap-frontend/src/modules/wallet/web3-react/pure/AccountIndexSelect/index.tsx b/libs/wallet/src/web3-react/pure/AccountIndexSelect/index.tsx similarity index 83% rename from apps/cowswap-frontend/src/modules/wallet/web3-react/pure/AccountIndexSelect/index.tsx rename to libs/wallet/src/web3-react/pure/AccountIndexSelect/index.tsx index c5414dfff3..a3e1fc4736 100644 --- a/apps/cowswap-frontend/src/modules/wallet/web3-react/pure/AccountIndexSelect/index.tsx +++ b/libs/wallet/src/web3-react/pure/AccountIndexSelect/index.tsx @@ -2,14 +2,8 @@ import { useCallback, useRef, useState } from 'react' import { Currency, CurrencyAmount } from '@uniswap/sdk-core' -import { Trans } from '@lingui/macro' - -import { ButtonPrimary } from 'legacy/components/Button' -import Loader from 'legacy/components/Loader' -import { shortenAddress } from 'legacy/utils' - -import { SelectDropdown } from 'common/pure/SelectDropdown' -import { TokenAmount } from 'common/pure/TokenAmount' +import { ButtonPrimary, Loader, SelectDropdown, TokenAmount } from '@cowprotocol/ui' +import { shortenAddress } from '@cowprotocol/common-utils' import * as styledEl from './styled' @@ -50,8 +44,7 @@ export function AccountIndexSelect(props: AccountIndexSelectProps) { <> - Please select which account you would like to use: - + Please select which account you would like to use: {accountsList.map((address, index) => { @@ -75,17 +68,17 @@ export function AccountIndexSelect(props: AccountIndexSelectProps) { {loadingAccounts ? ( <> - Loading... + Loading... ) : ( - Load more + 'Load more' )} - Connect selected account + Connect selected account diff --git a/apps/cowswap-frontend/src/modules/wallet/web3-react/pure/AccountIndexSelect/styled.tsx b/libs/wallet/src/web3-react/pure/AccountIndexSelect/styled.tsx similarity index 95% rename from apps/cowswap-frontend/src/modules/wallet/web3-react/pure/AccountIndexSelect/styled.tsx rename to libs/wallet/src/web3-react/pure/AccountIndexSelect/styled.tsx index 3ff7fa9229..a1e0d7d32d 100644 --- a/apps/cowswap-frontend/src/modules/wallet/web3-react/pure/AccountIndexSelect/styled.tsx +++ b/libs/wallet/src/web3-react/pure/AccountIndexSelect/styled.tsx @@ -1,6 +1,6 @@ import styled from 'styled-components/macro' -import { ButtonSecondary } from 'common/pure/ButtonSecondary' +import { ButtonSecondary } from '@cowprotocol/ui' export const Wrapper = styled.div` ${({ theme }) => theme.flexColumnNoWrap}; diff --git a/apps/cowswap-frontend/src/modules/wallet/web3-react/types.ts b/libs/wallet/src/web3-react/types.ts similarity index 58% rename from apps/cowswap-frontend/src/modules/wallet/web3-react/types.ts rename to libs/wallet/src/web3-react/types.ts index 304e1dcee5..0f92a8de1e 100644 --- a/apps/cowswap-frontend/src/modules/wallet/web3-react/types.ts +++ b/libs/wallet/src/web3-react/types.ts @@ -2,7 +2,7 @@ import { SupportedChainId } from '@cowprotocol/cow-sdk' import { Web3ReactHooks } from '@web3-react/core' import { Connector } from '@web3-react/types' -import { ConnectionType } from 'modules/wallet' +import { ConnectionType } from '../api/types' export interface Web3ReactConnection { connector: T @@ -10,3 +10,11 @@ export interface Web3ReactConnection { type: ConnectionType overrideActivate?: (chainId: SupportedChainId) => boolean } + +export type TryActivation = (connector: Connector) => void + +export interface ConnectionOptionProps { + darkMode: boolean + selectedWallet: string | undefined + tryActivation: TryActivation +} diff --git a/apps/cowswap-frontend/src/modules/wallet/web3-react/updater.ts b/libs/wallet/src/web3-react/updater.ts similarity index 84% rename from apps/cowswap-frontend/src/modules/wallet/web3-react/updater.ts rename to libs/wallet/src/web3-react/updater.ts index 809f64259f..dbfc009891 100644 --- a/apps/cowswap-frontend/src/modules/wallet/web3-react/updater.ts +++ b/libs/wallet/src/web3-react/updater.ts @@ -3,22 +3,22 @@ import { useEffect, useMemo, useState } from 'react' import { useWeb3React } from '@web3-react/core' -import { UNSUPPORTED_WC_WALLETS } from 'legacy/constants' -import useENSName from 'legacy/hooks/useENSName' - -import { useIsSafeWallet, useWalletMetaData } from 'modules/wallet' -import { getWalletType } from 'modules/wallet/api/utils/getWalletType' - -import { getSafeInfo } from 'api/gnosisSafe' -import { useIsProviderNetworkUnsupported } from 'common/hooks/useIsProviderNetworkUnsupported' -import { useIsSmartContractWallet } from 'common/hooks/useIsSmartContractWallet' -import { getCurrentChainIdFromUrl } from 'utils/getCurrentChainIdFromUrl' +import { getSafeInfo } from '@cowprotocol/core' +import { getCurrentChainIdFromUrl } from '@cowprotocol/common-utils' import { useSafeAppsSdkInfo } from './hooks/useSafeAppsSdkInfo' +import { useIsSafeWallet, useWalletMetaData } from './hooks/useWalletMetadata' import { gnosisSafeInfoAtom, walletDetailsAtom, walletInfoAtom } from '../api/state' import { GnosisSafeInfo, WalletDetails, WalletInfo } from '../api/types' +import { getWalletType } from '../api/utils/getWalletType' import { getWalletTypeLabel } from '../api/utils/getWalletTypeLabel' +import { useIsSmartContractWallet } from './hooks/useIsSmartContractWallet' +import { SupportedChainId } from '@cowprotocol/cow-sdk' +import { useENSName } from '@cowprotocol/ens' + +// Smart contract wallets are filtered out by default, no need to add them to this list +const UNSUPPORTED_WC_WALLETS = new Set(['DeFi Wallet', 'WallETH']) function _checkIsSupportedWallet(walletName?: string): boolean { return !(walletName && UNSUPPORTED_WC_WALLETS.has(walletName)) @@ -26,7 +26,7 @@ function _checkIsSupportedWallet(walletName?: string): boolean { function _useWalletInfo(): WalletInfo { const { account, chainId, isActive: active } = useWeb3React() - const isChainIdUnsupported = useIsProviderNetworkUnsupported() + const isChainIdUnsupported = !!chainId && !(chainId in SupportedChainId) return useMemo( () => ({ diff --git a/libs/wallet/src/web3-react/utils/getIsHardWareWallet.ts b/libs/wallet/src/web3-react/utils/getIsHardWareWallet.ts new file mode 100644 index 0000000000..ec20354da7 --- /dev/null +++ b/libs/wallet/src/web3-react/utils/getIsHardWareWallet.ts @@ -0,0 +1,9 @@ +import { ConnectionType } from '../../api/types' + +// TODO: add others +export const HARDWARE_WALLETS = [ConnectionType.TREZOR] as const + +export type HardWareWallet = (typeof HARDWARE_WALLETS)[number] + +export const getIsHardWareWallet = (connectionType: ConnectionType) => + HARDWARE_WALLETS.includes(connectionType as HardWareWallet) diff --git a/libs/wallet/src/web3-react/utils/getWeb3ReactConnection.ts b/libs/wallet/src/web3-react/utils/getWeb3ReactConnection.ts new file mode 100644 index 0000000000..85251539cb --- /dev/null +++ b/libs/wallet/src/web3-react/utils/getWeb3ReactConnection.ts @@ -0,0 +1,45 @@ +import { Connector } from '@web3-react/types' + +import { ConnectionType } from '../../api/types' +import { coinbaseWalletConnection } from '../connection/coinbase' +import { injectedConnection } from '../connection/injected' +import { injectedWidgetConnection } from '../connection/injectedWidget' +import { keystoneConnection } from '../connection/keystone' +import { ledgerConnection } from '../connection/ledger' +import { networkConnection } from '../connection/network' +import { gnosisSafeConnection } from '../connection/safe' +import { tallyWalletConnection } from '../connection/tally' +import { trezorConnection } from '../connection/trezor' +import { trustWalletConnection } from '../connection/trust' +import { walletConnectConnectionV2 } from '../connection/walletConnectV2' +import { Web3ReactConnection } from '../types' + +const connectionTypeToConnection: Record = { + [ConnectionType.INJECTED]: injectedConnection, + [ConnectionType.COINBASE_WALLET]: coinbaseWalletConnection, + [ConnectionType.WALLET_CONNECT_V2]: walletConnectConnectionV2, + [ConnectionType.ZENGO]: walletConnectConnectionV2, + [ConnectionType.NETWORK]: networkConnection, + [ConnectionType.GNOSIS_SAFE]: gnosisSafeConnection, + [ConnectionType.AMBIRE]: walletConnectConnectionV2, + [ConnectionType.ALPHA]: walletConnectConnectionV2, + [ConnectionType.TALLY]: tallyWalletConnection, + [ConnectionType.TRUST]: trustWalletConnection, + [ConnectionType.LEDGER]: ledgerConnection, + [ConnectionType.KEYSTONE]: keystoneConnection, + [ConnectionType.INJECTED_WIDGET]: injectedWidgetConnection, + [ConnectionType.TREZOR]: trezorConnection, +} +const CONNECTIONS: Web3ReactConnection[] = Object.values(connectionTypeToConnection) + +export function getWeb3ReactConnection(c: Connector | ConnectionType): Web3ReactConnection { + if (c instanceof Connector) { + const connection = CONNECTIONS.find((connection) => connection.connector === c) + if (!connection) { + throw Error('unsupported connector') + } + return connection + } + + return connectionTypeToConnection[c] +} diff --git a/libs/wallet/src/web3-react/utils/isChainAllowed.ts b/libs/wallet/src/web3-react/utils/isChainAllowed.ts new file mode 100644 index 0000000000..645ca8d4d3 --- /dev/null +++ b/libs/wallet/src/web3-react/utils/isChainAllowed.ts @@ -0,0 +1,29 @@ +import { ALL_SUPPORTED_CHAIN_IDS, SupportedChainId } from '@cowprotocol/cow-sdk' +import { Connector } from '@web3-react/types' + +import { getWeb3ReactConnection } from './getWeb3ReactConnection' + +import { ConnectionType } from '../../api/types' + +const allowedChainsByWallet: Record = { + [ConnectionType.INJECTED]: ALL_SUPPORTED_CHAIN_IDS, + [ConnectionType.INJECTED_WIDGET]: ALL_SUPPORTED_CHAIN_IDS, + [ConnectionType.COINBASE_WALLET]: ALL_SUPPORTED_CHAIN_IDS, + [ConnectionType.WALLET_CONNECT_V2]: ALL_SUPPORTED_CHAIN_IDS, + [ConnectionType.NETWORK]: ALL_SUPPORTED_CHAIN_IDS, + [ConnectionType.GNOSIS_SAFE]: ALL_SUPPORTED_CHAIN_IDS, + [ConnectionType.TALLY]: ALL_SUPPORTED_CHAIN_IDS, + [ConnectionType.TRUST]: ALL_SUPPORTED_CHAIN_IDS, + [ConnectionType.LEDGER]: ALL_SUPPORTED_CHAIN_IDS, + [ConnectionType.TREZOR]: ALL_SUPPORTED_CHAIN_IDS, + [ConnectionType.KEYSTONE]: ALL_SUPPORTED_CHAIN_IDS, + [ConnectionType.ALPHA]: [], + [ConnectionType.AMBIRE]: [], + [ConnectionType.ZENGO]: [], +} + +export function isChainAllowed(connector: Connector, chainId: number): boolean { + const connection = getWeb3ReactConnection(connector) + + return allowedChainsByWallet[connection.type].includes(chainId) +} diff --git a/apps/cowswap-frontend/src/modules/wallet/web3-react/hooks/switchChain.ts b/libs/wallet/src/web3-react/utils/switchChain.ts similarity index 84% rename from apps/cowswap-frontend/src/modules/wallet/web3-react/hooks/switchChain.ts rename to libs/wallet/src/web3-react/utils/switchChain.ts index cc71d43534..66f9dd2758 100644 --- a/apps/cowswap-frontend/src/modules/wallet/web3-react/hooks/switchChain.ts +++ b/libs/wallet/src/web3-react/utils/switchChain.ts @@ -1,13 +1,12 @@ import { SupportedChainId } from '@cowprotocol/cow-sdk' import { Connector } from '@web3-react/types' -import { getChainInfo } from 'legacy/constants/chainInfo' -import { RPC_URLS } from 'legacy/constants/networks' - -import { getIsWalletConnect } from './useIsWalletConnect' +import { getWeb3ReactConnection } from './getWeb3ReactConnection' +import { isChainAllowed } from './isChainAllowed' import { ConnectionType } from '../../api/types' -import { getWeb3ReactConnection, isChainAllowed } from '../connection' +import { getIsWalletConnect } from '../hooks/useIsWalletConnect' +import { getChainInfo, RPC_URLS } from '@cowprotocol/common-const' function getRpcUrls(chainId: SupportedChainId): [string] { switch (chainId) { diff --git a/libs/wallet/tsconfig.json b/libs/wallet/tsconfig.json new file mode 100644 index 0000000000..bab74ff2e6 --- /dev/null +++ b/libs/wallet/tsconfig.json @@ -0,0 +1,21 @@ +{ + "compilerOptions": { + "jsx": "react-jsx", + "allowJs": false, + "esModuleInterop": false, + "allowSyntheticDefaultImports": true, + "strict": true, + "types": ["vite/client"] + }, + "files": [], + "include": [], + "references": [ + { + "path": "./tsconfig.lib.json" + }, + { + "path": "./tsconfig.spec.json" + } + ], + "extends": "../../tsconfig.base.json" +} diff --git a/libs/wallet/tsconfig.lib.json b/libs/wallet/tsconfig.lib.json new file mode 100644 index 0000000000..1b2b0c12df --- /dev/null +++ b/libs/wallet/tsconfig.lib.json @@ -0,0 +1,19 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "../../dist/out-tsc", + "types": ["node", "vite/client"] + }, + "files": ["../../node_modules/@nx/react/typings/cssmodule.d.ts", "../../node_modules/@nx/react/typings/image.d.ts"], + "exclude": [ + "**/*.spec.ts", + "**/*.test.ts", + "**/*.spec.tsx", + "**/*.test.tsx", + "**/*.spec.js", + "**/*.test.js", + "**/*.spec.jsx", + "**/*.test.jsx" + ], + "include": ["**/*.js", "**/*.jsx", "**/*.ts", "**/*.tsx"] +} diff --git a/libs/wallet/tsconfig.spec.json b/libs/wallet/tsconfig.spec.json new file mode 100644 index 0000000000..26ef046ac5 --- /dev/null +++ b/libs/wallet/tsconfig.spec.json @@ -0,0 +1,20 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "../../dist/out-tsc", + "module": "commonjs", + "types": ["jest", "node"] + }, + "include": [ + "jest.config.ts", + "src/**/*.test.ts", + "src/**/*.spec.ts", + "src/**/*.test.tsx", + "src/**/*.spec.tsx", + "src/**/*.test.js", + "src/**/*.spec.js", + "src/**/*.test.jsx", + "src/**/*.spec.jsx", + "src/**/*.d.ts" + ] +} diff --git a/libs/wallet/vite.config.ts b/libs/wallet/vite.config.ts new file mode 100644 index 0000000000..070d48d360 --- /dev/null +++ b/libs/wallet/vite.config.ts @@ -0,0 +1,49 @@ +/// +import { defineConfig } from 'vite' +import react from '@vitejs/plugin-react-swc' +import viteTsConfigPaths from 'vite-tsconfig-paths' +import dts from 'vite-plugin-dts' +import * as path from 'path' + +export default defineConfig({ + cacheDir: '../../node_modules/.vite/wallet', + + plugins: [ + dts({ + entryRoot: 'src', + tsConfigFilePath: path.join(__dirname, 'tsconfig.lib.json'), + skipDiagnostics: true, + }), + react(), + viteTsConfigPaths({ + root: '../../', + }), + ], + + // Uncomment this if you are using workers. + // worker: { + // plugins: [ + // viteTsConfigPaths({ + // root: '../../', + // }), + // ], + // }, + + // Configuration for building your library. + // See: https://vitejs.dev/guide/build.html#library-mode + build: { + lib: { + // Could also be a dictionary or array of multiple entry points. + entry: 'src/index.ts', + name: 'wallet', + fileName: 'index', + // Change this to the formats you want to support. + // Don't forget to update your package.json as well. + formats: ['es', 'cjs'], + }, + rollupOptions: { + // External packages that should not be bundled into your library. + external: ['react', 'react-dom', 'react/jsx-runtime'], + }, + }, +}) diff --git a/libs/widget-lib/README.md b/libs/widget-lib/README.md index e917261a5b..eadb59aee9 100644 --- a/libs/widget-lib/README.md +++ b/libs/widget-lib/README.md @@ -21,7 +21,7 @@ Create an empty div somewhere in your website: Import the widget and initialise it: ```js -import { cowSwapWidget } from '@cowswap/widget-lib' +import { cowSwapWidget } from '@cowprotocol/widget-lib' // Initialise the widget const widgetContainer = document.getElementById('cowswap-widget') diff --git a/libs/widget-lib/docs/README.md b/libs/widget-lib/docs/README.md index 85b6cd1c38..57860a98de 100644 --- a/libs/widget-lib/docs/README.md +++ b/libs/widget-lib/docs/README.md @@ -21,7 +21,7 @@ npm install @cowprotocol/widget-lib ## Quick start ```typescript -import { cowSwapWidget, CowSwapWidgetParams, CowSwapWidgetSettings } from '@cowswap/widget-lib' +import { cowSwapWidget, CowSwapWidgetParams, CowSwapWidgetSettings } from '@cowprotocol/widget-lib' // Initialise the widget const widgetContainer = document.getElementById('cowswap-widget') @@ -70,7 +70,7 @@ interface JsonRpcRequest { An example of connecting a widget to Metamask: ```typescript -import { cowSwapWidget, CowSwapWidgetParams } from '@cowswap/widget-lib' +import { cowSwapWidget, CowSwapWidgetParams } from '@cowprotocol/widget-lib' const params: CowSwapWidgetParams = { container: document.getElementById('cowswap-widget'), @@ -137,7 +137,7 @@ export interface TradeAssets { You can change all possible widget options on the fly: ```typescript -import { cowSwapWidget, CowSwapWidgetParams, CowSwapWidgetSettings } from '@cowswap/widget-lib' +import { cowSwapWidget, CowSwapWidgetParams, CowSwapWidgetSettings } from '@cowprotocol/widget-lib' const params: CowSwapWidgetParams = { container: document.getElementById('cowswap-widget'), diff --git a/libs/widget-react/README.md b/libs/widget-react/README.md index 405b0776ae..637a2031d7 100644 --- a/libs/widget-react/README.md +++ b/libs/widget-react/README.md @@ -17,7 +17,7 @@ yarn add @cowprotocol/widget-react Import component and some convenient types ```ts -import { CowSwapWidgetSettings } from '@cowswap/widget-lib' +import { CowSwapWidgetSettings } from '@cowprotocol/widget-lib' import { CowSwapWidget, CowSwapWidgetParams } from '@cowprotocol/widget-react' ``` diff --git a/libs/widget-react/src/lib/CowSwapWidget.tsx b/libs/widget-react/src/lib/CowSwapWidget.tsx index c0212ea4c2..d95f8609f6 100644 --- a/libs/widget-react/src/lib/CowSwapWidget.tsx +++ b/libs/widget-react/src/lib/CowSwapWidget.tsx @@ -4,7 +4,7 @@ import { cowSwapWidget, CowSwapWidgetParams as CowSwapWidgetParamsAux, CowSwapWidgetSettings, -} from '@cowswap/widget-lib' +} from '@cowprotocol/widget-lib' export type CowSwapWidgetParams = Omit export interface CowSwapWidgetProps { diff --git a/libs/widget-react/vite.config.ts b/libs/widget-react/vite.config.ts index 82a40dd645..d6f035e1b7 100644 --- a/libs/widget-react/vite.config.ts +++ b/libs/widget-react/vite.config.ts @@ -1,6 +1,6 @@ /// import { joinPathFragments } from '@nx/devkit' -import react from '@vitejs/plugin-react' +import react from '@vitejs/plugin-react-swc' import { defineConfig } from 'vite' import dts from 'vite-plugin-dts' import viteTsConfigPaths from 'vite-tsconfig-paths' diff --git a/nx.json b/nx.json index 9cddd6252b..b02e49fd75 100644 --- a/nx.json +++ b/nx.json @@ -1,18 +1,20 @@ { "$schema": "./node_modules/nx/schemas/nx-schema.json", + "affected": { + "defaultBase": "develop" + }, "tasksRunnerOptions": { "default": { - "runner": "nx/tasks-runners/default", + "runner": "nx-cloud", "options": { "cacheableOperations": ["build", "lint", "test", "e2e"], - "accessToken": "YmVmZTg2ZTQtOGNjMi00ZjQzLTk1Y2EtZTA0MDNjY2ExNDZifHJlYWQtd3JpdGU=" + "accessToken": "M2U1ZmI5MTEtZmY3MS00YzRjLTkxYmQtZDhkM2QzZTBkNTVhfHJlYWQ=" } } }, "targetDefaults": { "build": { - "dependsOn": ["^build"], - "inputs": ["production", "^production"] + "inputs": ["default", "production", "^production"] }, "e2e": { "inputs": ["default", "^production"] diff --git a/package.json b/package.json index 329688bda3..d20562aeac 100644 --- a/package.json +++ b/package.json @@ -10,14 +10,14 @@ }, "scripts": { "start": "nx run cowswap-frontend:serve", - "preview": "nx run cowswap-frontend:preview", - "test": "nx run-many -t test -p $npm_package_config_enabledApps", - "e2e": "nx run-many -t e2e -p $npm_package_config_enabledApps", - "lint": "nx run-many -t lint -p $npm_package_config_enabledApps", - "build": "cross-env NODE_OPTIONS=--max-old-space-size=32768 nx run cowswap-frontend:build", + "preview": "cross-env NODE_OPTIONS=--max-old-space-size=32768 nx run cowswap-frontend:preview", "cosmos:export": "cross-env NODE_OPTIONS=--max-old-space-size=32768 nx run cowswap-frontend:cosmos:export", + "cosmos": "nx run cowswap-frontend:cosmos:run", + "test": "nx run-many -t test --output-style=stream", + "e2e": "nx run-many -t e2e", + "lint": "nx run-many -t lint", "prebuild": "nx run cowswap-frontend:i18n", - "postbuild": "rm -rf build && mkdir build && mv dist/apps/cowswap-frontend/* build", + "build": "cross-env NODE_OPTIONS=--max-old-space-size=32768 nx build cowswap-frontend", "prepare": "husky install", "postinstall": "yarn run patch-package", "analyze-build": "cross-env ANALYZE_BUNDLE=true ANALYZE_BUNDLE_TEMPLATE=sunburst yarn build" @@ -43,13 +43,14 @@ ] }, "dependencies": { + "@1inch/permit-signed-approvals-utils": "^1.4.8", "@amplitude/analytics-browser": "^1.1.4", "@babel/runtime": "^7.17.0", "@coinbase/wallet-sdk": "^3.3.0", - "@cowprotocol/app-data": "v0.2.7", + "@cowprotocol/app-data": "^1.1.0-RC.0", "@cowprotocol/contracts": "^1.3.1", "@cowprotocol/cow-runner-game": "^0.2.9", - "@cowprotocol/cow-sdk": "^2.3.0", + "@cowprotocol/cow-sdk": "^3.0.0-rc.0", "@cowprotocol/ethflowcontract": "cowprotocol/ethflowcontract.git#v1.0.0-artifacts", "@davatar/react": "1.8.1", "@ethersproject/bignumber": "^5.7.0", @@ -87,17 +88,16 @@ "@uniswap/sdk-core": "^3.0.1", "@uniswap/token-lists": "^1.0.0-beta.30", "@use-gesture/react": "^10.2.23", - "@web3-react/coinbase-wallet": "^8.2.0", - "@web3-react/core": "^8.2.0", - "@web3-react/eip1193": "^8.2.0", - "@web3-react/empty": "^8.2.0", - "@web3-react/gnosis-safe": "^8.2.0", - "@web3-react/metamask": "^8.2.1", - "@web3-react/network": "^8.2.0", - "@web3-react/types": "^8.2.0", - "@web3-react/url": "^8.2.0", - "@web3-react/walletconnect": "^8.2.0", - "@web3-react/walletconnect-v2": "^8.3.7", + "@walletconnect/ethereum-provider": "^2.10.2", + "@web3-react/coinbase-wallet": "^8.2.3", + "@web3-react/core": "^8.2.3", + "@web3-react/eip1193": "^8.2.3", + "@web3-react/empty": "^8.2.3", + "@web3-react/gnosis-safe": "^8.2.4", + "@web3-react/metamask": "^8.2.4", + "@web3-react/network": "^8.2.3", + "@web3-react/url": "^8.2.3", + "@web3-react/walletconnect-v2": "^8.5.1", "bnc-sdk": "^4.6.0", "buffer": "^6.0.3", "cids": "^1.0.0", @@ -213,6 +213,7 @@ "@vitejs/plugin-react-swc": "^3.3.2", "@vitest/coverage-c8": "~0.32.0", "@vitest/ui": "~0.32.0", + "@web3-react/types": "^8.2.3", "babel-jest": "^29.6.2", "babel-plugin-styled-components": "2.1.4", "babel-plugin-transform-import-meta": "^2.2.0", @@ -249,65 +250,10 @@ "vite": "~4.3.9", "vite-plugin-babel-macros": "^1.0.6", "vite-plugin-dts": "~2.3.0", - "vite-plugin-node-polyfills": "^0.11.1", + "vite-plugin-node-polyfills": "^0.12.0", "vite-plugin-pwa": "^0.16.4", "vite-plugin-svgr": "^3.2.0", "vite-tsconfig-paths": "~4.2.0", "vitest": "~0.32.0" - }, - "nx": { - "targets": { - "build": { - "outputs": [ - "{projectRoot}/build", - "{projectRoot}/src/locales" - ] - }, - "build:analyze": { - "outputs": [ - "{projectRoot}/build" - ] - }, - "ipfs:build": { - "outputs": [ - "{projectRoot}/build" - ] - }, - "optimize-bundle": { - "outputs": [ - "{projectRoot}/../node_modules/@ethereumjs/common/dist.browser/genesisStates/mainnet.json" - ] - }, - "i18n:extract": { - "outputs": [ - "{projectRoot}/src/locales" - ] - }, - "i18n": { - "outputs": [ - "{projectRoot}/src/locales" - ] - }, - "i18n:pseudo": { - "outputs": [ - "{projectRoot}/src/locales" - ] - }, - "cosmos:export": { - "outputs": [ - "{projectRoot}/public/cosmos" - ] - }, - "sitemap": { - "outputs": [ - "{projectRoot}/public/sitemap.xml" - ] - }, - "writeVersion": { - "outputs": [ - "{projectRoot}/public/version.json" - ] - } - } } } diff --git a/patches/@walletconnect+universal-provider+2.9.2.patch b/patches/@walletconnect+universal-provider+2.9.2.patch deleted file mode 100644 index 978361c8fa..0000000000 --- a/patches/@walletconnect+universal-provider+2.9.2.patch +++ /dev/null @@ -1,11 +0,0 @@ -diff --git a/node_modules/@walletconnect/universal-provider/dist/index.cjs.js b/node_modules/@walletconnect/universal-provider/dist/index.cjs.js -index a8c3659..f6e93ff 100644 ---- a/node_modules/@walletconnect/universal-provider/dist/index.cjs.js -+++ b/node_modules/@walletconnect/universal-provider/dist/index.cjs.js -@@ -24,5 +24,5 @@ __p += '`),H&&(m+=`' + - function print() { __p += __j.call(arguments, '') } - `:`; - `)+m+`return __p --}`;var b=va(function(){return $(o,C+"return "+m).apply(i,f)});if(b.source=m,xi(b))throw b;return b}function Hd(n){return U(n).toLowerCase()}function $d(n){return U(n).toUpperCase()}function Ud(n,t,e){if(n=U(n),n&&(e||t===i))return Es(n);if(!n||!(t=pn(t)))return n;var r=On(n),s=On(t),o=ys(r,s),f=Ss(r,s)+1;return at(r,o,f).join("")}function Wd(n,t,e){if(n=U(n),n&&(e||t===i))return n.slice(0,Os(n)+1);if(!n||!(t=pn(t)))return n;var r=On(n),s=Ss(r,On(t))+1;return at(r,0,s).join("")}function Fd(n,t,e){if(n=U(n),n&&(e||t===i))return n.replace(xr,"");if(!n||!(t=pn(t)))return n;var r=On(n),s=ys(r,On(t));return at(r,s).join("")}function Md(n,t){var e=Ta,r=La;if(K(t)){var s="separator"in t?t.separator:s;e="length"in t?O(t.length):e,r="omission"in t?pn(t.omission):r}n=U(n);var o=n.length;if(Tt(n)){var f=On(n);o=f.length}if(e>=o)return n;var c=e-Lt(r);if(c<1)return r;var l=f?at(f,0,c).join(""):n.slice(0,c);if(s===i)return l+r;if(f&&(c+=l.length-c),Ei(s)){if(n.slice(c).search(s)){var v,_=l;for(s.global||(s=qr(s.source,U(Yi.exec(s))+"g")),s.lastIndex=0;v=s.exec(_);)var m=v.index;l=l.slice(0,m===i?c:m)}}else if(n.indexOf(pn(s),c)!=c){var w=l.lastIndexOf(s);w>-1&&(l=l.slice(0,w))}return l+r}function qd(n){return n=U(n),n&&Qa.test(n)?n.replace(Ki,vf):n}var Bd=Ft(function(n,t,e){return n+(e?" ":"")+t.toUpperCase()}),Ri=_u("toUpperCase");function ga(n,t,e){return n=U(n),t=e?i:t,t===i?hf(n)?wf(n):tf(n):n.match(t)||[]}var va=T(function(n,t){try{return hn(n,i,t)}catch(e){return xi(e)?e:new S(e)}}),Gd=Zn(function(n,t){return wn(t,function(e){e=Fn(e),Jn(n,e,Ci(n[e],n))}),n});function Kd(n){var t=n==null?0:n.length,e=x();return n=t?G(n,function(r){if(typeof r[1]!="function")throw new Pn(F);return[e(r[0]),r[1]]}):[],T(function(r){for(var s=-1;++sjn)return[];var e=$n,r=nn(n,$n);t=x(t),n-=$n;for(var s=Wr(r,t);++e0||t<0)?new N(e):(n<0?e=e.takeRight(-n):n&&(e=e.drop(n)),t!==i&&(t=O(t),e=t<0?e.dropRight(-t):e.take(t-n)),e)},N.prototype.takeRightWhile=function(n){return this.reverse().takeWhile(n).reverse()},N.prototype.toArray=function(){return this.take($n)},Un(N.prototype,function(n,t){var e=/^(?:filter|find|map|reject)|While$/.test(t),r=/^(?:head|last)$/.test(t),s=a[r?"take"+(t=="last"?"Right":""):t],o=r||/^find/.test(t);s&&(a.prototype[t]=function(){var f=this.__wrapped__,c=r?[1]:arguments,l=f instanceof N,v=c[0],_=l||R(f),m=function(L){var H=s.apply(a,tt([L],c));return r&&w?H[0]:H};_&&e&&typeof v=="function"&&v.length!=1&&(l=_=!1);var w=this.__chain__,C=!!this.__actions__.length,E=o&&!w,b=l&&!C;if(!o&&_){f=b?f:new N(this);var y=n.apply(f,c);return y.__actions__.push({func:tr,args:[m],thisArg:i}),new An(y,w)}return E&&b?n.apply(this,c):(y=this.thru(m),E?r?y.value()[0]:y.value():y)})}),wn(["pop","push","shift","sort","splice","unshift"],function(n){var t=Se[n],e=/^(?:push|sort|unshift)$/.test(n)?"tap":"thru",r=/^(?:pop|shift)$/.test(n);a.prototype[n]=function(){var s=arguments;if(r&&!this.__chain__){var o=this.value();return t.apply(R(o)?o:[],s)}return this[e](function(f){return t.apply(R(f)?f:[],s)})}}),Un(N.prototype,function(n,t){var e=a[t];if(e){var r=e.name+"";W.call($t,r)||($t[r]=[]),$t[r].push({name:t,func:e})}}),$t[Ze(i,ct).name]=[{name:"wrapper",func:i}],N.prototype.clone=qf,N.prototype.reverse=Bf,N.prototype.value=Gf,a.prototype.at=ml,a.prototype.chain=wl,a.prototype.commit=Pl,a.prototype.next=Al,a.prototype.plant=Il,a.prototype.reverse=xl,a.prototype.toJSON=a.prototype.valueOf=a.prototype.value=El,a.prototype.first=a.prototype.head,ne&&(a.prototype[ne]=Cl),a},Dt=Pf();lt?((lt.exports=Dt)._=Dt,br._=Dt):k._=Dt}).call(de)})($i,$i.exports);var Hg=Object.defineProperty,$g=Object.defineProperties,Ug=Object.getOwnPropertyDescriptors,xa=Object.getOwnPropertySymbols,Wg=Object.prototype.hasOwnProperty,Fg=Object.prototype.propertyIsEnumerable,Ea=(A,u,i)=>u in A?Hg(A,u,{enumerable:!0,configurable:!0,writable:!0,value:i}):A[u]=i,fr=(A,u)=>{for(var i in u||(u={}))Wg.call(u,i)&&Ea(A,i,u[i]);if(xa)for(var i of xa(u))Fg.call(u,i)&&Ea(A,i,u[i]);return A},Mg=(A,u)=>$g(A,Ug(u));function yn(A,u,i){let p;const I=Ui(A);return u.rpcMap&&(p=u.rpcMap[I]),p||(p=`${Ng}?chainId=eip155:${I}&projectId=${i}`),p}function Ui(A){return A.includes("eip155")?Number(A.split(":")[1]):Number(A)}function ya(A){return A.map(u=>`${u.split(":")[0]}:${u.split(":")[1]}`)}function qg(A,u){const i=Object.keys(u.namespaces).filter(I=>I.includes(A));if(!i.length)return[];const p=[];return i.forEach(I=>{const D=u.namespaces[I].accounts;p.push(...D)}),p}function Bg(A={},u={}){const i=Sa(A),p=Sa(u);return $i.exports.merge(i,p)}function Sa(A){var u,i,p,I;const D={};if(!cn.isValidObject(A))return D;for(const[F,Mn]of Object.entries(A)){const Kt=cn.isCaipNamespace(F)?[F]:Mn.chains,lr=Mn.methods||[],Ct=Mn.events||[],Dn=Mn.rpcMap||{},qn=cn.parseNamespaceKey(F);D[qn]=Mg(fr(fr({},D[qn]),Mn),{chains:cn.mergeArrays(Kt,(u=D[qn])==null?void 0:u.chains),methods:cn.mergeArrays(lr,(i=D[qn])==null?void 0:i.methods),events:cn.mergeArrays(Ct,(p=D[qn])==null?void 0:p.events),rpcMap:fr(fr({},Dn),(I=D[qn])==null?void 0:I.rpcMap)})}return D}function Gg(A){return A.includes(":")?A.split(":")[2]:A}function Kg(A){const u={};for(const[i,p]of Object.entries(A)){const I=p.methods||[],D=p.events||[],F=p.accounts||[],Mn=cn.isCaipNamespace(i)?[i]:p.chains?p.chains:ya(p.accounts);u[i]={chains:Mn,methods:I,events:D,accounts:F}}return u}const Ra={},Z=A=>Ra[A],Wi=(A,u)=>{Ra[A]=u};class zg{constructor(u){this.name="polkadot",this.namespace=u.namespace,this.events=Z("events"),this.client=Z("client"),this.chainId=this.getDefaultChain(),this.httpProviders=this.createHttpProviders()}updateNamespace(u){this.namespace=Object.assign(this.namespace,u)}requestAccounts(){return this.getAccounts()}getDefaultChain(){if(this.chainId)return this.chainId;if(this.namespace.defaultChain)return this.namespace.defaultChain;const u=this.namespace.chains[0];if(!u)throw new Error("ChainId not found");return u.split(":")[1]}request(u){return this.namespace.methods.includes(u.request.method)?this.client.request(u):this.getHttpProvider().request(u.request)}setDefaultChain(u,i){if(this.chainId=u,!this.httpProviders[u]){const p=i||yn(`${this.name}:${u}`,this.namespace);if(!p)throw new Error(`No RPC url provided for chainId: ${u}`);this.setHttpProvider(u,p)}this.events.emit(ft.DEFAULT_CHAIN_CHANGED,`${this.name}:${this.chainId}`)}getAccounts(){const u=this.namespace.accounts;return u?u.filter(i=>i.split(":")[1]===this.chainId.toString()).map(i=>i.split(":")[2])||[]:[]}createHttpProviders(){const u={};return this.namespace.chains.forEach(i=>{var p;u[i]=this.createHttpProvider(i,(p=this.namespace.rpcMap)==null?void 0:p[i])}),u}getHttpProvider(){const u=`${this.name}:${this.chainId}`,i=this.httpProviders[u];if(typeof i>"u")throw new Error(`JSON-RPC provider for ${u} not found`);return i}setHttpProvider(u,i){const p=this.createHttpProvider(u,i);p&&(this.httpProviders[u]=p)}createHttpProvider(u,i){const p=i||yn(u,this.namespace);return typeof p>"u"?void 0:new At.JsonRpcProvider(new Gt.default(p,Z("disableProviderPing")))}}class Jg{constructor(u){this.name="eip155",this.namespace=u.namespace,this.events=Z("events"),this.client=Z("client"),this.httpProviders=this.createHttpProviders(),this.chainId=parseInt(this.getDefaultChain())}async request(u){switch(u.request.method){case"eth_requestAccounts":return this.getAccounts();case"eth_accounts":return this.getAccounts();case"wallet_switchEthereumChain":return await this.handleSwitchChain(u);case"eth_chainId":return parseInt(this.getDefaultChain())}return this.namespace.methods.includes(u.request.method)?await this.client.request(u):this.getHttpProvider().request(u.request)}updateNamespace(u){this.namespace=Object.assign(this.namespace,u)}setDefaultChain(u,i){const p=Ui(u);if(!this.httpProviders[p]){const I=i||yn(`${this.name}:${p}`,this.namespace,this.client.core.projectId);if(!I)throw new Error(`No RPC url provided for chainId: ${p}`);this.setHttpProvider(p,I)}this.chainId=p,this.events.emit(ft.DEFAULT_CHAIN_CHANGED,`${this.name}:${p}`)}requestAccounts(){return this.getAccounts()}getDefaultChain(){if(this.chainId)return this.chainId.toString();if(this.namespace.defaultChain)return this.namespace.defaultChain;const u=this.namespace.chains[0];if(!u)throw new Error("ChainId not found");return u.split(":")[1]}createHttpProvider(u,i){const p=i||yn(`${this.name}:${u}`,this.namespace,this.client.core.projectId);return typeof p>"u"?void 0:new At.JsonRpcProvider(new Aa.HttpConnection(p,Z("disableProviderPing")))}setHttpProvider(u,i){const p=this.createHttpProvider(u,i);p&&(this.httpProviders[u]=p)}createHttpProviders(){const u={};return this.namespace.chains.forEach(i=>{var p;const I=Ui(i);u[I]=this.createHttpProvider(I,(p=this.namespace.rpcMap)==null?void 0:p[i])}),u}getAccounts(){const u=this.namespace.accounts;return u?[...new Set(u.filter(i=>i.split(":")[1]===this.chainId.toString()).map(i=>i.split(":")[2]))]:[]}getHttpProvider(){const u=this.chainId,i=this.httpProviders[u];if(typeof i>"u")throw new Error(`JSON-RPC provider for ${u} not found`);return i}async handleSwitchChain(u){var i,p;let I=u.request.params?(i=u.request.params[0])==null?void 0:i.chainId:"0x0";I=I.startsWith("0x")?I:`0x${I}`;const D=parseInt(I,16);if(this.isChainApproved(D))this.setDefaultChain(`${D}`);else if(this.namespace.methods.includes("wallet_switchEthereumChain"))await this.client.request({topic:u.topic,request:{method:u.request.method,params:[{chainId:I}]},chainId:(p=this.namespace.chains)==null?void 0:p[0]}),this.setDefaultChain(`${D}`);else throw new Error(`Failed to switch to chain 'eip155:${D}'. The chain is not approved or the wallet does not support 'wallet_switchEthereumChain' method.`);return null}isChainApproved(u){return this.namespace.chains.includes(`${this.name}:${u}`)}}class Yg{constructor(u){this.name="solana",this.namespace=u.namespace,this.events=Z("events"),this.client=Z("client"),this.chainId=this.getDefaultChain(),this.httpProviders=this.createHttpProviders()}updateNamespace(u){this.namespace=Object.assign(this.namespace,u)}requestAccounts(){return this.getAccounts()}request(u){return this.namespace.methods.includes(u.request.method)?this.client.request(u):this.getHttpProvider().request(u.request)}setDefaultChain(u,i){if(!this.httpProviders[u]){const p=i||yn(`${this.name}:${u}`,this.namespace,this.client.core.projectId);if(!p)throw new Error(`No RPC url provided for chainId: ${u}`);this.setHttpProvider(u,p)}this.chainId=u,this.events.emit(ft.DEFAULT_CHAIN_CHANGED,`${this.name}:${this.chainId}`)}getDefaultChain(){if(this.chainId)return this.chainId;if(this.namespace.defaultChain)return this.namespace.defaultChain;const u=this.namespace.chains[0];if(!u)throw new Error("ChainId not found");return u.split(":")[1]}getAccounts(){const u=this.namespace.accounts;return u?[...new Set(u.filter(i=>i.split(":")[1]===this.chainId.toString()).map(i=>i.split(":")[2]))]:[]}createHttpProviders(){const u={};return this.namespace.chains.forEach(i=>{var p;u[i]=this.createHttpProvider(i,(p=this.namespace.rpcMap)==null?void 0:p[i])}),u}getHttpProvider(){const u=`${this.name}:${this.chainId}`,i=this.httpProviders[u];if(typeof i>"u")throw new Error(`JSON-RPC provider for ${u} not found`);return i}setHttpProvider(u,i){const p=this.createHttpProvider(u,i);p&&(this.httpProviders[u]=p)}createHttpProvider(u,i){const p=i||yn(u,this.namespace,this.client.core.projectId);return typeof p>"u"?void 0:new At.JsonRpcProvider(new Gt.default(p,Z("disableProviderPing")))}}class Zg{constructor(u){this.name="cosmos",this.namespace=u.namespace,this.events=Z("events"),this.client=Z("client"),this.chainId=this.getDefaultChain(),this.httpProviders=this.createHttpProviders()}updateNamespace(u){this.namespace=Object.assign(this.namespace,u)}requestAccounts(){return this.getAccounts()}getDefaultChain(){if(this.chainId)return this.chainId;if(this.namespace.defaultChain)return this.namespace.defaultChain;const u=this.namespace.chains[0];if(!u)throw new Error("ChainId not found");return u.split(":")[1]}request(u){return this.namespace.methods.includes(u.request.method)?this.client.request(u):this.getHttpProvider().request(u.request)}setDefaultChain(u,i){if(this.chainId=u,!this.httpProviders[u]){const p=i||yn(`${this.name}:${u}`,this.namespace,this.client.core.projectId);if(!p)throw new Error(`No RPC url provided for chainId: ${u}`);this.setHttpProvider(u,p)}this.events.emit(ft.DEFAULT_CHAIN_CHANGED,`${this.name}:${this.chainId}`)}getAccounts(){const u=this.namespace.accounts;return u?[...new Set(u.filter(i=>i.split(":")[1]===this.chainId.toString()).map(i=>i.split(":")[2]))]:[]}createHttpProviders(){const u={};return this.namespace.chains.forEach(i=>{var p;u[i]=this.createHttpProvider(i,(p=this.namespace.rpcMap)==null?void 0:p[i])}),u}getHttpProvider(){const u=`${this.name}:${this.chainId}`,i=this.httpProviders[u];if(typeof i>"u")throw new Error(`JSON-RPC provider for ${u} not found`);return i}setHttpProvider(u,i){const p=this.createHttpProvider(u,i);p&&(this.httpProviders[u]=p)}createHttpProvider(u,i){const p=i||yn(u,this.namespace,this.client.core.projectId);return typeof p>"u"?void 0:new At.JsonRpcProvider(new Gt.default(p,Z("disableProviderPing")))}}class Xg{constructor(u){this.name="cip34",this.namespace=u.namespace,this.events=Z("events"),this.client=Z("client"),this.chainId=this.getDefaultChain(),this.httpProviders=this.createHttpProviders()}updateNamespace(u){this.namespace=Object.assign(this.namespace,u)}requestAccounts(){return this.getAccounts()}getDefaultChain(){if(this.chainId)return this.chainId;if(this.namespace.defaultChain)return this.namespace.defaultChain;const u=this.namespace.chains[0];if(!u)throw new Error("ChainId not found");return u.split(":")[1]}request(u){return this.namespace.methods.includes(u.request.method)?this.client.request(u):this.getHttpProvider().request(u.request)}setDefaultChain(u,i){if(this.chainId=u,!this.httpProviders[u]){const p=i||this.getCardanoRPCUrl(u);if(!p)throw new Error(`No RPC url provided for chainId: ${u}`);this.setHttpProvider(u,p)}this.events.emit(ft.DEFAULT_CHAIN_CHANGED,`${this.name}:${this.chainId}`)}getAccounts(){const u=this.namespace.accounts;return u?[...new Set(u.filter(i=>i.split(":")[1]===this.chainId.toString()).map(i=>i.split(":")[2]))]:[]}createHttpProviders(){const u={};return this.namespace.chains.forEach(i=>{const p=this.getCardanoRPCUrl(i);u[i]=this.createHttpProvider(i,p)}),u}getHttpProvider(){const u=`${this.name}:${this.chainId}`,i=this.httpProviders[u];if(typeof i>"u")throw new Error(`JSON-RPC provider for ${u} not found`);return i}getCardanoRPCUrl(u){const i=this.namespace.rpcMap;if(i)return i[u]}setHttpProvider(u,i){const p=this.createHttpProvider(u,i);p&&(this.httpProviders[u]=p)}createHttpProvider(u,i){const p=i||this.getCardanoRPCUrl(u);return typeof p>"u"?void 0:new At.JsonRpcProvider(new Gt.default(p,Z("disableProviderPing")))}}class Qg{constructor(u){this.name="elrond",this.namespace=u.namespace,this.events=Z("events"),this.client=Z("client"),this.chainId=this.getDefaultChain(),this.httpProviders=this.createHttpProviders()}updateNamespace(u){this.namespace=Object.assign(this.namespace,u)}requestAccounts(){return this.getAccounts()}request(u){return this.namespace.methods.includes(u.request.method)?this.client.request(u):this.getHttpProvider().request(u.request)}setDefaultChain(u,i){if(!this.httpProviders[u]){const p=i||yn(`${this.name}:${u}`,this.namespace,this.client.core.projectId);if(!p)throw new Error(`No RPC url provided for chainId: ${u}`);this.setHttpProvider(u,p)}this.chainId=u,this.events.emit(ft.DEFAULT_CHAIN_CHANGED,`${this.name}:${this.chainId}`)}getDefaultChain(){if(this.chainId)return this.chainId;if(this.namespace.defaultChain)return this.namespace.defaultChain;const u=this.namespace.chains[0];if(!u)throw new Error("ChainId not found");return u.split(":")[1]}getAccounts(){const u=this.namespace.accounts;return u?[...new Set(u.filter(i=>i.split(":")[1]===this.chainId.toString()).map(i=>i.split(":")[2]))]:[]}createHttpProviders(){const u={};return this.namespace.chains.forEach(i=>{var p;u[i]=this.createHttpProvider(i,(p=this.namespace.rpcMap)==null?void 0:p[i])}),u}getHttpProvider(){const u=`${this.name}:${this.chainId}`,i=this.httpProviders[u];if(typeof i>"u")throw new Error(`JSON-RPC provider for ${u} not found`);return i}setHttpProvider(u,i){const p=this.createHttpProvider(u,i);p&&(this.httpProviders[u]=p)}createHttpProvider(u,i){const p=i||yn(u,this.namespace,this.client.core.projectId);return typeof p>"u"?void 0:new At.JsonRpcProvider(new Gt.default(p,Z("disableProviderPing")))}}class Vg{constructor(u){this.name="multiversx",this.namespace=u.namespace,this.events=Z("events"),this.client=Z("client"),this.chainId=this.getDefaultChain(),this.httpProviders=this.createHttpProviders()}updateNamespace(u){this.namespace=Object.assign(this.namespace,u)}requestAccounts(){return this.getAccounts()}request(u){return this.namespace.methods.includes(u.request.method)?this.client.request(u):this.getHttpProvider().request(u.request)}setDefaultChain(u,i){if(!this.httpProviders[u]){const p=i||yn(`${this.name}:${u}`,this.namespace,this.client.core.projectId);if(!p)throw new Error(`No RPC url provided for chainId: ${u}`);this.setHttpProvider(u,p)}this.chainId=u,this.events.emit(ft.DEFAULT_CHAIN_CHANGED,`${this.name}:${this.chainId}`)}getDefaultChain(){if(this.chainId)return this.chainId;if(this.namespace.defaultChain)return this.namespace.defaultChain;const u=this.namespace.chains[0];if(!u)throw new Error("ChainId not found");return u.split(":")[1]}getAccounts(){const u=this.namespace.accounts;return u?[...new Set(u.filter(i=>i.split(":")[1]===this.chainId.toString()).map(i=>i.split(":")[2]))]:[]}createHttpProviders(){const u={};return this.namespace.chains.forEach(i=>{var p;u[i]=this.createHttpProvider(i,(p=this.namespace.rpcMap)==null?void 0:p[i])}),u}getHttpProvider(){const u=`${this.name}:${this.chainId}`,i=this.httpProviders[u];if(typeof i>"u")throw new Error(`JSON-RPC provider for ${u} not found`);return i}setHttpProvider(u,i){const p=this.createHttpProvider(u,i);p&&(this.httpProviders[u]=p)}createHttpProvider(u,i){const p=i||yn(u,this.namespace,this.client.core.projectId);return typeof p>"u"?void 0:new At.JsonRpcProvider(new Gt.default(p,Z("disableProviderPing")))}}var kg=Object.defineProperty,jg=Object.defineProperties,nv=Object.getOwnPropertyDescriptors,Oa=Object.getOwnPropertySymbols,tv=Object.prototype.hasOwnProperty,ev=Object.prototype.propertyIsEnumerable,ba=(A,u,i)=>u in A?kg(A,u,{enumerable:!0,configurable:!0,writable:!0,value:i}):A[u]=i,cr=(A,u)=>{for(var i in u||(u={}))tv.call(u,i)&&ba(A,i,u[i]);if(Oa)for(var i of Oa(u))ev.call(u,i)&&ba(A,i,u[i]);return A},Fi=(A,u)=>jg(A,nv(u));class hr{constructor(u){this.events=new bg.default,this.rpcProviders={},this.shouldAbortPairingAttempt=!1,this.maxPairingAttempts=10,this.disableProviderPing=!1,this.providerOpts=u,this.logger=typeof u?.logger<"u"&&typeof u?.logger!="string"?u.logger:Pa.pino(Pa.getDefaultLoggerOptions({level:u?.logger||Ca})),this.disableProviderPing=u?.disableProviderPing||!1}static async init(u){const i=new hr(u);return await i.initialize(),i}async request(u,i){const[p,I]=this.validateChain(i);if(!this.session)throw new Error("Please call connect() before request()");return await this.getProvider(p).request({request:cr({},u),chainId:`${p}:${I}`,topic:this.session.topic})}sendAsync(u,i,p){this.request(u,p).then(I=>i(null,I)).catch(I=>i(I,void 0))}async enable(){if(!this.client)throw new Error("Sign Client not initialized");return this.session||await this.connect({namespaces:this.namespaces,optionalNamespaces:this.optionalNamespaces,sessionProperties:this.sessionProperties}),await this.requestAccounts()}async disconnect(){var u;if(!this.session)throw new Error("Please call connect() before enable()");await this.client.disconnect({topic:(u=this.session)==null?void 0:u.topic,reason:cn.getSdkError("USER_DISCONNECTED")}),await this.cleanup()}async connect(u){if(!this.client)throw new Error("Sign Client not initialized");if(this.setNamespaces(u),await this.cleanupPendingPairings(),!u.skipPairing)return await this.pair(u.pairingTopic)}on(u,i){this.events.on(u,i)}once(u,i){this.events.once(u,i)}removeListener(u,i){this.events.removeListener(u,i)}off(u,i){this.events.off(u,i)}get isWalletConnect(){return!0}async pair(u){this.shouldAbortPairingAttempt=!1;let i=0;do{if(this.shouldAbortPairingAttempt)throw new Error("Pairing aborted");if(i>=this.maxPairingAttempts)throw new Error("Max auto pairing attempts reached");const{uri:p,approval:I}=await this.client.connect({pairingTopic:u,requiredNamespaces:this.namespaces,optionalNamespaces:this.optionalNamespaces,sessionProperties:this.sessionProperties});p&&(this.uri=p,this.events.emit("display_uri",p)),await I().then(D=>{this.session=D,this.namespaces||(this.namespaces=Kg(D.namespaces),this.persist("namespaces",this.namespaces))}).catch(D=>{if(D.message!==wa.PROPOSAL_EXPIRY_MESSAGE)throw D;i++})}while(!this.session);return this.onConnect(),this.session}setDefaultChain(u,i){try{if(!this.session)return;const[p,I]=this.validateChain(u);this.getProvider(p).setDefaultChain(I,i)}catch(p){if(!/Please call connect/.test(p.message))throw p}}async cleanupPendingPairings(u={}){this.logger.info("Cleaning up inactive pairings...");const i=this.client.pairing.getAll();if(cn.isValidArray(i)){for(const p of i)u.deletePairings?this.client.core.expirer.set(p.topic,0):await this.client.core.relayer.subscriber.unsubscribe(p.topic);this.logger.info(`Inactive pairings cleared: ${i.length}`)}}abortPairingAttempt(){this.shouldAbortPairingAttempt=!0}async checkStorage(){if(this.namespaces=await this.getFromStore("namespaces"),this.optionalNamespaces=await this.getFromStore("optionalNamespaces")||{},this.client.session.length){const u=this.client.session.keys.length-1;this.session=this.client.session.get(this.client.session.keys[u]),this.createProviders()}}async initialize(){this.logger.trace("Initialized"),await this.createClient(),await this.checkStorage(),this.registerEventListeners()}async createClient(){this.client=this.providerOpts.client||await Og.default.init({logger:this.providerOpts.logger||Ca,relayUrl:this.providerOpts.relayUrl||Tg,projectId:this.providerOpts.projectId,metadata:this.providerOpts.metadata,storageOptions:this.providerOpts.storageOptions,storage:this.providerOpts.storage,name:this.providerOpts.name}),this.logger.trace("SignClient Initialized")}createProviders(){if(!this.client)throw new Error("Sign Client not initialized");if(!this.session)throw new Error("Session not initialized. Please call connect() before enable()");const u=[...new Set(Object.keys(this.session.namespaces).map(i=>cn.parseNamespaceKey(i)))];Wi("client",this.client),Wi("events",this.events),Wi("disableProviderPing",this.disableProviderPing),u.forEach(i=>{if(!this.session)return;const p=qg(i,this.session),I=ya(p),D=Bg(this.namespaces,this.optionalNamespaces),F=Fi(cr({},D[i]),{accounts:p,chains:I});switch(i){case"eip155":this.rpcProviders[i]=new Jg({namespace:F});break;case"solana":this.rpcProviders[i]=new Yg({namespace:F});break;case"cosmos":this.rpcProviders[i]=new Zg({namespace:F});break;case"polkadot":this.rpcProviders[i]=new zg({namespace:F});break;case"cip34":this.rpcProviders[i]=new Xg({namespace:F});break;case"elrond":this.rpcProviders[i]=new Qg({namespace:F});break;case"multiversx":this.rpcProviders[i]=new Vg({namespace:F});break}})}registerEventListeners(){if(typeof this.client>"u")throw new Error("Sign Client is not initialized");this.client.on("session_ping",u=>{this.events.emit("session_ping",u)}),this.client.on("session_event",u=>{const{params:i}=u,{event:p}=i;if(p.name==="accountsChanged"){const I=p.data;I&&cn.isValidArray(I)&&this.events.emit("accountsChanged",I.map(Gg))}else p.name==="chainChanged"?this.onChainChanged(i.chainId):this.events.emit(p.name,p.data);this.events.emit("session_event",u)}),this.client.on("session_update",({topic:u,params:i})=>{var p;const{namespaces:I}=i,D=(p=this.client)==null?void 0:p.session.get(u);this.session=Fi(cr({},D),{namespaces:I}),this.onSessionUpdate(),this.events.emit("session_update",{topic:u,params:i})}),this.client.on("session_delete",async u=>{await this.cleanup(),this.events.emit("session_delete",u),this.events.emit("disconnect",Fi(cr({},cn.getSdkError("USER_DISCONNECTED")),{data:u.topic}))}),this.on(ft.DEFAULT_CHAIN_CHANGED,u=>{this.onChainChanged(u,!0)})}getProvider(u){if(!this.rpcProviders[u])throw new Error(`Provider not found: ${u}`);return this.rpcProviders[u]}onSessionUpdate(){Object.keys(this.rpcProviders).forEach(u=>{var i;this.getProvider(u).updateNamespace((i=this.session)==null?void 0:i.namespaces[u])})}setNamespaces(u){const{namespaces:i,optionalNamespaces:p,sessionProperties:I}=u;i&&Object.keys(i).length&&(this.namespaces=i),p&&Object.keys(p).length&&(this.optionalNamespaces=p),this.sessionProperties=I,this.persist("namespaces",i),this.persist("optionalNamespaces",p)}validateChain(u){const[i,p]=u?.split(":")||["",""];if(!this.namespaces||!Object.keys(this.namespaces).length)return[i,p];if(i&&!Object.keys(this.namespaces||{}).map(F=>cn.parseNamespaceKey(F)).includes(i))throw new Error(`Namespace '${i}' is not configured. Please call connect() first with namespace config.`);if(i&&p)return[i,p];const I=cn.parseNamespaceKey(Object.keys(this.namespaces)[0]),D=this.rpcProviders[I].getDefaultChain();return[I,D]}async requestAccounts(){const[u]=this.validateChain();return await this.getProvider(u).requestAccounts()}onChainChanged(u,i=!1){var p;if(!this.namespaces)return;const[I,D]=this.validateChain(u);i||this.getProvider(I).setDefaultChain(D),((p=this.namespaces[I])!=null?p:this.namespaces[`${I}:${D}`]).defaultChain=D,this.persist("namespaces",this.namespaces),this.events.emit("chainChanged",D)}onConnect(){this.createProviders(),this.events.emit("connect",{session:this.session})}async cleanup(){this.session=void 0,this.namespaces=void 0,this.optionalNamespaces=void 0,this.sessionProperties=void 0,this.persist("namespaces",void 0),this.persist("optionalNamespaces",void 0),this.persist("sessionProperties",void 0),await this.cleanupPendingPairings({deletePairings:!0})}persist(u,i){this.client.core.storage.setItem(`${Ia}/${u}`,i)}async getFromStore(u){return await this.client.core.storage.getItem(`${Ia}/${u}`)}}const rv=hr;exports.UniversalProvider=rv,exports.default=hr; -+}`;var b=va(function(){return $(o,C+"return "+m).apply(i,f)});if(b.source=m,xi(b))throw b;return b}function Hd(n){return U(n).toLowerCase()}function $d(n){return U(n).toUpperCase()}function Ud(n,t,e){if(n=U(n),n&&(e||t===i))return Es(n);if(!n||!(t=pn(t)))return n;var r=On(n),s=On(t),o=ys(r,s),f=Ss(r,s)+1;return at(r,o,f).join("")}function Wd(n,t,e){if(n=U(n),n&&(e||t===i))return n.slice(0,Os(n)+1);if(!n||!(t=pn(t)))return n;var r=On(n),s=Ss(r,On(t))+1;return at(r,0,s).join("")}function Fd(n,t,e){if(n=U(n),n&&(e||t===i))return n.replace(xr,"");if(!n||!(t=pn(t)))return n;var r=On(n),s=ys(r,On(t));return at(r,s).join("")}function Md(n,t){var e=Ta,r=La;if(K(t)){var s="separator"in t?t.separator:s;e="length"in t?O(t.length):e,r="omission"in t?pn(t.omission):r}n=U(n);var o=n.length;if(Tt(n)){var f=On(n);o=f.length}if(e>=o)return n;var c=e-Lt(r);if(c<1)return r;var l=f?at(f,0,c).join(""):n.slice(0,c);if(s===i)return l+r;if(f&&(c+=l.length-c),Ei(s)){if(n.slice(c).search(s)){var v,_=l;for(s.global||(s=qr(s.source,U(Yi.exec(s))+"g")),s.lastIndex=0;v=s.exec(_);)var m=v.index;l=l.slice(0,m===i?c:m)}}else if(n.indexOf(pn(s),c)!=c){var w=l.lastIndexOf(s);w>-1&&(l=l.slice(0,w))}return l+r}function qd(n){return n=U(n),n&&Qa.test(n)?n.replace(Ki,vf):n}var Bd=Ft(function(n,t,e){return n+(e?" ":"")+t.toUpperCase()}),Ri=_u("toUpperCase");function ga(n,t,e){return n=U(n),t=e?i:t,t===i?hf(n)?wf(n):tf(n):n.match(t)||[]}var va=T(function(n,t){try{return hn(n,i,t)}catch(e){return xi(e)?e:new S(e)}}),Gd=Zn(function(n,t){return wn(t,function(e){e=Fn(e),Jn(n,e,Ci(n[e],n))}),n});function Kd(n){var t=n==null?0:n.length,e=x();return n=t?G(n,function(r){if(typeof r[1]!="function")throw new Pn(F);return[e(r[0]),r[1]]}):[],T(function(r){for(var s=-1;++sjn)return[];var e=$n,r=nn(n,$n);t=x(t),n-=$n;for(var s=Wr(r,t);++e0||t<0)?new N(e):(n<0?e=e.takeRight(-n):n&&(e=e.drop(n)),t!==i&&(t=O(t),e=t<0?e.dropRight(-t):e.take(t-n)),e)},N.prototype.takeRightWhile=function(n){return this.reverse().takeWhile(n).reverse()},N.prototype.toArray=function(){return this.take($n)},Un(N.prototype,function(n,t){var e=/^(?:filter|find|map|reject)|While$/.test(t),r=/^(?:head|last)$/.test(t),s=a[r?"take"+(t=="last"?"Right":""):t],o=r||/^find/.test(t);s&&(a.prototype[t]=function(){var f=this.__wrapped__,c=r?[1]:arguments,l=f instanceof N,v=c[0],_=l||R(f),m=function(L){var H=s.apply(a,tt([L],c));return r&&w?H[0]:H};_&&e&&typeof v=="function"&&v.length!=1&&(l=_=!1);var w=this.__chain__,C=!!this.__actions__.length,E=o&&!w,b=l&&!C;if(!o&&_){f=b?f:new N(this);var y=n.apply(f,c);return y.__actions__.push({func:tr,args:[m],thisArg:i}),new An(y,w)}return E&&b?n.apply(this,c):(y=this.thru(m),E?r?y.value()[0]:y.value():y)})}),wn(["pop","push","shift","sort","splice","unshift"],function(n){var t=Se[n],e=/^(?:push|sort|unshift)$/.test(n)?"tap":"thru",r=/^(?:pop|shift)$/.test(n);a.prototype[n]=function(){var s=arguments;if(r&&!this.__chain__){var o=this.value();return t.apply(R(o)?o:[],s)}return this[e](function(f){return t.apply(R(f)?f:[],s)})}}),Un(N.prototype,function(n,t){var e=a[t];if(e){var r=e.name+"";W.call($t,r)||($t[r]=[]),$t[r].push({name:t,func:e})}}),$t[Ze(i,ct).name]=[{name:"wrapper",func:i}],N.prototype.clone=qf,N.prototype.reverse=Bf,N.prototype.value=Gf,a.prototype.at=ml,a.prototype.chain=wl,a.prototype.commit=Pl,a.prototype.next=Al,a.prototype.plant=Il,a.prototype.reverse=xl,a.prototype.toJSON=a.prototype.valueOf=a.prototype.value=El,a.prototype.first=a.prototype.head,ne&&(a.prototype[ne]=Cl),a},Dt=Pf();lt?((lt.exports=Dt)._=Dt,br._=Dt):k._=Dt}).call(de)})($i,$i.exports);var Hg=Object.defineProperty,$g=Object.defineProperties,Ug=Object.getOwnPropertyDescriptors,xa=Object.getOwnPropertySymbols,Wg=Object.prototype.hasOwnProperty,Fg=Object.prototype.propertyIsEnumerable,Ea=(A,u,i)=>u in A?Hg(A,u,{enumerable:!0,configurable:!0,writable:!0,value:i}):A[u]=i,fr=(A,u)=>{for(var i in u||(u={}))Wg.call(u,i)&&Ea(A,i,u[i]);if(xa)for(var i of xa(u))Fg.call(u,i)&&Ea(A,i,u[i]);return A},Mg=(A,u)=>$g(A,Ug(u));function yn(A,u,i){let p;const I=Ui(A);return u.rpcMap&&(p=u.rpcMap[I]),p||(p=`${Ng}?chainId=eip155:${I}&projectId=${i}`),p}function Ui(A){return A.includes("eip155")?Number(A.split(":")[1]):Number(A)}function ya(A){return A.map(u=>`${u.split(":")[0]}:${u.split(":")[1]}`)}function qg(A,u){const i=Object.keys(u.namespaces).filter(I=>I.includes(A));if(!i.length)return[];const p=[];return i.forEach(I=>{const D=u.namespaces[I].accounts;p.push(...D)}),p}function Bg(A={},u={}){const i=Sa(A),p=Sa(u);return $i.exports.merge(i,p)}function Sa(A){var u,i,p,I;const D={};if(!cn.isValidObject(A))return D;for(const[F,Mn]of Object.entries(A)){const Kt=cn.isCaipNamespace(F)?[F]:Mn.chains,lr=Mn.methods||[],Ct=Mn.events||[],Dn=Mn.rpcMap||{},qn=cn.parseNamespaceKey(F);D[qn]=Mg(fr(fr({},D[qn]),Mn),{chains:cn.mergeArrays(Kt,(u=D[qn])==null?void 0:u.chains),methods:cn.mergeArrays(lr,(i=D[qn])==null?void 0:i.methods),events:cn.mergeArrays(Ct,(p=D[qn])==null?void 0:p.events),rpcMap:fr(fr({},Dn),(I=D[qn])==null?void 0:I.rpcMap)})}return D}function Gg(A){return A.includes(":")?A.split(":")[2]:A}function Kg(A){const u={};for(const[i,p]of Object.entries(A)){const I=p.methods||[],D=p.events||[],F=p.accounts||[],Mn=cn.isCaipNamespace(i)?[i]:p.chains?p.chains:ya(p.accounts);u[i]={chains:Mn,methods:I,events:D,accounts:F}}return u}const Ra={},Z=A=>Ra[A],Wi=(A,u)=>{Ra[A]=u};class zg{constructor(u){this.name="polkadot",this.namespace=u.namespace,this.events=Z("events"),this.client=Z("client"),this.chainId=this.getDefaultChain(),this.httpProviders=this.createHttpProviders()}updateNamespace(u){this.namespace=Object.assign(this.namespace,u)}requestAccounts(){return this.getAccounts()}getDefaultChain(){if(this.chainId)return this.chainId;if(this.namespace.defaultChain)return this.namespace.defaultChain;const u=this.namespace.chains[0];if(!u)throw new Error("ChainId not found");return u.split(":")[1]}request(u){return this.namespace.methods.includes(u.request.method)?this.client.request(u):this.getHttpProvider().request(u.request)}setDefaultChain(u,i){if(this.chainId=u,!this.httpProviders[u]){const p=i||yn(`${this.name}:${u}`,this.namespace);if(!p)throw new Error(`No RPC url provided for chainId: ${u}`);this.setHttpProvider(u,p)}this.events.emit(ft.DEFAULT_CHAIN_CHANGED,`${this.name}:${this.chainId}`)}getAccounts(){const u=this.namespace.accounts;return u?u.filter(i=>i.split(":")[1]===this.chainId.toString()).map(i=>i.split(":")[2])||[]:[]}createHttpProviders(){const u={};return this.namespace.chains.forEach(i=>{var p;u[i]=this.createHttpProvider(i,(p=this.namespace.rpcMap)==null?void 0:p[i])}),u}getHttpProvider(){const u=`${this.name}:${this.chainId}`,i=this.httpProviders[u];if(typeof i>"u")throw new Error(`JSON-RPC provider for ${u} not found`);return i}setHttpProvider(u,i){const p=this.createHttpProvider(u,i);p&&(this.httpProviders[u]=p)}createHttpProvider(u,i){const p=i||yn(u,this.namespace);return typeof p>"u"?void 0:new At.JsonRpcProvider(new Gt.default(p,Z("disableProviderPing")))}}class Jg{constructor(u){this.name="eip155",this.namespace=u.namespace,this.events=Z("events"),this.client=Z("client"),this.httpProviders=this.createHttpProviders(),this.chainId=parseInt(this.getDefaultChain())}async request(u){switch(u.request.method){case"eth_requestAccounts":return this.getAccounts();case"eth_accounts":return this.getAccounts();case"wallet_switchEthereumChain":return await this.handleSwitchChain(u);case"eth_chainId":return parseInt(this.getDefaultChain())}return this.namespace.methods.includes(u.request.method)?await this.client.request(u):this.getHttpProvider().request(u.request)}updateNamespace(u){this.namespace=Object.assign(this.namespace,u)}setDefaultChain(u,i){const p=Ui(u);if(!this.httpProviders[p]){const I=i||yn(`${this.name}:${p}`,this.namespace,this.client.core.projectId);if(!I)throw new Error(`No RPC url provided for chainId: ${p}`);this.setHttpProvider(p,I)}this.chainId=p,this.events.emit(ft.DEFAULT_CHAIN_CHANGED,`${this.name}:${p}`)}requestAccounts(){return this.getAccounts()}getDefaultChain(){if(this.chainId)return this.chainId.toString();if(this.namespace.defaultChain)return this.namespace.defaultChain;const u=this.namespace.chains[0];if(!u)throw new Error("ChainId not found");return u.split(":")[1]}createHttpProvider(u,i){const p=i||yn(`${this.name}:${u}`,this.namespace,this.client.core.projectId);return typeof p>"u"?void 0:new At.JsonRpcProvider(new Aa.HttpConnection(p,Z("disableProviderPing")))}setHttpProvider(u,i){const p=this.createHttpProvider(u,i);p&&(this.httpProviders[u]=p)}createHttpProviders(){const u={};return this.namespace.chains.forEach(i=>{var p;const I=Ui(i);u[I]=this.createHttpProvider(I,(p=this.namespace.rpcMap)==null?void 0:p[i])}),u}getAccounts(){const u=this.namespace.accounts;return u?[...new Set(u.filter(i=>i.split(":")[1]===this.chainId.toString()).map(i=>i.split(":")[2]))]:[]}getHttpProvider(){const u=this.chainId,i=this.httpProviders[u];if(typeof i>"u")throw new Error(`JSON-RPC provider for ${u} not found`);return i}async handleSwitchChain(u){var i,p;let I=u.request.params?(i=u.request.params[0])==null?void 0:i.chainId:"0x0";I=I.startsWith("0x")?I:`0x${I}`;const D=parseInt(I,16);if(this.isChainApproved(D))this.setDefaultChain(`${D}`);else if(this.namespace.methods.includes("wallet_switchEthereumChain"))await this.client.request({topic:u.topic,request:{method:u.request.method,params:[{chainId:I}]},chainId:(p=this.namespace.chains)==null?void 0:p[0]}),this.setDefaultChain(`${D}`);else throw new Error(`Failed to switch to chain 'eip155:${D}'. The chain is not approved or the wallet does not support 'wallet_switchEthereumChain' method.`);return null}isChainApproved(u){return this.namespace.chains.includes(`${this.name}:${u}`)}}class Yg{constructor(u){this.name="solana",this.namespace=u.namespace,this.events=Z("events"),this.client=Z("client"),this.chainId=this.getDefaultChain(),this.httpProviders=this.createHttpProviders()}updateNamespace(u){this.namespace=Object.assign(this.namespace,u)}requestAccounts(){return this.getAccounts()}request(u){return this.namespace.methods.includes(u.request.method)?this.client.request(u):this.getHttpProvider().request(u.request)}setDefaultChain(u,i){if(!this.httpProviders[u]){const p=i||yn(`${this.name}:${u}`,this.namespace,this.client.core.projectId);if(!p)throw new Error(`No RPC url provided for chainId: ${u}`);this.setHttpProvider(u,p)}this.chainId=u,this.events.emit(ft.DEFAULT_CHAIN_CHANGED,`${this.name}:${this.chainId}`)}getDefaultChain(){if(this.chainId)return this.chainId;if(this.namespace.defaultChain)return this.namespace.defaultChain;const u=this.namespace.chains[0];if(!u)throw new Error("ChainId not found");return u.split(":")[1]}getAccounts(){const u=this.namespace.accounts;return u?[...new Set(u.filter(i=>i.split(":")[1]===this.chainId.toString()).map(i=>i.split(":")[2]))]:[]}createHttpProviders(){const u={};return this.namespace.chains.forEach(i=>{var p;u[i]=this.createHttpProvider(i,(p=this.namespace.rpcMap)==null?void 0:p[i])}),u}getHttpProvider(){const u=`${this.name}:${this.chainId}`,i=this.httpProviders[u];if(typeof i>"u")throw new Error(`JSON-RPC provider for ${u} not found`);return i}setHttpProvider(u,i){const p=this.createHttpProvider(u,i);p&&(this.httpProviders[u]=p)}createHttpProvider(u,i){const p=i||yn(u,this.namespace,this.client.core.projectId);return typeof p>"u"?void 0:new At.JsonRpcProvider(new Gt.default(p,Z("disableProviderPing")))}}class Zg{constructor(u){this.name="cosmos",this.namespace=u.namespace,this.events=Z("events"),this.client=Z("client"),this.chainId=this.getDefaultChain(),this.httpProviders=this.createHttpProviders()}updateNamespace(u){this.namespace=Object.assign(this.namespace,u)}requestAccounts(){return this.getAccounts()}getDefaultChain(){if(this.chainId)return this.chainId;if(this.namespace.defaultChain)return this.namespace.defaultChain;const u=this.namespace.chains[0];if(!u)throw new Error("ChainId not found");return u.split(":")[1]}request(u){return this.namespace.methods.includes(u.request.method)?this.client.request(u):this.getHttpProvider().request(u.request)}setDefaultChain(u,i){if(this.chainId=u,!this.httpProviders[u]){const p=i||yn(`${this.name}:${u}`,this.namespace,this.client.core.projectId);if(!p)throw new Error(`No RPC url provided for chainId: ${u}`);this.setHttpProvider(u,p)}this.events.emit(ft.DEFAULT_CHAIN_CHANGED,`${this.name}:${this.chainId}`)}getAccounts(){const u=this.namespace.accounts;return u?[...new Set(u.filter(i=>i.split(":")[1]===this.chainId.toString()).map(i=>i.split(":")[2]))]:[]}createHttpProviders(){const u={};return this.namespace.chains.forEach(i=>{var p;u[i]=this.createHttpProvider(i,(p=this.namespace.rpcMap)==null?void 0:p[i])}),u}getHttpProvider(){const u=`${this.name}:${this.chainId}`,i=this.httpProviders[u];if(typeof i>"u")throw new Error(`JSON-RPC provider for ${u} not found`);return i}setHttpProvider(u,i){const p=this.createHttpProvider(u,i);p&&(this.httpProviders[u]=p)}createHttpProvider(u,i){const p=i||yn(u,this.namespace,this.client.core.projectId);return typeof p>"u"?void 0:new At.JsonRpcProvider(new Gt.default(p,Z("disableProviderPing")))}}class Xg{constructor(u){this.name="cip34",this.namespace=u.namespace,this.events=Z("events"),this.client=Z("client"),this.chainId=this.getDefaultChain(),this.httpProviders=this.createHttpProviders()}updateNamespace(u){this.namespace=Object.assign(this.namespace,u)}requestAccounts(){return this.getAccounts()}getDefaultChain(){if(this.chainId)return this.chainId;if(this.namespace.defaultChain)return this.namespace.defaultChain;const u=this.namespace.chains[0];if(!u)throw new Error("ChainId not found");return u.split(":")[1]}request(u){return this.namespace.methods.includes(u.request.method)?this.client.request(u):this.getHttpProvider().request(u.request)}setDefaultChain(u,i){if(this.chainId=u,!this.httpProviders[u]){const p=i||this.getCardanoRPCUrl(u);if(!p)throw new Error(`No RPC url provided for chainId: ${u}`);this.setHttpProvider(u,p)}this.events.emit(ft.DEFAULT_CHAIN_CHANGED,`${this.name}:${this.chainId}`)}getAccounts(){const u=this.namespace.accounts;return u?[...new Set(u.filter(i=>i.split(":")[1]===this.chainId.toString()).map(i=>i.split(":")[2]))]:[]}createHttpProviders(){const u={};return this.namespace.chains.forEach(i=>{const p=this.getCardanoRPCUrl(i);u[i]=this.createHttpProvider(i,p)}),u}getHttpProvider(){const u=`${this.name}:${this.chainId}`,i=this.httpProviders[u];if(typeof i>"u")throw new Error(`JSON-RPC provider for ${u} not found`);return i}getCardanoRPCUrl(u){const i=this.namespace.rpcMap;if(i)return i[u]}setHttpProvider(u,i){const p=this.createHttpProvider(u,i);p&&(this.httpProviders[u]=p)}createHttpProvider(u,i){const p=i||this.getCardanoRPCUrl(u);return typeof p>"u"?void 0:new At.JsonRpcProvider(new Gt.default(p,Z("disableProviderPing")))}}class Qg{constructor(u){this.name="elrond",this.namespace=u.namespace,this.events=Z("events"),this.client=Z("client"),this.chainId=this.getDefaultChain(),this.httpProviders=this.createHttpProviders()}updateNamespace(u){this.namespace=Object.assign(this.namespace,u)}requestAccounts(){return this.getAccounts()}request(u){return this.namespace.methods.includes(u.request.method)?this.client.request(u):this.getHttpProvider().request(u.request)}setDefaultChain(u,i){if(!this.httpProviders[u]){const p=i||yn(`${this.name}:${u}`,this.namespace,this.client.core.projectId);if(!p)throw new Error(`No RPC url provided for chainId: ${u}`);this.setHttpProvider(u,p)}this.chainId=u,this.events.emit(ft.DEFAULT_CHAIN_CHANGED,`${this.name}:${this.chainId}`)}getDefaultChain(){if(this.chainId)return this.chainId;if(this.namespace.defaultChain)return this.namespace.defaultChain;const u=this.namespace.chains[0];if(!u)throw new Error("ChainId not found");return u.split(":")[1]}getAccounts(){const u=this.namespace.accounts;return u?[...new Set(u.filter(i=>i.split(":")[1]===this.chainId.toString()).map(i=>i.split(":")[2]))]:[]}createHttpProviders(){const u={};return this.namespace.chains.forEach(i=>{var p;u[i]=this.createHttpProvider(i,(p=this.namespace.rpcMap)==null?void 0:p[i])}),u}getHttpProvider(){const u=`${this.name}:${this.chainId}`,i=this.httpProviders[u];if(typeof i>"u")throw new Error(`JSON-RPC provider for ${u} not found`);return i}setHttpProvider(u,i){const p=this.createHttpProvider(u,i);p&&(this.httpProviders[u]=p)}createHttpProvider(u,i){const p=i||yn(u,this.namespace,this.client.core.projectId);return typeof p>"u"?void 0:new At.JsonRpcProvider(new Gt.default(p,Z("disableProviderPing")))}}class Vg{constructor(u){this.name="multiversx",this.namespace=u.namespace,this.events=Z("events"),this.client=Z("client"),this.chainId=this.getDefaultChain(),this.httpProviders=this.createHttpProviders()}updateNamespace(u){this.namespace=Object.assign(this.namespace,u)}requestAccounts(){return this.getAccounts()}request(u){return this.namespace.methods.includes(u.request.method)?this.client.request(u):this.getHttpProvider().request(u.request)}setDefaultChain(u,i){if(!this.httpProviders[u]){const p=i||yn(`${this.name}:${u}`,this.namespace,this.client.core.projectId);if(!p)throw new Error(`No RPC url provided for chainId: ${u}`);this.setHttpProvider(u,p)}this.chainId=u,this.events.emit(ft.DEFAULT_CHAIN_CHANGED,`${this.name}:${this.chainId}`)}getDefaultChain(){if(this.chainId)return this.chainId;if(this.namespace.defaultChain)return this.namespace.defaultChain;const u=this.namespace.chains[0];if(!u)throw new Error("ChainId not found");return u.split(":")[1]}getAccounts(){const u=this.namespace.accounts;return u?[...new Set(u.filter(i=>i.split(":")[1]===this.chainId.toString()).map(i=>i.split(":")[2]))]:[]}createHttpProviders(){const u={};return this.namespace.chains.forEach(i=>{var p;u[i]=this.createHttpProvider(i,(p=this.namespace.rpcMap)==null?void 0:p[i])}),u}getHttpProvider(){const u=`${this.name}:${this.chainId}`,i=this.httpProviders[u];if(typeof i>"u")throw new Error(`JSON-RPC provider for ${u} not found`);return i}setHttpProvider(u,i){const p=this.createHttpProvider(u,i);p&&(this.httpProviders[u]=p)}createHttpProvider(u,i){const p=i||yn(u,this.namespace,this.client.core.projectId);return typeof p>"u"?void 0:new At.JsonRpcProvider(new Gt.default(p,Z("disableProviderPing")))}}var kg=Object.defineProperty,jg=Object.defineProperties,nv=Object.getOwnPropertyDescriptors,Oa=Object.getOwnPropertySymbols,tv=Object.prototype.hasOwnProperty,ev=Object.prototype.propertyIsEnumerable,ba=(A,u,i)=>u in A?kg(A,u,{enumerable:!0,configurable:!0,writable:!0,value:i}):A[u]=i,cr=(A,u)=>{for(var i in u||(u={}))tv.call(u,i)&&ba(A,i,u[i]);if(Oa)for(var i of Oa(u))ev.call(u,i)&&ba(A,i,u[i]);return A},Fi=(A,u)=>jg(A,nv(u));class hr{constructor(u){this.events=new bg.default,this.rpcProviders={},this.shouldAbortPairingAttempt=!1,this.maxPairingAttempts=10,this.disableProviderPing=!1,this.providerOpts=u,this.logger=typeof u?.logger<"u"&&typeof u?.logger!="string"?u.logger:Pa.pino(Pa.getDefaultLoggerOptions({level:u?.logger||Ca})),this.disableProviderPing=u?.disableProviderPing||!1}static async init(u){const i=new hr(u);return await i.initialize(),i}async request(u,i){const[p,I]=this.validateChain(i);if(!this.session)throw new Error("Please call connect() before request()");return await this.getProvider(p).request({request:cr({},u),chainId:`${p}:${I}`,topic:this.session.topic})}sendAsync(u,i,p){this.request(u,p).then(I=>i(null,I)).catch(I=>i(I,void 0))}async enable(){if(!this.client)throw new Error("Sign Client not initialized");return this.session||await this.connect({namespaces:this.namespaces,optionalNamespaces:this.optionalNamespaces,sessionProperties:this.sessionProperties}),await this.requestAccounts()}async disconnect(){var u;if(!this.session)throw new Error("Please call connect() before enable()");await this.client.disconnect({topic:(u=this.session)==null?void 0:u.topic,reason:cn.getSdkError("USER_DISCONNECTED")}),await this.cleanup()}async connect(u){if(!this.client)throw new Error("Sign Client not initialized");if(this.setNamespaces(u),await this.cleanupPendingPairings(),!u.skipPairing)return await this.pair(u.pairingTopic)}on(u,i){this.events.on(u,i)}once(u,i){this.events.once(u,i)}removeListener(u,i){this.events.removeListener(u,i)}off(u,i){this.events.off(u,i)}get isWalletConnect(){return!0}async pair(u){this.shouldAbortPairingAttempt=!1;let i=0;do{if(this.shouldAbortPairingAttempt)throw new Error("Pairing aborted");if(i>=this.maxPairingAttempts)throw new Error("Max auto pairing attempts reached");const{uri:p,approval:I}=await this.client.connect({pairingTopic:u,requiredNamespaces:this.namespaces,optionalNamespaces:this.optionalNamespaces,sessionProperties:this.sessionProperties});p&&(this.uri=p,this.events.emit("display_uri",p)),await I().then(D=>{this.session=D,this.namespaces||(this.namespaces=Kg(D.namespaces),this.persist("namespaces",this.namespaces))}).catch(D=>{if(D.message!==wa.PROPOSAL_EXPIRY_MESSAGE)throw D;i++})}while(!this.session);return this.onConnect(),this.session}setDefaultChain(u,i){try{if(!this.session)return;const[p,I]=this.validateChain(u);this.getProvider(p).setDefaultChain(I,i)}catch(p){if(!/Please call connect/.test(p.message))throw p}}async cleanupPendingPairings(u={}){this.logger.info("Cleaning up inactive pairings...");const i=this.client.pairing.getAll();if(cn.isValidArray(i)){for(const p of i)u.deletePairings?this.client.core.expirer.set(p.topic,0):await this.client.core.relayer.subscriber.unsubscribe(p.topic);this.logger.info(`Inactive pairings cleared: ${i.length}`)}}abortPairingAttempt(){this.shouldAbortPairingAttempt=!0}async checkStorage(){if(this.namespaces=await this.getFromStore("namespaces"),this.optionalNamespaces=await this.getFromStore("optionalNamespaces")||{},this.client.session.length){const u=this.client.session.keys.length-1;this.session=this.client.session.get(this.client.session.keys[u]),this.createProviders()}}async initialize(){this.logger.trace("Initialized"),await this.createClient(),await this.checkStorage(),this.registerEventListeners()}async createClient(){this.client=this.providerOpts.client||await (Og.default.init || Og.default.default.init)({logger:this.providerOpts.logger||Ca,relayUrl:this.providerOpts.relayUrl||Tg,projectId:this.providerOpts.projectId,metadata:this.providerOpts.metadata,storageOptions:this.providerOpts.storageOptions,storage:this.providerOpts.storage,name:this.providerOpts.name}),this.logger.trace("SignClient Initialized")}createProviders(){if(!this.client)throw new Error("Sign Client not initialized");if(!this.session)throw new Error("Session not initialized. Please call connect() before enable()");const u=[...new Set(Object.keys(this.session.namespaces).map(i=>cn.parseNamespaceKey(i)))];Wi("client",this.client),Wi("events",this.events),Wi("disableProviderPing",this.disableProviderPing),u.forEach(i=>{if(!this.session)return;const p=qg(i,this.session),I=ya(p),D=Bg(this.namespaces,this.optionalNamespaces),F=Fi(cr({},D[i]),{accounts:p,chains:I});switch(i){case"eip155":this.rpcProviders[i]=new Jg({namespace:F});break;case"solana":this.rpcProviders[i]=new Yg({namespace:F});break;case"cosmos":this.rpcProviders[i]=new Zg({namespace:F});break;case"polkadot":this.rpcProviders[i]=new zg({namespace:F});break;case"cip34":this.rpcProviders[i]=new Xg({namespace:F});break;case"elrond":this.rpcProviders[i]=new Qg({namespace:F});break;case"multiversx":this.rpcProviders[i]=new Vg({namespace:F});break}})}registerEventListeners(){if(typeof this.client>"u")throw new Error("Sign Client is not initialized");this.client.on("session_ping",u=>{this.events.emit("session_ping",u)}),this.client.on("session_event",u=>{const{params:i}=u,{event:p}=i;if(p.name==="accountsChanged"){const I=p.data;I&&cn.isValidArray(I)&&this.events.emit("accountsChanged",I.map(Gg))}else p.name==="chainChanged"?this.onChainChanged(i.chainId):this.events.emit(p.name,p.data);this.events.emit("session_event",u)}),this.client.on("session_update",({topic:u,params:i})=>{var p;const{namespaces:I}=i,D=(p=this.client)==null?void 0:p.session.get(u);this.session=Fi(cr({},D),{namespaces:I}),this.onSessionUpdate(),this.events.emit("session_update",{topic:u,params:i})}),this.client.on("session_delete",async u=>{await this.cleanup(),this.events.emit("session_delete",u),this.events.emit("disconnect",Fi(cr({},cn.getSdkError("USER_DISCONNECTED")),{data:u.topic}))}),this.on(ft.DEFAULT_CHAIN_CHANGED,u=>{this.onChainChanged(u,!0)})}getProvider(u){if(!this.rpcProviders[u])throw new Error(`Provider not found: ${u}`);return this.rpcProviders[u]}onSessionUpdate(){Object.keys(this.rpcProviders).forEach(u=>{var i;this.getProvider(u).updateNamespace((i=this.session)==null?void 0:i.namespaces[u])})}setNamespaces(u){const{namespaces:i,optionalNamespaces:p,sessionProperties:I}=u;i&&Object.keys(i).length&&(this.namespaces=i),p&&Object.keys(p).length&&(this.optionalNamespaces=p),this.sessionProperties=I,this.persist("namespaces",i),this.persist("optionalNamespaces",p)}validateChain(u){const[i,p]=u?.split(":")||["",""];if(!this.namespaces||!Object.keys(this.namespaces).length)return[i,p];if(i&&!Object.keys(this.namespaces||{}).map(F=>cn.parseNamespaceKey(F)).includes(i))throw new Error(`Namespace '${i}' is not configured. Please call connect() first with namespace config.`);if(i&&p)return[i,p];const I=cn.parseNamespaceKey(Object.keys(this.namespaces)[0]),D=this.rpcProviders[I].getDefaultChain();return[I,D]}async requestAccounts(){const[u]=this.validateChain();return await this.getProvider(u).requestAccounts()}onChainChanged(u,i=!1){var p;if(!this.namespaces)return;const[I,D]=this.validateChain(u);i||this.getProvider(I).setDefaultChain(D),((p=this.namespaces[I])!=null?p:this.namespaces[`${I}:${D}`]).defaultChain=D,this.persist("namespaces",this.namespaces),this.events.emit("chainChanged",D)}onConnect(){this.createProviders(),this.events.emit("connect",{session:this.session})}async cleanup(){this.session=void 0,this.namespaces=void 0,this.optionalNamespaces=void 0,this.sessionProperties=void 0,this.persist("namespaces",void 0),this.persist("optionalNamespaces",void 0),this.persist("sessionProperties",void 0),await this.cleanupPendingPairings({deletePairings:!0})}persist(u,i){this.client.core.storage.setItem(`${Ia}/${u}`,i)}async getFromStore(u){return await this.client.core.storage.getItem(`${Ia}/${u}`)}}const rv=hr;exports.UniversalProvider=rv,exports.default=hr; - //# sourceMappingURL=index.cjs.js.map diff --git a/patches/@web3-react+walletconnect-v2+8.3.7.patch b/patches/@web3-react+walletconnect-v2+8.3.7.patch deleted file mode 100644 index c841e8394e..0000000000 --- a/patches/@web3-react+walletconnect-v2+8.3.7.patch +++ /dev/null @@ -1,13 +0,0 @@ -diff --git a/node_modules/@web3-react/walletconnect-v2/dist/index.js b/node_modules/@web3-react/walletconnect-v2/dist/index.js -index b5bc5a9..cd92c3c 100644 ---- a/node_modules/@web3-react/walletconnect-v2/dist/index.js -+++ b/node_modules/@web3-react/walletconnect-v2/dist/index.js -@@ -83,7 +83,7 @@ class WalletConnect extends types_1.Connector { - return this.eagerConnection; - const rpcMap = this.rpcMap ? (0, utils_1.getBestUrlMap)(this.rpcMap, this.timeout) : undefined; - const chains = desiredChainId ? (0, utils_1.getChainsWithDefault)(this.chains, desiredChainId) : this.chains; -- return (this.eagerConnection = Promise.resolve().then(() => __importStar(require('@walletconnect/ethereum-provider'))).then((ethProviderModule) => __awaiter(this, void 0, void 0, function* () { -+ return (this.eagerConnection = Promise.resolve().then(() => __importStar(require('../node_modules/@walletconnect/ethereum-provider/dist/index.cjs'))).then((ethProviderModule) => __awaiter(this, void 0, void 0, function* () { - const provider = (this.provider = yield ethProviderModule.default.init(Object.assign(Object.assign({}, this.options), { chains, rpcMap: yield rpcMap }))); - return provider - .on('disconnect', this.disconnectListener) diff --git a/apps/cowswap-frontend/testing/imgMock.js b/testing/imgMock.js similarity index 100% rename from apps/cowswap-frontend/testing/imgMock.js rename to testing/imgMock.js diff --git a/apps/cowswap-frontend/testing/svgrMock.js b/testing/svgrMock.js similarity index 100% rename from apps/cowswap-frontend/testing/svgrMock.js rename to testing/svgrMock.js diff --git a/tools/getReactProcessEnv.ts b/tools/getReactProcessEnv.ts new file mode 100644 index 0000000000..4c9a3dc0f3 --- /dev/null +++ b/tools/getReactProcessEnv.ts @@ -0,0 +1,13 @@ +import { loadEnv } from 'vite' + +export function getReactProcessEnv(mode: string): { [key: string]: string } { + const env = loadEnv(mode, process.cwd(), ['REACT_APP_']) + + // expose .env as process.env instead of import.meta since jest does not import meta yet + return Object.entries(env).reduce((prev, [key, val]) => { + return { + ...prev, + ['process.env.' + key]: JSON.stringify(val), + } + }, {}) +} diff --git a/tsconfig.base.json b/tsconfig.base.json index 8b32512a7e..dfa00a1964 100644 --- a/tsconfig.base.json +++ b/tsconfig.base.json @@ -31,12 +31,20 @@ "allowSyntheticDefaultImports": true, "baseUrl": ".", "paths": { - "@cowswap/abis": ["libs/abis/src/index.ts"], - "@cowswap/ui": ["libs/ui/src/index.ts"], - "@cowswap/ui-utils": ["libs/ui-utils/src/index.ts"], - "@cowswap/widget-lib": ["libs/widget-lib/src/index.ts"], - "@cowswap/widget-react": ["libs/widget-react/src/index.ts"], - "@cowswap/snackbars": ["libs/snackbars/src/index.ts"] + "@cowprotocol/abis": ["libs/abis/src/index.ts"], + "@cowprotocol/analytics": ["libs/analytics/src/index.ts"], + "@cowprotocol/assets/*": ["libs/assets/src/*"], + "@cowprotocol/common-const": ["libs/common-const/src/index.ts"], + "@cowprotocol/common-hooks": ["libs/common-hooks/src/index.ts"], + "@cowprotocol/common-utils": ["libs/common-utils/src/index.ts"], + "@cowprotocol/core": ["libs/core/src/index.ts"], + "@cowprotocol/ens": ["libs/ens/src/index.ts"], + "@cowprotocol/snackbars": ["libs/snackbars/src/index.ts"], + "@cowprotocol/ui": ["libs/ui/src/index.ts"], + "@cowprotocol/ui-utils": ["libs/ui-utils/src/index.ts"], + "@cowprotocol/wallet": ["libs/wallet/src/index.ts"], + "@cowprotocol/widget-lib": ["libs/widget-lib/src/index.ts"], + "@cowprotocol/widget-react": ["libs/widget-react/src/index.ts"] } }, "exclude": ["node_modules", "tmp"] diff --git a/yarn.lock b/yarn.lock index 92ba99114d..ba044c2b34 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2,6 +2,15 @@ # yarn lockfile v1 +"@1inch/permit-signed-approvals-utils@^1.4.8": + version "1.4.8" + resolved "https://registry.yarnpkg.com/@1inch/permit-signed-approvals-utils/-/permit-signed-approvals-utils-1.4.8.tgz#d5d20e9e8a763f2649945aef8b843034a9a92c52" + integrity sha512-1U9U/tdvZpp9ZXaNmiiehu6S2EIYV3A4c1pj48oPcObRaWxX0QSDCrEHh95eJ0ND9y7QgvdlOy8DSAWUmxZOhA== + dependencies: + "@metamask/eth-sig-util" "^4.0.1" + web3 "^1.5.1" + web3-utils "^1.5.1" + "@aashutoshrathi/word-wrap@^1.2.3": version "1.2.6" resolved "https://registry.yarnpkg.com/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz#bd9154aec9983f77b3a034ecaa015c2e4201f6cf" @@ -1439,14 +1448,15 @@ dependencies: chalk "^4.1.0" -"@cowprotocol/app-data@v0.2.7": - version "0.2.7" - resolved "https://registry.yarnpkg.com/@cowprotocol/app-data/-/app-data-0.2.7.tgz#8cabd22f9491119111176ab544c323f793169818" - integrity sha512-kN+eiG4r49Q0yUp/TyhRZsAHCvt2RNR9EhI/1XubQYiTa5Il0CiSVLUjDbV1r2BYyZ6JBMMtHS/n8dCT2or/BQ== +"@cowprotocol/app-data@^1.1.0-RC.0": + version "1.1.0-RC.0" + resolved "https://registry.yarnpkg.com/@cowprotocol/app-data/-/app-data-1.1.0-RC.0.tgz#ac4e5d7a036c4033df431e07f7670e47be7662fd" + integrity sha512-tQrFTTXu2beVrPnHlB1YsRfYpmK9wvYpqJXsdHlXisuTm38EGPMSIAxV9NxYFbqlbslmYvBX7uSFPO70kMrN9g== dependencies: ajv "^8.11.0" cross-fetch "^3.1.5" ipfs-only-hash "^4.0.0" + json-stringify-deterministic "^1.0.8" multiformats "^9.6.4" "@cowprotocol/contracts@^1.3.1", "@cowprotocol/contracts@^1.4.0": @@ -1459,13 +1469,14 @@ resolved "https://registry.yarnpkg.com/@cowprotocol/cow-runner-game/-/cow-runner-game-0.2.9.tgz#3f94b3f370bd114f77db8b1d238cba3ef4e9d644" integrity sha512-rX7HnoV+HYEEkBaqVUsAkGGo0oBrExi+d6Io+8nQZYwZk+IYLmS9jdcIObsLviM2h4YX8+iin6NuKl35AaiHmg== -"@cowprotocol/cow-sdk@^2.3.0": - version "2.3.1" - resolved "https://registry.yarnpkg.com/@cowprotocol/cow-sdk/-/cow-sdk-2.3.1.tgz#ea7347869eada629b706cc24567ddcaa48bcc1ed" - integrity sha512-Rn3zCo3VCPqi3Wzqov0mDHXVVxBVhkLpnxnxcEZW7Kpv9WGcudl1vpz9e3Gs3YMzUQ5G6IA+kHxm5l81boIPhQ== +"@cowprotocol/cow-sdk@^3.0.0-rc.0": + version "3.0.0-rc.0" + resolved "https://registry.yarnpkg.com/@cowprotocol/cow-sdk/-/cow-sdk-3.0.0-rc.0.tgz#2583d3726a0f559b2a2faf86ed86261820b93311" + integrity sha512-hdAkLKdda7kPXHZxhDKvRo01MbFMHM+WV8okPJL0xgpVsjzQTCitKkitUf3e9kSdyUebdaGe3iWVZviCiI72ew== dependencies: "@cowprotocol/contracts" "^1.4.0" "@ethersproject/abstract-signer" "^5.7.0" + "@openzeppelin/merkle-tree" "^1.0.5" cross-fetch "^3.1.5" exponential-backoff "^3.1.1" graphql-request "^4.3.0" @@ -3060,31 +3071,6 @@ "@jridgewell/resolve-uri" "3.1.0" "@jridgewell/sourcemap-codec" "1.4.14" -"@json-rpc-tools/provider@^1.5.5": - version "1.7.6" - resolved "https://registry.yarnpkg.com/@json-rpc-tools/provider/-/provider-1.7.6.tgz#8a17c34c493fa892632e278fd9331104e8491ec6" - integrity sha512-z7D3xvJ33UfCGv77n40lbzOYjZKVM3k2+5cV7xS8G6SCvKTzMkhkUYuD/qzQUNT4cG/lv0e9mRToweEEVLVVmA== - dependencies: - "@json-rpc-tools/utils" "^1.7.6" - axios "^0.21.0" - safe-json-utils "^1.1.1" - ws "^7.4.0" - -"@json-rpc-tools/types@^1.7.6": - version "1.7.6" - resolved "https://registry.yarnpkg.com/@json-rpc-tools/types/-/types-1.7.6.tgz#5abd5fde01364a130c46093b501715bcce5bdc0e" - integrity sha512-nDSqmyRNEqEK9TZHtM15uNnDljczhCUdBmRhpNZ95bIPKEDQ+nTDmGMFd2lLin3upc5h2VVVd9tkTDdbXUhDIQ== - dependencies: - keyvaluestorage-interface "^1.0.0" - -"@json-rpc-tools/utils@^1.7.6": - version "1.7.6" - resolved "https://registry.yarnpkg.com/@json-rpc-tools/utils/-/utils-1.7.6.tgz#67f04987dbaa2e7adb6adff1575367b75a9a9ba1" - integrity sha512-HjA8x/U/Q78HRRe19yh8HVKoZ+Iaoo3YZjakJYxR+rw52NHo6jM+VE9b8+7ygkCFXl/EHID5wh/MkXaE/jGyYw== - dependencies: - "@json-rpc-tools/types" "^1.7.6" - "@pedrouid/environment" "^1.0.1" - "@juggle/resize-observer@^3.3.1": version "3.4.0" resolved "https://registry.yarnpkg.com/@juggle/resize-observer/-/resize-observer-3.4.0.tgz#08d6c5e20cf7e4cc02fd181c4b0c225cd31dbb60" @@ -3234,6 +3220,17 @@ resolved "https://registry.yarnpkg.com/@metamask/detect-provider/-/detect-provider-1.2.0.tgz#3667a7531f2a682e3c3a43eaf3a1958bdb42a696" integrity sha512-ocA76vt+8D0thgXZ7LxFPyqw3H7988qblgzddTDA6B8a/yU0uKV42QR/DhA+Jh11rJjxW0jKvwb5htA6krNZDQ== +"@metamask/eth-sig-util@^4.0.1": + version "4.0.1" + resolved "https://registry.yarnpkg.com/@metamask/eth-sig-util/-/eth-sig-util-4.0.1.tgz#3ad61f6ea9ad73ba5b19db780d40d9aae5157088" + integrity sha512-tghyZKLHZjcdlDqCA3gNZmLeR0XvOE9U1qoQO9ohyAZT6Pya+H9vkBPcsyXytmYLNgVoin7CKCmweo/R43V+tQ== + dependencies: + ethereumjs-abi "^0.6.8" + ethereumjs-util "^6.2.1" + ethjs-util "^0.1.6" + tweetnacl "^1.0.3" + tweetnacl-util "^0.15.1" + "@metamask/eth-sig-util@^5.0.2": version "5.1.0" resolved "https://registry.yarnpkg.com/@metamask/eth-sig-util/-/eth-sig-util-5.1.0.tgz#a47f62800ee1917fef976ba67544a0ccd7d1bd6b" @@ -3420,6 +3417,11 @@ dependencies: "@noble/hashes" "1.3.1" +"@noble/hashes@1.2.0", "@noble/hashes@~1.2.0": + version "1.2.0" + resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.2.0.tgz#a3150eeb09cc7ab207ebf6d7b9ad311a9bdbed12" + integrity sha512-FZfhjEDbT5GRswV3C6uvLPHMiVD6lQBmpoX5+eSiPaMTXte/IKqI5dykDxzZB/WBeK/CDuQRBWarPdi3FNY2zQ== + "@noble/hashes@1.3.0": version "1.3.0" resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.3.0.tgz#085fd70f6d7d9d109671090ccae1d3bec62554a1" @@ -3430,6 +3432,11 @@ resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.3.1.tgz#8831ef002114670c603c458ab8b11328406953a9" integrity sha512-EbqwksQwz9xDRGfDST86whPBgM65E0OH/pCgqW0GBVzO22bNE+NuIbeTb714+IfSjU3aRk47EUvXIb5bTsenKA== +"@noble/secp256k1@1.7.1", "@noble/secp256k1@~1.7.0": + version "1.7.1" + resolved "https://registry.yarnpkg.com/@noble/secp256k1/-/secp256k1-1.7.1.tgz#b251c70f824ce3ca7f8dc3df08d58f005cc0507c" + integrity sha512-hOUk6AyBFmqVrv7k5WAw/LpszxVbj9gGN4JRkIX52fdFAj1UA61KXmZDvqVEm+pOyec3+fIeZB02LYa/pWOArw== + "@nodelib/fs.scandir@2.1.5": version "2.1.5" resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5" @@ -3904,6 +3911,14 @@ yargs "^17.6.2" yargs-parser "21.1.1" +"@openzeppelin/merkle-tree@^1.0.5": + version "1.0.5" + resolved "https://registry.yarnpkg.com/@openzeppelin/merkle-tree/-/merkle-tree-1.0.5.tgz#4836d377777a7e39f31674f06ec3d6909def7913" + integrity sha512-JkwG2ysdHeIphrScNxYagPy6jZeNONgDRyqU6lbFgE8HKCZFSkcP8r6AjZs+3HZk4uRNV0kNBBzuWhKQ3YV7Kw== + dependencies: + "@ethersproject/abi" "^5.7.0" + ethereum-cryptography "^1.1.2" + "@parcel/watcher@2.0.4": version "2.0.4" resolved "https://registry.yarnpkg.com/@parcel/watcher/-/watcher-2.0.4.tgz#f300fef4cc38008ff4b8c29d92588eced3ce014b" @@ -3912,11 +3927,6 @@ node-addon-api "^3.2.1" node-gyp-build "^4.3.0" -"@pedrouid/environment@^1.0.1": - version "1.0.1" - resolved "https://registry.yarnpkg.com/@pedrouid/environment/-/environment-1.0.1.tgz#858f0f8a057340e0b250398b75ead77d6f4342ec" - integrity sha512-HaW78NszGzRZd9SeoI3JD11JqY+lubnaOx7Pewj5pfjqWXOEATpeKIFb9Z4t2WBUK2iryiXX3lzWwmYWgUL0Ug== - "@phenomnomnominal/tsquery@~5.0.1": version "5.0.1" resolved "https://registry.yarnpkg.com/@phenomnomnominal/tsquery/-/tsquery-5.0.1.tgz#a2a5abc89f92c01562a32806655817516653a388" @@ -4372,6 +4382,15 @@ resolved "https://registry.yarnpkg.com/@scure/base/-/base-1.1.1.tgz#ebb651ee52ff84f420097055f4bf46cfba403938" integrity sha512-ZxOhsSyxYwLJj3pLZCefNitxsj093tb2vq90mp2txoYeBqbcjDjqFhyM8eUjq/uFm6zJ+mUuqxlS2FkuSY1MTA== +"@scure/bip32@1.1.5": + version "1.1.5" + resolved "https://registry.yarnpkg.com/@scure/bip32/-/bip32-1.1.5.tgz#d2ccae16dcc2e75bc1d75f5ef3c66a338d1ba300" + integrity sha512-XyNh1rB0SkEqd3tXcXMi+Xe1fvg+kUIcoRIEujP1Jgv7DqW2r9lg3Ah0NkFaCs9sTkQAQA8kw7xiRXzENi9Rtw== + dependencies: + "@noble/hashes" "~1.2.0" + "@noble/secp256k1" "~1.7.0" + "@scure/base" "~1.1.0" + "@scure/bip32@1.3.0": version "1.3.0" resolved "https://registry.yarnpkg.com/@scure/bip32/-/bip32-1.3.0.tgz#6c8d980ef3f290987736acd0ee2e0f0d50068d87" @@ -4390,6 +4409,14 @@ "@noble/hashes" "~1.3.1" "@scure/base" "~1.1.0" +"@scure/bip39@1.1.1": + version "1.1.1" + resolved "https://registry.yarnpkg.com/@scure/bip39/-/bip39-1.1.1.tgz#b54557b2e86214319405db819c4b6a370cf340c5" + integrity sha512-t+wDck2rVkh65Hmv280fYdVdY25J9YeEUIgn2LG1WM6gxFkGzcksoDiUkWVpVp3Oex9xGC68JU2dSbUfwZ2jPg== + dependencies: + "@noble/hashes" "~1.2.0" + "@scure/base" "~1.1.0" + "@scure/bip39@1.2.0": version "1.2.0" resolved "https://registry.yarnpkg.com/@scure/bip39/-/bip39-1.2.0.tgz#a207e2ef96de354de7d0002292ba1503538fc77b" @@ -5567,6 +5594,13 @@ dependencies: "@babel/types" "^7.20.7" +"@types/bn.js@^4.11.3": + version "4.11.6" + resolved "https://registry.yarnpkg.com/@types/bn.js/-/bn.js-4.11.6.tgz#c306c70d9358aaea33cd4eda092a742b9505967c" + integrity sha512-pqr857jrp2kPuO9uRjZ3PwnJTjoQy+fcdxvBTvHm6dkmEL9q+hDD/2j/0ELOBPtPnS8LjCX0gI9nbl8lVkadpg== + dependencies: + "@types/node" "*" + "@types/bn.js@^5.1.0", "@types/bn.js@^5.1.1": version "5.1.1" resolved "https://registry.yarnpkg.com/@types/bn.js/-/bn.js-5.1.1.tgz#b51e1b55920a4ca26e9285ff79936bbdec910682" @@ -6796,31 +6830,10 @@ resolved "https://registry.yarnpkg.com/@wagmi/chains/-/chains-1.6.0.tgz#eb992ad28dbaaab729b5bcab3e5b461e8a035656" integrity sha512-5FRlVxse5P4ZaHG3GTvxwVANSmYJas1eQrTBHhjxVtqXoorm0aLmCHbhmN8Xo1yu09PaWKlleEvfE98yH4AgIw== -"@walletconnect/browser-utils@^1.8.0": - version "1.8.0" - resolved "https://registry.yarnpkg.com/@walletconnect/browser-utils/-/browser-utils-1.8.0.tgz#33c10e777aa6be86c713095b5206d63d32df0951" - integrity sha512-Wcqqx+wjxIo9fv6eBUFHPsW1y/bGWWRboni5dfD8PtOmrihrEpOCmvRJe4rfl7xgJW8Ea9UqKEaq0bIRLHlK4A== - dependencies: - "@walletconnect/safe-json" "1.0.0" - "@walletconnect/types" "^1.8.0" - "@walletconnect/window-getters" "1.0.0" - "@walletconnect/window-metadata" "1.0.0" - detect-browser "5.2.0" - -"@walletconnect/client@^1.8.0": - version "1.8.0" - resolved "https://registry.yarnpkg.com/@walletconnect/client/-/client-1.8.0.tgz#6f46b5499c7c861c651ff1ebe5da5b66225ca696" - integrity sha512-svyBQ14NHx6Cs2j4TpkQaBI/2AF4+LXz64FojTjMtV4VMMhl81jSO1vNeg+yYhQzvjcGH/GpSwixjyCW0xFBOQ== - dependencies: - "@walletconnect/core" "^1.8.0" - "@walletconnect/iso-crypto" "^1.8.0" - "@walletconnect/types" "^1.8.0" - "@walletconnect/utils" "^1.8.0" - -"@walletconnect/core@2.9.2": - version "2.9.2" - resolved "https://registry.yarnpkg.com/@walletconnect/core/-/core-2.9.2.tgz#c46734ca63771b28fd77606fd521930b7ecfc5e1" - integrity sha512-VARMPAx8sIgodeyngDHbealP3B621PQqjqKsByFUTOep8ZI1/R/20zU+cmq6j9RCrL+kLKZcrZqeVzs8Z7OlqQ== +"@walletconnect/core@2.10.2": + version "2.10.2" + resolved "https://registry.yarnpkg.com/@walletconnect/core/-/core-2.10.2.tgz#a1bf6e3e87b33f9df795ce0970d8ddd400fdc8a3" + integrity sha512-JQz/xp3SLEpTeRQctdck2ugSBVEpMxoSE+lFi2voJkZop1hv6P+uqr6E4PzjFluAjeAnKlT1xvra0aFWjPWVcw== dependencies: "@walletconnect/heartbeat" "1.2.1" "@walletconnect/jsonrpc-provider" "1.0.13" @@ -6833,42 +6846,12 @@ "@walletconnect/relay-auth" "^1.0.4" "@walletconnect/safe-json" "^1.0.2" "@walletconnect/time" "^1.0.2" - "@walletconnect/types" "2.9.2" - "@walletconnect/utils" "2.9.2" + "@walletconnect/types" "2.10.2" + "@walletconnect/utils" "2.10.2" events "^3.3.0" lodash.isequal "4.5.0" uint8arrays "^3.1.0" -"@walletconnect/core@^1.8.0": - version "1.8.0" - resolved "https://registry.yarnpkg.com/@walletconnect/core/-/core-1.8.0.tgz#6b2748b90c999d9d6a70e52e26a8d5e8bfeaa81e" - integrity sha512-aFTHvEEbXcZ8XdWBw6rpQDte41Rxwnuk3SgTD8/iKGSRTni50gI9S3YEzMj05jozSiOBxQci4pJDMVhIUMtarw== - dependencies: - "@walletconnect/socket-transport" "^1.8.0" - "@walletconnect/types" "^1.8.0" - "@walletconnect/utils" "^1.8.0" - -"@walletconnect/crypto@^1.0.2": - version "1.0.3" - resolved "https://registry.yarnpkg.com/@walletconnect/crypto/-/crypto-1.0.3.tgz#7b8dd4d7e2884fe3543c7c07aea425eef5ef9dd4" - integrity sha512-+2jdORD7XQs76I2Odgr3wwrtyuLUXD/kprNVsjWRhhhdO9Mt6WqVzOPu0/t7OHSmgal8k7SoBQzUc5hu/8zL/g== - dependencies: - "@walletconnect/encoding" "^1.0.2" - "@walletconnect/environment" "^1.0.1" - "@walletconnect/randombytes" "^1.0.3" - aes-js "^3.1.2" - hash.js "^1.1.7" - tslib "1.14.1" - -"@walletconnect/encoding@^1.0.1", "@walletconnect/encoding@^1.0.2": - version "1.0.2" - resolved "https://registry.yarnpkg.com/@walletconnect/encoding/-/encoding-1.0.2.tgz#cb3942ad038d6a6bf01158f66773062dd25724da" - integrity sha512-CrwSBrjqJ7rpGQcTL3kU+Ief+Bcuu9PH6JLOb+wM6NITX1GTxR/MfNwnQfhLKK6xpRAyj2/nM04OOH6wS8Imag== - dependencies: - is-typedarray "1.0.0" - tslib "1.14.1" - typedarray-to-buffer "3.1.5" - "@walletconnect/environment@^1.0.1": version "1.0.1" resolved "https://registry.yarnpkg.com/@walletconnect/environment/-/environment-1.0.1.tgz#1d7f82f0009ab821a2ba5ad5e5a7b8ae3b214cd7" @@ -6876,33 +6859,19 @@ dependencies: tslib "1.14.1" -"@walletconnect/ethereum-provider@^1.7.8": - version "1.8.0" - resolved "https://registry.yarnpkg.com/@walletconnect/ethereum-provider/-/ethereum-provider-1.8.0.tgz#ed1dbf9cecc3b818758a060d2f9017c50bde1d32" - integrity sha512-Nq9m+oo5P0F+njsROHw9KMWdoc/8iGHYzQdkjJN/1C7DtsqFRg5k5a3hd9rzCLpbPsOC1q8Z5lRs6JQgDvPm6Q== - dependencies: - "@walletconnect/client" "^1.8.0" - "@walletconnect/jsonrpc-http-connection" "^1.0.2" - "@walletconnect/jsonrpc-provider" "^1.0.5" - "@walletconnect/signer-connection" "^1.8.0" - "@walletconnect/types" "^1.8.0" - "@walletconnect/utils" "^1.8.0" - eip1193-provider "1.0.1" - eventemitter3 "4.0.7" - -"@walletconnect/ethereum-provider@^2.8.6": - version "2.9.2" - resolved "https://registry.yarnpkg.com/@walletconnect/ethereum-provider/-/ethereum-provider-2.9.2.tgz#fb3a6fca279bb4e98e75baa2fb9730545d41bb99" - integrity sha512-eO1dkhZffV1g7vpG19XUJTw09M/bwGUwwhy1mJ3AOPbOSbMPvwiCuRz2Kbtm1g9B0Jv15Dl+TvJ9vTgYF8zoZg== +"@walletconnect/ethereum-provider@^2.10.1", "@walletconnect/ethereum-provider@^2.10.2": + version "2.10.2" + resolved "https://registry.yarnpkg.com/@walletconnect/ethereum-provider/-/ethereum-provider-2.10.2.tgz#d5aca538fbcbbf7dd771bceb2430de30f06411de" + integrity sha512-QMYFZ6+rVq2CJLdIPdKK0j1Qm66UA27oQU5V2SrL8EVwl7wFfm0Bq7fnL+qAWeDpn612dNeNErpk/ROa1zWlWg== dependencies: "@walletconnect/jsonrpc-http-connection" "^1.0.7" "@walletconnect/jsonrpc-provider" "^1.0.13" "@walletconnect/jsonrpc-types" "^1.0.3" "@walletconnect/jsonrpc-utils" "^1.0.8" - "@walletconnect/sign-client" "2.9.2" - "@walletconnect/types" "2.9.2" - "@walletconnect/universal-provider" "2.9.2" - "@walletconnect/utils" "2.9.2" + "@walletconnect/sign-client" "2.10.2" + "@walletconnect/types" "2.10.2" + "@walletconnect/universal-provider" "2.10.2" + "@walletconnect/utils" "2.10.2" events "^3.3.0" "@walletconnect/events@^1.0.1": @@ -6922,16 +6891,7 @@ "@walletconnect/time" "^1.0.2" tslib "1.14.1" -"@walletconnect/iso-crypto@^1.8.0": - version "1.8.0" - resolved "https://registry.yarnpkg.com/@walletconnect/iso-crypto/-/iso-crypto-1.8.0.tgz#44ddf337c4f02837c062dbe33fa7ab36789df451" - integrity sha512-pWy19KCyitpfXb70hA73r9FcvklS+FvO9QUIttp3c2mfW8frxgYeRXfxLRCIQTkaYueRKvdqPjbyhPLam508XQ== - dependencies: - "@walletconnect/crypto" "^1.0.2" - "@walletconnect/types" "^1.8.0" - "@walletconnect/utils" "^1.8.0" - -"@walletconnect/jsonrpc-http-connection@^1.0.2", "@walletconnect/jsonrpc-http-connection@^1.0.7": +"@walletconnect/jsonrpc-http-connection@^1.0.7": version "1.0.7" resolved "https://registry.yarnpkg.com/@walletconnect/jsonrpc-http-connection/-/jsonrpc-http-connection-1.0.7.tgz#a6973569b8854c22da707a759d241e4f5c2d5a98" integrity sha512-qlfh8fCfu8LOM9JRR9KE0s0wxP6ZG9/Jom8M0qsoIQeKF3Ni0FyV4V1qy/cc7nfI46SLQLSl4tgWSfLiE1swyQ== @@ -6941,7 +6901,7 @@ cross-fetch "^3.1.4" tslib "1.14.1" -"@walletconnect/jsonrpc-provider@1.0.13", "@walletconnect/jsonrpc-provider@^1.0.13", "@walletconnect/jsonrpc-provider@^1.0.5": +"@walletconnect/jsonrpc-provider@1.0.13", "@walletconnect/jsonrpc-provider@^1.0.13": version "1.0.13" resolved "https://registry.yarnpkg.com/@walletconnect/jsonrpc-provider/-/jsonrpc-provider-1.0.13.tgz#9a74da648d015e1fffc745f0c7d629457f53648b" integrity sha512-K73EpThqHnSR26gOyNEL+acEex3P7VWZe6KE12ZwKzAt2H4e5gldZHbjsu2QR9cLeJ8AXuO7kEMOIcRv1QEc7g== @@ -6950,7 +6910,7 @@ "@walletconnect/safe-json" "^1.0.2" tslib "1.14.1" -"@walletconnect/jsonrpc-types@1.0.3", "@walletconnect/jsonrpc-types@^1.0.1", "@walletconnect/jsonrpc-types@^1.0.2", "@walletconnect/jsonrpc-types@^1.0.3": +"@walletconnect/jsonrpc-types@1.0.3", "@walletconnect/jsonrpc-types@^1.0.2", "@walletconnect/jsonrpc-types@^1.0.3": version "1.0.3" resolved "https://registry.yarnpkg.com/@walletconnect/jsonrpc-types/-/jsonrpc-types-1.0.3.tgz#65e3b77046f1a7fa8347ae02bc1b841abe6f290c" integrity sha512-iIQ8hboBl3o5ufmJ8cuduGad0CQm3ZlsHtujv9Eu16xq89q+BG7Nh5VLxxUgmtpnrePgFkTwXirCTkwJH1v+Yw== @@ -6958,7 +6918,7 @@ keyvaluestorage-interface "^1.0.0" tslib "1.14.1" -"@walletconnect/jsonrpc-utils@1.0.8", "@walletconnect/jsonrpc-utils@^1.0.3", "@walletconnect/jsonrpc-utils@^1.0.6", "@walletconnect/jsonrpc-utils@^1.0.7", "@walletconnect/jsonrpc-utils@^1.0.8": +"@walletconnect/jsonrpc-utils@1.0.8", "@walletconnect/jsonrpc-utils@^1.0.6", "@walletconnect/jsonrpc-utils@^1.0.7", "@walletconnect/jsonrpc-utils@^1.0.8": version "1.0.8" resolved "https://registry.yarnpkg.com/@walletconnect/jsonrpc-utils/-/jsonrpc-utils-1.0.8.tgz#82d0cc6a5d6ff0ecc277cb35f71402c91ad48d72" integrity sha512-vdeb03bD8VzJUL6ZtzRYsFMq1eZQcM3EAzT0a3st59dyLfJ0wq+tKMpmGH7HlB7waD858UWgfIcudbPFsbzVdw== @@ -6994,57 +6954,30 @@ pino "7.11.0" tslib "1.14.1" -"@walletconnect/mobile-registry@^1.4.0": - version "1.4.0" - resolved "https://registry.yarnpkg.com/@walletconnect/mobile-registry/-/mobile-registry-1.4.0.tgz#502cf8ab87330841d794819081e748ebdef7aee5" - integrity sha512-ZtKRio4uCZ1JUF7LIdecmZt7FOLnX72RPSY7aUVu7mj7CSfxDwUn6gBuK6WGtH+NZCldBqDl5DenI5fFSvkKYw== - -"@walletconnect/modal-core@2.6.1": - version "2.6.1" - resolved "https://registry.yarnpkg.com/@walletconnect/modal-core/-/modal-core-2.6.1.tgz#bc76055d0b644a2d4b98024324825c108a700905" - integrity sha512-f2hYlJ5pwzGvjyaZ6BoGR5uiMgXzWXt6w6ktt1N8lmY6PiYp8whZgqx2hTxVWwVlsGnaIfh6UHp1hGnANx0eTQ== +"@walletconnect/modal-core@2.6.2": + version "2.6.2" + resolved "https://registry.yarnpkg.com/@walletconnect/modal-core/-/modal-core-2.6.2.tgz#d73e45d96668764e0c8668ea07a45bb8b81119e9" + integrity sha512-cv8ibvdOJQv2B+nyxP9IIFdxvQznMz8OOr/oR/AaUZym4hjXNL/l1a2UlSQBXrVjo3xxbouMxLb3kBsHoYP2CA== dependencies: - valtio "1.11.0" + valtio "1.11.2" -"@walletconnect/modal-ui@2.6.1": - version "2.6.1" - resolved "https://registry.yarnpkg.com/@walletconnect/modal-ui/-/modal-ui-2.6.1.tgz#200c54c8dfe3c71321abb2724e18bb357dfd6371" - integrity sha512-RFUOwDAMijSK8B7W3+KoLKaa1l+KEUG0LCrtHqaB0H0cLnhEGdLR+kdTdygw+W8+yYZbkM5tXBm7MlFbcuyitA== +"@walletconnect/modal-ui@2.6.2": + version "2.6.2" + resolved "https://registry.yarnpkg.com/@walletconnect/modal-ui/-/modal-ui-2.6.2.tgz#fa57c087c57b7f76aaae93deab0f84bb68b59cf9" + integrity sha512-rbdstM1HPGvr7jprQkyPggX7rP4XiCG85ZA+zWBEX0dVQg8PpAgRUqpeub4xQKDgY7pY/xLRXSiCVdWGqvG2HA== dependencies: - "@walletconnect/modal-core" "2.6.1" - lit "2.7.6" + "@walletconnect/modal-core" "2.6.2" + lit "2.8.0" motion "10.16.2" qrcode "1.5.3" -"@walletconnect/modal@^2.5.9": - version "2.6.1" - resolved "https://registry.yarnpkg.com/@walletconnect/modal/-/modal-2.6.1.tgz#066fdbfcff83b58c8a9da66ab4af0eb93e3626de" - integrity sha512-G84tSzdPKAFk1zimgV7JzIUFT5olZUVtI3GcOk77OeLYjlMfnDT23RVRHm5EyCrjkptnvpD0wQScXePOFd2Xcw== - dependencies: - "@walletconnect/modal-core" "2.6.1" - "@walletconnect/modal-ui" "2.6.1" - -"@walletconnect/qrcode-modal@^1.8.0": - version "1.8.0" - resolved "https://registry.yarnpkg.com/@walletconnect/qrcode-modal/-/qrcode-modal-1.8.0.tgz#ddd6f5c9b7ee52c16adf9aacec2a3eac4994caea" - integrity sha512-BueaFefaAi8mawE45eUtztg3ZFbsAH4DDXh1UNwdUlsvFMjqcYzLUG0xZvDd6z2eOpbgDg2N3bl6gF0KONj1dg== - dependencies: - "@walletconnect/browser-utils" "^1.8.0" - "@walletconnect/mobile-registry" "^1.4.0" - "@walletconnect/types" "^1.8.0" - copy-to-clipboard "^3.3.1" - preact "10.4.1" - qrcode "1.4.4" - -"@walletconnect/randombytes@^1.0.3": - version "1.0.3" - resolved "https://registry.yarnpkg.com/@walletconnect/randombytes/-/randombytes-1.0.3.tgz#e795e4918367fd1e6a2215e075e64ab93e23985b" - integrity sha512-35lpzxcHFbTN3ABefC9W+uBpNZl1GC4Wpx0ed30gibfO/y9oLdy1NznbV96HARQKSBV9J9M/rrtIvf6a23jfYw== +"@walletconnect/modal@^2.6.2": + version "2.6.2" + resolved "https://registry.yarnpkg.com/@walletconnect/modal/-/modal-2.6.2.tgz#4b534a836f5039eeb3268b80be7217a94dd12651" + integrity sha512-eFopgKi8AjKf/0U4SemvcYw9zlLpx9njVN8sf6DAkowC2Md0gPU/UNEbH1Wwj407pEKnEds98pKWib1NN1ACoA== dependencies: - "@walletconnect/encoding" "^1.0.2" - "@walletconnect/environment" "^1.0.1" - randombytes "^2.1.0" - tslib "1.14.1" + "@walletconnect/modal-core" "2.6.2" + "@walletconnect/modal-ui" "2.6.2" "@walletconnect/relay-api@^1.0.9": version "1.0.9" @@ -7066,11 +6999,6 @@ tslib "1.14.1" uint8arrays "^3.0.0" -"@walletconnect/safe-json@1.0.0": - version "1.0.0" - resolved "https://registry.yarnpkg.com/@walletconnect/safe-json/-/safe-json-1.0.0.tgz#12eeb11d43795199c045fafde97e3c91646683b2" - integrity sha512-QJzp/S/86sUAgWY6eh5MKYmSfZaRpIlmCJdi5uG4DJlKkZrHEF7ye7gA+VtbVzvTtpM/gRwO2plQuiooIeXjfg== - "@walletconnect/safe-json@^1.0.1", "@walletconnect/safe-json@^1.0.2": version "1.0.2" resolved "https://registry.yarnpkg.com/@walletconnect/safe-json/-/safe-json-1.0.2.tgz#7237e5ca48046e4476154e503c6d3c914126fa77" @@ -7078,42 +7006,21 @@ dependencies: tslib "1.14.1" -"@walletconnect/sign-client@2.9.2": - version "2.9.2" - resolved "https://registry.yarnpkg.com/@walletconnect/sign-client/-/sign-client-2.9.2.tgz#ff4c81c082c2078878367d07f24bcb20b1f7ab9e" - integrity sha512-anRwnXKlR08lYllFMEarS01hp1gr6Q9XUgvacr749hoaC/AwGVlxYFdM8+MyYr3ozlA+2i599kjbK/mAebqdXg== +"@walletconnect/sign-client@2.10.2": + version "2.10.2" + resolved "https://registry.yarnpkg.com/@walletconnect/sign-client/-/sign-client-2.10.2.tgz#33300a9cfe42487473f66b73c99535f6b26f8c54" + integrity sha512-vviSLV3f92I0bReX+OLr1HmbH0uIzYEQQFd1MzIfDk9PkfFT/LLAHhUnDaIAMkIdippqDcJia+5QEtT4JihL3Q== dependencies: - "@walletconnect/core" "2.9.2" + "@walletconnect/core" "2.10.2" "@walletconnect/events" "^1.0.1" "@walletconnect/heartbeat" "1.2.1" "@walletconnect/jsonrpc-utils" "1.0.8" "@walletconnect/logger" "^2.0.1" "@walletconnect/time" "^1.0.2" - "@walletconnect/types" "2.9.2" - "@walletconnect/utils" "2.9.2" + "@walletconnect/types" "2.10.2" + "@walletconnect/utils" "2.10.2" events "^3.3.0" -"@walletconnect/signer-connection@^1.8.0": - version "1.8.0" - resolved "https://registry.yarnpkg.com/@walletconnect/signer-connection/-/signer-connection-1.8.0.tgz#6cdf490df770e504cc1a550bdb5bac7696b130bc" - integrity sha512-+YAaTAP52MWZJ2wWnqKClKCPlPHBo6reURFe0cWidLADh9mi/kPWGALZ5AENK22zpem1bbKV466rF5Rzvu0ehA== - dependencies: - "@walletconnect/client" "^1.8.0" - "@walletconnect/jsonrpc-types" "^1.0.1" - "@walletconnect/jsonrpc-utils" "^1.0.3" - "@walletconnect/qrcode-modal" "^1.8.0" - "@walletconnect/types" "^1.8.0" - eventemitter3 "4.0.7" - -"@walletconnect/socket-transport@^1.8.0": - version "1.8.0" - resolved "https://registry.yarnpkg.com/@walletconnect/socket-transport/-/socket-transport-1.8.0.tgz#9a1128a249628a0be11a0979b522fe82b44afa1b" - integrity sha512-5DyIyWrzHXTcVp0Vd93zJ5XMW61iDM6bcWT4p8DTRfFsOtW46JquruMhxOLeCOieM4D73kcr3U7WtyR4JUsGuQ== - dependencies: - "@walletconnect/types" "^1.8.0" - "@walletconnect/utils" "^1.8.0" - ws "7.5.3" - "@walletconnect/time@^1.0.2": version "1.0.2" resolved "https://registry.yarnpkg.com/@walletconnect/time/-/time-1.0.2.tgz#6c5888b835750ecb4299d28eecc5e72c6d336523" @@ -7121,10 +7028,10 @@ dependencies: tslib "1.14.1" -"@walletconnect/types@2.9.2": - version "2.9.2" - resolved "https://registry.yarnpkg.com/@walletconnect/types/-/types-2.9.2.tgz#d5fd5a61dc0f41cbdca59d1885b85207ac7bf8c5" - integrity sha512-7Rdn30amnJEEal4hk83cdwHUuxI1SWQ+K7fFFHBMqkuHLGi3tpMY6kpyfDxnUScYEZXqgRps4Jo5qQgnRqVM7A== +"@walletconnect/types@2.10.2": + version "2.10.2" + resolved "https://registry.yarnpkg.com/@walletconnect/types/-/types-2.10.2.tgz#68e433a29ec2cf42d79d8b50c77bd5c1d91db721" + integrity sha512-luNV+07Wdla4STi9AejseCQY31tzWKQ5a7C3zZZaRK/di+rFaAAb7YW04OP4klE7tw/mJRGPTlekZElmHxO8kQ== dependencies: "@walletconnect/events" "^1.0.1" "@walletconnect/heartbeat" "1.2.1" @@ -7133,30 +7040,25 @@ "@walletconnect/logger" "^2.0.1" events "^3.3.0" -"@walletconnect/types@^1.8.0": - version "1.8.0" - resolved "https://registry.yarnpkg.com/@walletconnect/types/-/types-1.8.0.tgz#3f5e85b2d6b149337f727ab8a71b8471d8d9a195" - integrity sha512-Cn+3I0V0vT9ghMuzh1KzZvCkiAxTq+1TR2eSqw5E5AVWfmCtECFkVZBP6uUJZ8YjwLqXheI+rnjqPy7sVM4Fyg== - -"@walletconnect/universal-provider@2.9.2": - version "2.9.2" - resolved "https://registry.yarnpkg.com/@walletconnect/universal-provider/-/universal-provider-2.9.2.tgz#40e54e98bc48b1f2f5f77eb5b7f05462093a8506" - integrity sha512-JmaolkO8D31UdRaQCHwlr8uIFUI5BYhBzqYFt54Mc6gbIa1tijGOmdyr6YhhFO70LPmS6gHIjljwOuEllmlrxw== +"@walletconnect/universal-provider@2.10.2": + version "2.10.2" + resolved "https://registry.yarnpkg.com/@walletconnect/universal-provider/-/universal-provider-2.10.2.tgz#85c8da39f65da8fe33f65f62689e703607b5ddc5" + integrity sha512-wFgI0LbQ3D56sgaUMsgOHCM5m8WLxiC71BGuCKQfApgsbNMVKugYVy2zWHyUyi8sqTQHI+uSaVpDev4UHq9LEw== dependencies: "@walletconnect/jsonrpc-http-connection" "^1.0.7" "@walletconnect/jsonrpc-provider" "1.0.13" "@walletconnect/jsonrpc-types" "^1.0.2" "@walletconnect/jsonrpc-utils" "^1.0.7" "@walletconnect/logger" "^2.0.1" - "@walletconnect/sign-client" "2.9.2" - "@walletconnect/types" "2.9.2" - "@walletconnect/utils" "2.9.2" + "@walletconnect/sign-client" "2.10.2" + "@walletconnect/types" "2.10.2" + "@walletconnect/utils" "2.10.2" events "^3.3.0" -"@walletconnect/utils@2.9.2": - version "2.9.2" - resolved "https://registry.yarnpkg.com/@walletconnect/utils/-/utils-2.9.2.tgz#035bdb859ee81a4bcc6420f56114cc5ec3e30afb" - integrity sha512-D44hwXET/8JhhIjqljY6qxSu7xXnlPrf63UN/Qfl98vDjWlYVcDl2+JIQRxD9GPastw0S8XZXdRq59XDXLuZBg== +"@walletconnect/utils@2.10.2": + version "2.10.2" + resolved "https://registry.yarnpkg.com/@walletconnect/utils/-/utils-2.10.2.tgz#1f2c6a2f1bb95bcc4517b1e94aa7164c9286eb46" + integrity sha512-syxXRpc2yhSknMu3IfiBGobxOY7fLfLTJuw+ppKaeO6WUdZpIit3wfuGOcc0Ms3ZPFCrGfyGOoZsCvgdXtptRg== dependencies: "@stablelib/chacha20poly1305" "1.0.1" "@stablelib/hkdf" "1.0.1" @@ -7166,45 +7068,20 @@ "@walletconnect/relay-api" "^1.0.9" "@walletconnect/safe-json" "^1.0.2" "@walletconnect/time" "^1.0.2" - "@walletconnect/types" "2.9.2" + "@walletconnect/types" "2.10.2" "@walletconnect/window-getters" "^1.0.1" "@walletconnect/window-metadata" "^1.0.1" detect-browser "5.3.0" query-string "7.1.3" uint8arrays "^3.1.0" -"@walletconnect/utils@^1.8.0": - version "1.8.0" - resolved "https://registry.yarnpkg.com/@walletconnect/utils/-/utils-1.8.0.tgz#2591a197c1fa7429941fe428876088fda6632060" - integrity sha512-zExzp8Mj1YiAIBfKNm5u622oNw44WOESzo6hj+Q3apSMIb0Jph9X3GDIdbZmvVZsNPxWDL7uodKgZcCInZv2vA== - dependencies: - "@walletconnect/browser-utils" "^1.8.0" - "@walletconnect/encoding" "^1.0.1" - "@walletconnect/jsonrpc-utils" "^1.0.3" - "@walletconnect/types" "^1.8.0" - bn.js "4.11.8" - js-sha3 "0.8.0" - query-string "6.13.5" - -"@walletconnect/window-getters@1.0.0": - version "1.0.0" - resolved "https://registry.yarnpkg.com/@walletconnect/window-getters/-/window-getters-1.0.0.tgz#1053224f77e725dfd611c83931b5f6c98c32bfc8" - integrity sha512-xB0SQsLaleIYIkSsl43vm8EwETpBzJ2gnzk7e0wMF3ktqiTGS6TFHxcprMl5R44KKh4tCcHCJwolMCaDSwtAaA== - -"@walletconnect/window-getters@^1.0.0", "@walletconnect/window-getters@^1.0.1": +"@walletconnect/window-getters@^1.0.1": version "1.0.1" resolved "https://registry.yarnpkg.com/@walletconnect/window-getters/-/window-getters-1.0.1.tgz#f36d1c72558a7f6b87ecc4451fc8bd44f63cbbdc" integrity sha512-vHp+HqzGxORPAN8gY03qnbTMnhqIwjeRJNOMOAzePRg4xVEEE2WvYsI9G2NMjOknA8hnuYbU3/hwLcKbjhc8+Q== dependencies: tslib "1.14.1" -"@walletconnect/window-metadata@1.0.0": - version "1.0.0" - resolved "https://registry.yarnpkg.com/@walletconnect/window-metadata/-/window-metadata-1.0.0.tgz#93b1cc685e6b9b202f29c26be550fde97800c4e5" - integrity sha512-9eFvmJxIKCC3YWOL97SgRkKhlyGXkrHwamfechmqszbypFspaSk+t2jQXAEU7YClHF6Qjw5eYOmy1//zFi9/GA== - dependencies: - "@walletconnect/window-getters" "^1.0.0" - "@walletconnect/window-metadata@^1.0.1": version "1.0.1" resolved "https://registry.yarnpkg.com/@walletconnect/window-metadata/-/window-metadata-1.0.1.tgz#2124f75447b7e989e4e4e1581d55d25bc75f7be5" @@ -7213,105 +7090,96 @@ "@walletconnect/window-getters" "^1.0.1" tslib "1.14.1" -"@web3-react/coinbase-wallet@^8.2.0": - version "8.2.0" - resolved "https://registry.yarnpkg.com/@web3-react/coinbase-wallet/-/coinbase-wallet-8.2.0.tgz#038bb9e915834046320621aa49db5ba79130e488" - integrity sha512-SFPrsRbyw1gECyKJmE/TAB3iMhHAqh9DTa8X2FKPMgPyNPVPcha4+G0SuWy55rysh0MO6TJbj9pofX3HvXaYpw== +"@web3-react/coinbase-wallet@^8.2.3": + version "8.2.3" + resolved "https://registry.yarnpkg.com/@web3-react/coinbase-wallet/-/coinbase-wallet-8.2.3.tgz#08d9ae9c9d15313a58f0bc33d970c73b0aaf813a" + integrity sha512-hYrOwv0RzhwQuI87GBv9ZHAblgrFg7YomnObOyuH2tPZT8+cQAtgP4D293TDQhW9SR1NXxzoS0tbTECWd4yUAQ== dependencies: - "@web3-react/types" "^8.2.0" + "@web3-react/types" "^8.2.3" -"@web3-react/core@^8.2.0": - version "8.2.0" - resolved "https://registry.yarnpkg.com/@web3-react/core/-/core-8.2.0.tgz#95fb615bb283be520e6f61b5e48cfb0047943808" - integrity sha512-r7dmK2E8Jrpvm/DF93hGMB+8lECHSI3Oo0NrHbhxkisK6in6rdgAXeYFhZtM48LBAm9py6fQvLzjCM6Qx9q0oQ== +"@web3-react/core@^8.2.3": + version "8.2.3" + resolved "https://registry.yarnpkg.com/@web3-react/core/-/core-8.2.3.tgz#142899e74401bfd3a481a1b9578b2fd8f9dfde81" + integrity sha512-0ezmRKhqQpoa9ct2/3erg60zBXfC/f/liYR1mfSGKtIroRkLnPARigZSV6pI+fi8bhfGJ0RKtFWyTCCWZzdq1w== dependencies: - "@web3-react/store" "^8.2.0" - "@web3-react/types" "^8.2.0" - zustand "^4.3.5" + "@web3-react/store" "^8.2.3" + "@web3-react/types" "^8.2.3" + zustand "4.4.0" optionalDependencies: "@ethersproject/providers" "^5" -"@web3-react/eip1193@^8.2.0": - version "8.2.0" - resolved "https://registry.yarnpkg.com/@web3-react/eip1193/-/eip1193-8.2.0.tgz#a7953769f9d0bec54472aceb01f72c889458378f" - integrity sha512-Ugbt+FisHO8aLD5o5B4AZdtgSVpjrbmtC5MgHrOEBw+IwFqr20EJreh052u8ExI2OrPjARIVOkNcp50Xxs7oUw== +"@web3-react/eip1193@^8.2.3": + version "8.2.3" + resolved "https://registry.yarnpkg.com/@web3-react/eip1193/-/eip1193-8.2.3.tgz#d09d5a5ea98719010eb7dd845631acb1f15c51e5" + integrity sha512-PdL8PCv3zgQrnowRlBK7PIO8G7v/nc31PYgarACo8mX+l5Y4+l7+ma/kpkULXp5yLtc4qlQYlCalmXpcbtl2FA== dependencies: - "@web3-react/types" "^8.2.0" + "@web3-react/types" "^8.2.3" eventemitter3 "^4.0.7" -"@web3-react/empty@^8.2.0": - version "8.2.0" - resolved "https://registry.yarnpkg.com/@web3-react/empty/-/empty-8.2.0.tgz#dac248ab22867700b5be716cd5a3f8f95308e8c5" - integrity sha512-U8BIF56lW1GHXFz9cPAJnlmKM8VcsjpXr+LXNXGS+9mr5AEjNcjbn9T9EnQf4hY4YXUPHAnjsVcZoUfw3q6u7Q== +"@web3-react/empty@^8.2.3": + version "8.2.3" + resolved "https://registry.yarnpkg.com/@web3-react/empty/-/empty-8.2.3.tgz#70a0b07d7918a1f10c6dc4001b9fefc2f72face8" + integrity sha512-Uopeac2XgyJLmK8EawNmG1kferlSvklKgWzbianygriC3C3+6yHvflUBmHzYfcpZDq5gotP4JJr2bmhGAocQ5w== dependencies: - "@web3-react/types" "^8.2.0" + "@web3-react/types" "^8.2.3" -"@web3-react/gnosis-safe@^8.2.0": - version "8.2.1" - resolved "https://registry.yarnpkg.com/@web3-react/gnosis-safe/-/gnosis-safe-8.2.1.tgz#c38601b2bd8c1a30691f9562693bc6e1b199e113" - integrity sha512-e4m6IphnnR3ENUnIL63GTN3uZGMdsb2V1uomJrbGtgcnZm/yM3/cea0f9J07+eF7zM6rIdad9NSbeivZQiiyOQ== +"@web3-react/gnosis-safe@^8.2.4": + version "8.2.4" + resolved "https://registry.yarnpkg.com/@web3-react/gnosis-safe/-/gnosis-safe-8.2.4.tgz#1f595a64bd26506a2e537b8a6734b5bf243d4e36" + integrity sha512-4M0CFludHJXtLsKJlKBIeMZcdTO60e6psYhYm2GLy76do9K9JJvBE8U4YVFBHLpk7sWpySsrCuYcaVZyzZ/xtA== dependencies: "@safe-global/safe-apps-provider" "^0.17.1" "@safe-global/safe-apps-sdk" "^8.0.0" - "@web3-react/types" "^8.2.0" + "@web3-react/types" "^8.2.3" -"@web3-react/metamask@^8.2.1": - version "8.2.1" - resolved "https://registry.yarnpkg.com/@web3-react/metamask/-/metamask-8.2.1.tgz#7ffac16e2a55ff8f1195e2831a9f9f99fa0bfba9" - integrity sha512-JysxkAImIygkD95Bimrj7HwcTq79tq4ZSlphZt24LBMrEVY5K8k+e5mCAuJuDZ7Fu+aBxqpS0lgPjaBGKdNu/A== +"@web3-react/metamask@^8.2.4": + version "8.2.4" + resolved "https://registry.yarnpkg.com/@web3-react/metamask/-/metamask-8.2.4.tgz#26438222c4b17964c011ea359058ba6feb6a2330" + integrity sha512-4yoqDgvcB0QKUGSk00/fUipA3z5rOXcQYAwE0CABPa5lbTRAIm5i8F0Gj8UW7QO0pQus4UtjX0+JxWdclB7UrA== dependencies: "@metamask/detect-provider" "^1.2.0" - "@web3-react/types" "^8.2.0" + "@web3-react/types" "^8.2.3" -"@web3-react/network@^8.2.0": - version "8.2.0" - resolved "https://registry.yarnpkg.com/@web3-react/network/-/network-8.2.0.tgz#225ae9e135711e8c64ab3123570abaa5b82b8145" - integrity sha512-3OcJwuaot8A+VTSoCe17MZv/K/TNVw7DjtYoS7lBRS/CmzYIwP53Tosea4MkliOuXiUUKj7Ge1D2FpWohq6pHw== +"@web3-react/network@^8.2.3": + version "8.2.3" + resolved "https://registry.yarnpkg.com/@web3-react/network/-/network-8.2.3.tgz#edc8268877006780321fed7e632ebd86ef057eb8" + integrity sha512-OAlXo3aNhldANmHt/N88SuLrWihVQizJf0cNy1cqnbNIAg87292PnAqCZrj3Pwaq/s8hoSgapc87zl1KFJeTjA== dependencies: "@ethersproject/providers" "^5" - "@web3-react/types" "^8.2.0" + "@web3-react/types" "^8.2.3" -"@web3-react/store@^8.2.0": - version "8.2.0" - resolved "https://registry.yarnpkg.com/@web3-react/store/-/store-8.2.0.tgz#4260c7d1fca3c8e0358f32ed8909a5d8dba69a80" - integrity sha512-cG8nb+tBeRUJu+98ko6YZuAWmoipGMEbR3bhineCNd4x2mXv3GbWSPtE17GeWVshZgDbZu2/Du0okTx+22VWCg== +"@web3-react/store@^8.2.3": + version "8.2.3" + resolved "https://registry.yarnpkg.com/@web3-react/store/-/store-8.2.3.tgz#64a0ddaf49f85c120e07f5089dd4d7df9346f881" + integrity sha512-qUJQ5pDsYYDra+/+glq2BmIS43HYAiEZ22sLLVh6E75WiZKRNOOqUxBDPe33KTIn718DLt51j+wd2FT+oT/kJQ== dependencies: "@ethersproject/address" "^5" - "@web3-react/types" "^8.2.0" - zustand "^4.3.5" + "@web3-react/types" "^8.2.3" + zustand "4.4.0" -"@web3-react/types@^8.2.0": - version "8.2.0" - resolved "https://registry.yarnpkg.com/@web3-react/types/-/types-8.2.0.tgz#195464ebb94cb417e6dc3c16951573f9b6b3832a" - integrity sha512-TBYTFlqJZaEpVbuAAKRJFX5PZc3lI1TqDZzY94zwCrCh4GBepwwK7+PxmRAppMFuNa5x0vFX/ghLEC44e6TCFg== +"@web3-react/types@^8.2.3": + version "8.2.3" + resolved "https://registry.yarnpkg.com/@web3-react/types/-/types-8.2.3.tgz#e2ac1eaaa7f96b518a5535fee048bf73470f5c21" + integrity sha512-kSG90QkN+n7IOtp10nQ44oS8J7jzfH9EmqnruwBpCGybh1FM/ohyRvUKWYZNfNE4wsjTSpKsINR0/VdDsZMHyg== dependencies: - zustand "^4.3.5" + zustand "4.4.0" -"@web3-react/url@^8.2.0": - version "8.2.0" - resolved "https://registry.yarnpkg.com/@web3-react/url/-/url-8.2.0.tgz#5df80f213bf6b6f382aa842ae37ad0703d413a37" - integrity sha512-dt1i8AgZso6y0sX67JSZ1DzsU511iFu4Gcxksbw/yJPlFybsHco+Fcg94WLjWj4ec26kVRUBySUVCyXrYlg0kQ== +"@web3-react/url@^8.2.3": + version "8.2.3" + resolved "https://registry.yarnpkg.com/@web3-react/url/-/url-8.2.3.tgz#20de44f6e653575f0d522c3e905ab00bf1e6a918" + integrity sha512-gOcs8uEbD+BKMvw2VhTWnD8Ls3aOmbebLwASu7daWYuM2eB8hS8AoqsEAbV1NnliNpY7ztd+L1Vi5CckiIhXcw== dependencies: "@ethersproject/providers" "^5" - "@web3-react/types" "^8.2.0" + "@web3-react/types" "^8.2.3" -"@web3-react/walletconnect-v2@^8.3.7": - version "8.3.7" - resolved "https://registry.yarnpkg.com/@web3-react/walletconnect-v2/-/walletconnect-v2-8.3.7.tgz#272ff3674eeb9a8eae2ae06a133993a6ff01669f" - integrity sha512-iaD6Uqhfdkk50n8S+ADJBttgivdMNuR+mti+v98WAUCO3Spnw5i47B2fs+qCQwJIwmD5qCis0zZzlZMwBOriGg== +"@web3-react/walletconnect-v2@^8.5.1": + version "8.5.1" + resolved "https://registry.yarnpkg.com/@web3-react/walletconnect-v2/-/walletconnect-v2-8.5.1.tgz#bc7d43b53bb30ec524e0cc36e20e1f279bf18818" + integrity sha512-K6RjdllFpEftTDQw39fRfuVcBLNCWXDxx5oZiWDc7D2RW071C0m1WridOeUiELmCXykyDCrIjd2zAVwV4GGueA== dependencies: - "@walletconnect/ethereum-provider" "^2.8.6" - "@walletconnect/modal" "^2.5.9" - "@web3-react/types" "^8.2.0" - eventemitter3 "^4.0.7" - -"@web3-react/walletconnect@^8.2.0": - version "8.2.0" - resolved "https://registry.yarnpkg.com/@web3-react/walletconnect/-/walletconnect-8.2.0.tgz#e4e325132f04f03a07a19cd193b4b97bfe6a9914" - integrity sha512-Yl1C0beRnwohtFZ9c6xz6mOci2MqoES2hYKhJI4X7qKqcmQJC6TOeLjlYfzjdUTUvP8IDf0A7flYZVeBUvL/fg== - dependencies: - "@walletconnect/ethereum-provider" "^1.7.8" - "@web3-react/types" "^8.2.0" + "@walletconnect/ethereum-provider" "^2.10.1" + "@walletconnect/modal" "^2.6.2" + "@web3-react/types" "^8.2.3" eventemitter3 "^4.0.7" "@webassemblyjs/ast@1.11.6", "@webassemblyjs/ast@^1.11.5": @@ -7575,11 +7443,6 @@ aes-js@3.0.0: resolved "https://registry.yarnpkg.com/aes-js/-/aes-js-3.0.0.tgz#e21df10ad6c2053295bcbb8dab40b09dbea87e4d" integrity sha512-H7wUZRn8WpTq9jocdxQ2c8x2sKo9ZVmzfRE13GiNJXfp7NcKYEdvl3vspKjXox6RIG2VtaRe4JFvxG4rqp2Zuw== -aes-js@^3.1.2: - version "3.1.2" - resolved "https://registry.yarnpkg.com/aes-js/-/aes-js-3.1.2.tgz#db9aabde85d5caabbfc0d4f2a4446960f627146a" - integrity sha512-e5pEa2kBnBOgR4Y/p20pskXI74UEz7de8ZGVo58asOtvSVG5YAbJeELPZxOmt+Bnz3rX753YKhfIn4X4l1PPRQ== - agent-base@6, agent-base@^6.0.2: version "6.0.2" resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-6.0.2.tgz#49fff58577cfee3f37176feab4c22e00f86d7f77" @@ -7672,11 +7535,6 @@ ansi-regex@^3.0.0: resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.1.tgz#123d6479e92ad45ad897d4054e3c7ca7db4944e1" integrity sha512-+O9Jct8wf++lXxxFc4hc8LsjaSq0HFzzL7cVsw8pRDIPdjKD2mT4ytDZlLuSBZ4cLKZFXIrMGO7DbQCtMJJMKw== -ansi-regex@^4.1.0: - version "4.1.1" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-4.1.1.tgz#164daac87ab2d6f6db3a29875e2d1766582dabed" - integrity sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g== - ansi-regex@^5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" @@ -8038,13 +7896,6 @@ axios@^0.19.2: dependencies: follow-redirects "1.5.10" -axios@^0.21.0: - version "0.21.4" - resolved "https://registry.yarnpkg.com/axios/-/axios-0.21.4.tgz#c67b90dc0568e5c1cf2b0b858c43ba28e2eda575" - integrity sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg== - dependencies: - follow-redirects "^1.14.0" - axios@^1.0.0: version "1.4.0" resolved "https://registry.yarnpkg.com/axios/-/axios-1.4.0.tgz#38a7bf1224cd308de271146038b551d725f0be1f" @@ -8516,12 +8367,7 @@ bn.js@4.11.6: resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.11.6.tgz#53344adb14617a13f6e8dd2ce28905d1c0ba3215" integrity sha512-XWwnNNFCuuSQ0m3r3C4LE3EiORltHd9M05pq6FOlVeiophzRbMo50Sbz1ehl8K3Z+jw9+vmgnXefY1hz8X+2wA== -bn.js@4.11.8: - version "4.11.8" - resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.11.8.tgz#2cde09eb5ee341f484746bb0309b3253b1b1442f" - integrity sha512-ItfYfPLkWHUjckQCk8xC+LwxgK8NYcXywGigJgSwOP8Y2iyWT4f2vsZnoOXTTbo+o5yXmIUJ4gn5538SO5S3gA== - -bn.js@^4.0.0, bn.js@^4.1.0, bn.js@^4.11.6, bn.js@^4.11.8, bn.js@^4.11.9, bn.js@^4.12.0: +bn.js@^4.0.0, bn.js@^4.1.0, bn.js@^4.11.0, bn.js@^4.11.6, bn.js@^4.11.8, bn.js@^4.11.9, bn.js@^4.12.0: version "4.12.0" resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.12.0.tgz#775b3f278efbb9718eec7361f483fb36fbbfea88" integrity sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA== @@ -8793,19 +8639,6 @@ bser@2.1.1: dependencies: node-int64 "^0.4.0" -buffer-alloc-unsafe@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/buffer-alloc-unsafe/-/buffer-alloc-unsafe-1.1.0.tgz#bd7dc26ae2972d0eda253be061dba992349c19f0" - integrity sha512-TEM2iMIEQdJ2yjPJoSIsldnleVaAk1oW3DBVUykyOLsEsFmEc9kn+SFFPz+gl54KQNxlDnAwCXosOS9Okx2xAg== - -buffer-alloc@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/buffer-alloc/-/buffer-alloc-1.2.0.tgz#890dd90d923a873e08e10e5fd51a57e5b7cce0ec" - integrity sha512-CFsHQgjtW1UChdXgbyJGtnm+O/uLQeZdtbDo8mfUgYXCHSM1wgrVxXm6bSyrUuErEb+4sYVGCzASBRot7zyrow== - dependencies: - buffer-alloc-unsafe "^1.1.0" - buffer-fill "^1.0.0" - buffer-crc32@~0.2.3: version "0.2.13" resolved "https://registry.yarnpkg.com/buffer-crc32/-/buffer-crc32-0.2.13.tgz#0d333e3f00eac50aa1454abd30ef8c2a5d9a7242" @@ -8816,12 +8649,7 @@ buffer-equal@0.0.1: resolved "https://registry.yarnpkg.com/buffer-equal/-/buffer-equal-0.0.1.tgz#91bc74b11ea405bc916bc6aa908faafa5b4aac4b" integrity sha512-RgSV6InVQ9ODPdLWJ5UAqBqJBOg370Nz6ZQtRzpt6nUjc8v0St97uJ4PYC6NztqIScrAXafKM3mZPMygSe1ggA== -buffer-fill@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/buffer-fill/-/buffer-fill-1.0.0.tgz#f8f78b76789888ef39f205cd637f68e702122b2c" - integrity sha512-T7zexNBwiiaCOGDg9xNX9PBmjrubblRkENuptryuI64URkXDFum9il/JGL8Lm8wYfAXpredVXXZz7eMHilimiQ== - -buffer-from@^1.0.0, buffer-from@^1.1.1: +buffer-from@^1.0.0: version "1.1.2" resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.2.tgz#2b146a6fd72e80b4f55d255f35ed59a3a9a41bd5" integrity sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ== @@ -9326,15 +9154,6 @@ clipboardy@^2.3.0: execa "^1.0.0" is-wsl "^2.1.1" -cliui@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/cliui/-/cliui-5.0.0.tgz#deefcfdb2e800784aa34f46fa08e06851c7bbbc5" - integrity sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA== - dependencies: - string-width "^3.1.0" - strip-ansi "^5.2.0" - wrap-ansi "^5.1.0" - cliui@^6.0.0: version "6.0.0" resolved "https://registry.yarnpkg.com/cliui/-/cliui-6.0.0.tgz#511d702c0c4e41ca156d7d0e96021f23e13225b1" @@ -9700,7 +9519,7 @@ cookie@^0.4.1: resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.4.2.tgz#0e41f24de5ecf317947c82fc789e06a884824432" integrity sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA== -copy-to-clipboard@^3.2.0, copy-to-clipboard@^3.3.1: +copy-to-clipboard@^3.2.0: version "3.3.3" resolved "https://registry.yarnpkg.com/copy-to-clipboard/-/copy-to-clipboard-3.3.3.tgz#55ac43a1db8ae639a4bd99511c148cdd1b83a1b0" integrity sha512-2KV8NhB5JqC3ky0r9PMCAZKbUHSwtEo4CwCs0KXgruG43gX5PMqDEBbVU4OUzw2MuAWUfsuFmWvEKG5QRfSnJA== @@ -10736,11 +10555,6 @@ destroy@1.2.0: resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.2.0.tgz#4803735509ad8be552934c67df614f94e66fa015" integrity sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg== -detect-browser@5.2.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/detect-browser/-/detect-browser-5.2.0.tgz#c9cd5afa96a6a19fda0bbe9e9be48a6b6e1e9c97" - integrity sha512-tr7XntDAu50BVENgQfajMLzacmSe34D+qZc4zjnniz0ZVuw/TZcLcyxHQjYpJTM36sGEkZZlYLnIM1hH7alTMA== - detect-browser@5.3.0: version "5.3.0" resolved "https://registry.yarnpkg.com/detect-browser/-/detect-browser-5.3.0.tgz#9705ef2bddf46072d0f7265a1fe300e36fe7ceca" @@ -11071,13 +10885,6 @@ ee-first@1.1.1: resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" integrity sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow== -eip1193-provider@1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/eip1193-provider/-/eip1193-provider-1.0.1.tgz#420d29cf4f6c443e3f32e718fb16fafb250637c3" - integrity sha512-kSuqwQ26d7CzuS/t3yRXo2Su2cVH0QfvyKbr2H7Be7O5YDyIq4hQGCNTo5wRdP07bt+E2R/8nPCzey4ojBHf7g== - dependencies: - "@json-rpc-tools/provider" "^1.5.5" - ejs@^3.1.6, ejs@^3.1.7: version "3.1.9" resolved "https://registry.yarnpkg.com/ejs/-/ejs-3.1.9.tgz#03c9e8777fe12686a9effcef22303ca3d8eeb361" @@ -11097,7 +10904,7 @@ electron-to-chromium@^1.4.477: resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.477.tgz#05669aa6f161ee9076a6805457e9bd9fe6d0dfd1" integrity sha512-shUVy6Eawp33dFBFIoYbIwLHrX0IZ857AlH9ug2o4rvbWmpaCUdBpQ5Zw39HRrfzAFm4APJE9V+E2A/WB0YqJw== -elliptic@6.5.4, elliptic@^6.4.0, elliptic@^6.5.3, elliptic@^6.5.4: +elliptic@6.5.4, elliptic@^6.4.0, elliptic@^6.5.2, elliptic@^6.5.3, elliptic@^6.5.4: version "6.5.4" resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.5.4.tgz#da37cebd31e79a1367e941b592ed1fbebd58abbb" integrity sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ== @@ -11125,11 +10932,6 @@ emittery@^0.8.1: resolved "https://registry.yarnpkg.com/emittery/-/emittery-0.8.1.tgz#bb23cc86d03b30aa75a7f734819dee2e1ba70860" integrity sha512-uDfvUjVrfGJJhymx/kz6prltenw1u7WrCg1oa94zYY8xxVpLLUu045LAT0dhDZdXG58/EpPL/5kA180fQ/qudg== -emoji-regex@^7.0.1: - version "7.0.3" - resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-7.0.3.tgz#933a04052860c85e83c122479c4748a8e4c72156" - integrity sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA== - emoji-regex@^8.0.0: version "8.0.0" resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" @@ -11965,6 +11767,16 @@ ethereum-cryptography@^0.1.3: secp256k1 "^4.0.1" setimmediate "^1.0.5" +ethereum-cryptography@^1.1.2: + version "1.2.0" + resolved "https://registry.yarnpkg.com/ethereum-cryptography/-/ethereum-cryptography-1.2.0.tgz#5ccfa183e85fdaf9f9b299a79430c044268c9b3a" + integrity sha512-6yFQC9b5ug6/17CQpCyE3k9eKBMdhyVjzUy1WkiuY/E4vj/SXDBbCw8QEIaXqf0Mf2SnY6RmpDcwlUmBSS0EJw== + dependencies: + "@noble/hashes" "1.2.0" + "@noble/secp256k1" "1.7.1" + "@scure/bip32" "1.1.5" + "@scure/bip39" "1.1.1" + ethereum-cryptography@^2.0.0: version "2.1.2" resolved "https://registry.yarnpkg.com/ethereum-cryptography/-/ethereum-cryptography-2.1.2.tgz#18fa7108622e56481157a5cb7c01c0c6a672eb67" @@ -11975,6 +11787,27 @@ ethereum-cryptography@^2.0.0: "@scure/bip32" "1.3.1" "@scure/bip39" "1.2.1" +ethereumjs-abi@^0.6.8: + version "0.6.8" + resolved "https://registry.yarnpkg.com/ethereumjs-abi/-/ethereumjs-abi-0.6.8.tgz#71bc152db099f70e62f108b7cdfca1b362c6fcae" + integrity sha512-Tx0r/iXI6r+lRsdvkFDlut0N08jWMnKRZ6Gkq+Nmw75lZe4e6o3EkSnkaBP5NF6+m5PTGAr9JP43N3LyeoglsA== + dependencies: + bn.js "^4.11.8" + ethereumjs-util "^6.0.0" + +ethereumjs-util@^6.0.0, ethereumjs-util@^6.2.1: + version "6.2.1" + resolved "https://registry.yarnpkg.com/ethereumjs-util/-/ethereumjs-util-6.2.1.tgz#fcb4e4dd5ceacb9d2305426ab1a5cd93e3163b69" + integrity sha512-W2Ktez4L01Vexijrm5EB6w7dg4n/TgpoYU4avuT5T3Vmnw/eCRtiBrJfQYS/DCSvDIOLn2k57GcHdeBcgVxAqw== + dependencies: + "@types/bn.js" "^4.11.3" + bn.js "^4.11.0" + create-hash "^1.1.2" + elliptic "^6.5.2" + ethereum-cryptography "^0.1.3" + ethjs-util "0.1.6" + rlp "^2.2.3" + ethereumjs-util@^7.1.0, ethereumjs-util@^7.1.1, ethereumjs-util@^7.1.2, ethereumjs-util@^7.1.5: version "7.1.5" resolved "https://registry.yarnpkg.com/ethereumjs-util/-/ethereumjs-util-7.1.5.tgz#9ecf04861e4fbbeed7465ece5f23317ad1129181" @@ -12030,7 +11863,7 @@ ethjs-unit@0.1.6: bn.js "4.11.6" number-to-bn "1.7.0" -ethjs-util@^0.1.6: +ethjs-util@0.1.6, ethjs-util@^0.1.6: version "0.1.6" resolved "https://registry.yarnpkg.com/ethjs-util/-/ethjs-util-0.1.6.tgz#f308b62f185f9fe6237132fb2a9818866a5cd536" integrity sha512-CUnVOQq7gSpDHZVVrQW8ExxUETWrnrvXYvYz55wOU8Uj4VCgw56XC2B/fVqQN+f7gmrnRHSLVnFAwsCuNwji8w== @@ -12053,7 +11886,7 @@ eventemitter3@4.0.4: resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-4.0.4.tgz#b5463ace635a083d018bdc7c917b4c5f10a85384" integrity sha512-rlaVLnVxtxvoyLsQQFBx53YmXHDxRIzzTLbdfxqi4yocpSjAxXwkU0cScM5JgSKMqEhrZpnvQ2D9gjylR0AimQ== -eventemitter3@4.0.7, eventemitter3@^4.0.0, eventemitter3@^4.0.7: +eventemitter3@^4.0.0, eventemitter3@^4.0.7: version "4.0.7" resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-4.0.7.tgz#2de9b68f6528d5644ef5c59526a1b4a07306169f" integrity sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw== @@ -12584,7 +12417,7 @@ follow-redirects@1.5.10: dependencies: debug "=3.1.0" -follow-redirects@^1.0.0, follow-redirects@^1.14.0, follow-redirects@^1.15.0: +follow-redirects@^1.0.0, follow-redirects@^1.15.0: version "1.15.2" resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.2.tgz#b460864144ba63f2681096f274c4e57026da2c13" integrity sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA== @@ -14523,7 +14356,7 @@ is-typed-array@^1.1.10, is-typed-array@^1.1.3, is-typed-array@^1.1.9: dependencies: which-typed-array "^1.1.11" -is-typedarray@1.0.0, is-typedarray@^1.0.0, is-typedarray@~1.0.0: +is-typedarray@^1.0.0, is-typedarray@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" integrity sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA== @@ -14565,7 +14398,7 @@ is-yarn-global@^0.3.0: resolved "https://registry.yarnpkg.com/is-yarn-global/-/is-yarn-global-0.3.0.tgz#d502d3382590ea3004893746754c89139973e232" integrity sha512-VjSeb/lHmkoyd8ryPVIKvOCn4D1koMqY+vqyjjUfc3xyKtP4dYOxM44sZrnqQSzSds3xyOrUTLTC9LVCVgLngw== -isarray@^2.0.1, isarray@^2.0.5: +isarray@^2.0.5: version "2.0.5" resolved "https://registry.yarnpkg.com/isarray/-/isarray-2.0.5.tgz#8af1e4c1221244cc62459faf38940d4e644a5723" integrity sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw== @@ -15947,6 +15780,11 @@ json-stable-stringify@^1.0.2: dependencies: jsonify "^0.0.1" +json-stringify-deterministic@^1.0.8: + version "1.0.10" + resolved "https://registry.yarnpkg.com/json-stringify-deterministic/-/json-stringify-deterministic-1.0.10.tgz#d56660b6e9c12f47dee4340ec2ce26745fa6ee64" + integrity sha512-hBLYMyCnoYh0rQ2ZyEegbLaFAS5KqOZ6HZ5fgq6lGWhtNRKw2JUp/hkfjQS1bjYZlHW9AjvXBWCJe9OwcugRNw== + json-stringify-safe@^5.0.1, json-stringify-safe@~5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" @@ -16242,14 +16080,21 @@ lit-html@^2.7.0: dependencies: "@types/trusted-types" "^2.0.2" -lit@2.7.6: - version "2.7.6" - resolved "https://registry.yarnpkg.com/lit/-/lit-2.7.6.tgz#810007b876ed43e0c70124de91831921598b1665" - integrity sha512-1amFHA7t4VaaDe+vdQejSVBklwtH9svGoG6/dZi9JhxtJBBlqY5D1RV7iLUYY0trCqQc4NfhYYZilZiVHt7Hxg== +lit-html@^2.8.0: + version "2.8.0" + resolved "https://registry.yarnpkg.com/lit-html/-/lit-html-2.8.0.tgz#96456a4bb4ee717b9a7d2f94562a16509d39bffa" + integrity sha512-o9t+MQM3P4y7M7yNzqAyjp7z+mQGa4NS4CxiyLqFPyFWyc4O+nodLrkrxSaCTrla6M5YOLaT3RpbbqjszB5g3Q== + dependencies: + "@types/trusted-types" "^2.0.2" + +lit@2.8.0: + version "2.8.0" + resolved "https://registry.yarnpkg.com/lit/-/lit-2.8.0.tgz#4d838ae03059bf9cafa06e5c61d8acc0081e974e" + integrity sha512-4Sc3OFX9QHOJaHbmTMk28SYgVxLN3ePDjg7hofEft2zWlehFL3LiAuapWc4U/kYwMYJSh2hTCPZ6/LIC7ii0MA== dependencies: "@lit/reactive-element" "^1.6.0" lit-element "^3.3.0" - lit-html "^2.7.0" + lit-html "^2.8.0" load-bmfont@^1.3.1: version "1.4.1" @@ -18403,7 +18248,7 @@ pkg-up@^4.0.0: dependencies: find-up "^6.2.0" -pngjs@^3.0.0, pngjs@^3.3.0, pngjs@^3.3.3: +pngjs@^3.0.0, pngjs@^3.3.3: version "3.4.0" resolved "https://registry.yarnpkg.com/pngjs/-/pngjs-3.4.0.tgz#99ca7d725965fb655814eaf65f38f12bbdbf555f" integrity sha512-NCrCHhWmnQklfH4MtJMRjZ2a8c80qXeMlQMv2uVp9ISJMTt562SbGd6n2oq0PaPgKm7Z6pL9E2UlLIhC+SHL3w== @@ -18996,11 +18841,6 @@ postcss@^8.3.5, postcss@^8.4.21, postcss@^8.4.23, postcss@^8.4.26, postcss@^8.4. picocolors "^1.0.0" source-map-js "^1.0.2" -preact@10.4.1: - version "10.4.1" - resolved "https://registry.yarnpkg.com/preact/-/preact-10.4.1.tgz#9b3ba020547673a231c6cf16f0fbaef0e8863431" - integrity sha512-WKrRpCSwL2t3tpOOGhf2WfTpcmbpxaWtDbdJdKdjd0aEiTkvOmS4NBkG6kzlaAHI9AkQ3iVqbFWM3Ei7mZ4o1Q== - preact@^10.5.9: version "10.16.0" resolved "https://registry.yarnpkg.com/preact/-/preact-10.16.0.tgz#68a06d70b191b8a313ea722d61e09c6b2a79a37e" @@ -19077,16 +18917,16 @@ process-nextick-args@~2.0.0: resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2" integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag== -"process-polyfill@npm:process@^0.11.10", process@^0.11.10: - version "0.11.10" - resolved "https://registry.yarnpkg.com/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182" - integrity sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A== - process-warning@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/process-warning/-/process-warning-1.0.0.tgz#980a0b25dc38cd6034181be4b7726d89066b4616" integrity sha512-du4wfLyj4yCZq1VupnVSZmRsPJsNuxoDQFdCFHLaYiEbFBD7QE0a+I4D7hOxrVnh78QE/YipFAj9lXHiXocV+Q== +process@^0.11.10: + version "0.11.10" + resolved "https://registry.yarnpkg.com/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182" + integrity sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A== + progress@^2.0.3: version "2.0.3" resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8" @@ -19266,19 +19106,6 @@ q@^1.1.2, q@^1.5.1: resolved "https://registry.yarnpkg.com/q/-/q-1.5.1.tgz#7e32f75b41381291d04611f1bf14109ac00651d7" integrity sha512-kV/CThkXo6xyFEZUugw/+pIOywXcDbFYgSct5cT3gqlbkBE1SJdwy6UQoZvodiWF/ckQLZyDE/Bu1M6gVu5lVw== -qrcode@1.4.4: - version "1.4.4" - resolved "https://registry.yarnpkg.com/qrcode/-/qrcode-1.4.4.tgz#f0c43568a7e7510a55efc3b88d9602f71963ea83" - integrity sha512-oLzEC5+NKFou9P0bMj5+v6Z40evexeE29Z9cummZXZ9QXyMr3lphkURzxjXgPJC5azpxcshoDWV1xE46z+/c3Q== - dependencies: - buffer "^5.4.3" - buffer-alloc "^1.2.0" - buffer-from "^1.1.1" - dijkstrajs "^1.0.1" - isarray "^2.0.1" - pngjs "^3.3.0" - yargs "^13.2.4" - qrcode@1.5.3: version "1.5.3" resolved "https://registry.yarnpkg.com/qrcode/-/qrcode-1.5.3.tgz#03afa80912c0dccf12bc93f615a535aad1066170" @@ -19315,15 +19142,6 @@ qs@~6.5.2: resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.3.tgz#3aeeffc91967ef6e35c0e488ef46fb296ab76aad" integrity sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA== -query-string@6.13.5: - version "6.13.5" - resolved "https://registry.yarnpkg.com/query-string/-/query-string-6.13.5.tgz#99e95e2fb7021db90a6f373f990c0c814b3812d8" - integrity sha512-svk3xg9qHR39P3JlHuD7g3nRnyay5mHbrPctEBDUxUkHRifPHXJDhBUycdCC0NBjXoDf44Gb+IsOZL1Uwn8M/Q== - dependencies: - decode-uri-component "^0.2.0" - split-on-first "^1.0.0" - strict-uri-encode "^2.0.0" - query-string@7.1.3: version "7.1.3" resolved "https://registry.yarnpkg.com/query-string/-/query-string-7.1.3.tgz#a1cf90e994abb113a325804a972d98276fe02328" @@ -20407,7 +20225,7 @@ ripple-lib@^1.10.1: ripple-lib-transactionparser "0.8.2" ws "^7.2.0" -rlp@^2.2.4: +rlp@^2.2.3, rlp@^2.2.4: version "2.2.7" resolved "https://registry.yarnpkg.com/rlp/-/rlp-2.2.7.tgz#33f31c4afac81124ac4b283e2bd4d9720b30beaf" integrity sha512-d5gdPmgQ0Z+AklL2NVXr/IoSjNZFfTVvQWzL/AM2AOcSzYP2xjlb0AC8YyCLc41MSNf6P6QVtjgPdmVtzb+4lQ== @@ -21298,15 +21116,6 @@ string-width@^2.1.1: is-fullwidth-code-point "^2.0.0" strip-ansi "^4.0.0" -string-width@^3.0.0, string-width@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-3.1.0.tgz#22767be21b62af1081574306f69ac51b62203961" - integrity sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w== - dependencies: - emoji-regex "^7.0.1" - is-fullwidth-code-point "^2.0.0" - strip-ansi "^5.1.0" - string-width@^5.0.1, string-width@^5.1.2: version "5.1.2" resolved "https://registry.yarnpkg.com/string-width/-/string-width-5.1.2.tgz#14f8daec6d81e7221d2a357e668cab73bdbca794" @@ -21394,13 +21203,6 @@ strip-ansi@^4.0.0: dependencies: ansi-regex "^3.0.0" -strip-ansi@^5.0.0, strip-ansi@^5.1.0, strip-ansi@^5.2.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-5.2.0.tgz#8c9a536feb6afc962bdfa5b104a5091c1ad9c0ae" - integrity sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA== - dependencies: - ansi-regex "^4.1.0" - strip-ansi@^7.0.1: version "7.1.0" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-7.1.0.tgz#d5b6568ca689d8561370b0707685d22434faff45" @@ -22391,7 +22193,7 @@ typed-array-length@^1.0.4: for-each "^0.3.3" is-typed-array "^1.1.9" -typedarray-to-buffer@3.1.5, typedarray-to-buffer@^3.1.5: +typedarray-to-buffer@^3.1.5: version "3.1.5" resolved "https://registry.yarnpkg.com/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz#a97ee7a9ff42691b9f783ff1bc5112fe3fca9080" integrity sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q== @@ -22817,10 +22619,10 @@ validator@^13.7.0: resolved "https://registry.yarnpkg.com/validator/-/validator-13.9.0.tgz#33e7b85b604f3bbce9bb1a05d5c3e22e1c2ff855" integrity sha512-B+dGG8U3fdtM0/aNK4/X8CXq/EcxU2WPrPEkJGslb47qyHsxmbggTWK0yEA4qnYVNF+nxNlN88o14hIcPmSIEA== -valtio@1.11.0: - version "1.11.0" - resolved "https://registry.yarnpkg.com/valtio/-/valtio-1.11.0.tgz#c029dcd17a0f99d2fbec933721fe64cfd32a31ed" - integrity sha512-65Yd0yU5qs86b5lN1eu/nzcTgQ9/6YnD6iO+DDaDbQLn1Zv2w12Gwk43WkPlUBxk5wL/6cD5YMFf7kj6HZ1Kpg== +valtio@1.11.2: + version "1.11.2" + resolved "https://registry.yarnpkg.com/valtio/-/valtio-1.11.2.tgz#b8049c02dfe65620635d23ebae9121a741bb6530" + integrity sha512-1XfIxnUXzyswPAPXo1P3Pdx2mq/pIqZICkWN60Hby0d9Iqb+MEIpqgYVlbflvHdrp2YR/q3jyKWRPJJ100yxaw== dependencies: proxy-compare "2.5.1" use-sync-external-store "1.2.0" @@ -22928,15 +22730,15 @@ vite-plugin-dts@~2.3.0: magic-string "^0.29.0" ts-morph "18.0.0" -vite-plugin-node-polyfills@^0.11.1: - version "0.11.1" - resolved "https://registry.yarnpkg.com/vite-plugin-node-polyfills/-/vite-plugin-node-polyfills-0.11.1.tgz#5f947258a7025d9f22b72f45075fabc6763ed61b" - integrity sha512-9bIZGzMhaGk2s/UC0fpDyIsPo5e33xAUAgZOav2GMgxC5KD48lgTecMmWgL326idrXmLGI12ef52CsKHSvSV6Q== +vite-plugin-node-polyfills@^0.12.0: + version "0.12.0" + resolved "https://registry.yarnpkg.com/vite-plugin-node-polyfills/-/vite-plugin-node-polyfills-0.12.0.tgz#f97606cb9bdfa66e71d83738e5e05a409096321f" + integrity sha512-xZfpD81aNhwEbIjccEiy8Q/hDdnlYqBSeEaUMIukOpGHuMaz65jqrC2lmnF/FXnliovISy2L1n92da0JOvk36A== dependencies: "@rollup/plugin-inject" "^5.0.3" buffer-polyfill "npm:buffer@^6.0.3" node-stdlib-browser "^1.2.0" - process-polyfill "npm:process@^0.11.10" + process "^0.11.10" vite-plugin-pwa@^0.16.4: version "0.16.4" @@ -23296,7 +23098,7 @@ web3-shh@1.10.0: web3-core-subscriptions "1.10.0" web3-net "1.10.0" -web3-utils@1.10.0, web3-utils@^1.8.1: +web3-utils@1.10.0, web3-utils@^1.5.1, web3-utils@^1.8.1: version "1.10.0" resolved "https://registry.yarnpkg.com/web3-utils/-/web3-utils-1.10.0.tgz#ca4c1b431a765c14ac7f773e92e0fd9377ccf578" integrity sha512-kSaCM0uMcZTNUSmn5vMEhlo02RObGNRRCkdX0V9UTAU0+lrvn0HSaudyCo6CQzuXUsnuY2ERJGCGPfeWmv19Rg== @@ -23309,7 +23111,7 @@ web3-utils@1.10.0, web3-utils@^1.8.1: randombytes "^2.1.0" utf8 "3.0.0" -web3@^1.8.1: +web3@^1.5.1, web3@^1.8.1: version "1.10.0" resolved "https://registry.yarnpkg.com/web3/-/web3-1.10.0.tgz#2fde0009f59aa756c93e07ea2a7f3ab971091274" integrity sha512-YfKY9wSkGcM8seO+daR89oVTcbu18NsVfvOngzqMYGUU0pPSQmE57qQDvQzUeoIOHAnXEBNzrhjQJmm8ER0rng== @@ -23973,15 +23775,6 @@ wrap-ansi@^4.0.0: string-width "^2.1.1" strip-ansi "^4.0.0" -wrap-ansi@^5.1.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-5.1.0.tgz#1fd1f67235d5b6d0fee781056001bfb694c03b09" - integrity sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q== - dependencies: - ansi-styles "^3.2.0" - string-width "^3.0.0" - strip-ansi "^5.0.0" - wrap-ansi@^6.2.0: version "6.2.0" resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-6.2.0.tgz#e9393ba07102e6c91a3b221478f0257cd2856e53" @@ -24028,12 +23821,7 @@ ws@7.4.6: resolved "https://registry.yarnpkg.com/ws/-/ws-7.4.6.tgz#5654ca8ecdeee47c33a9a4bf6d28e2be2980377c" integrity sha512-YmhHDO4MzaDLB+M9ym/mDA5z0naX8j7SIlT8f8z+I0VtzsRbekxEutHSme7NPS2qE8StCYQNUnfWdXta/Yu85A== -ws@7.5.3: - version "7.5.3" - resolved "https://registry.yarnpkg.com/ws/-/ws-7.5.3.tgz#160835b63c7d97bfab418fc1b8a9fced2ac01a74" - integrity sha512-kQ/dHIzuLrS6Je9+uv81ueZomEwH0qVYstcAQ4/Z93K8zeko9gtAbttJWzoC5ukqXY1PpoouV3+VSOqEAFt5wg== - -ws@7.5.9, ws@^7.2.0, ws@^7.4.0, ws@^7.4.5, ws@^7.4.6, ws@^7.5.1: +ws@7.5.9, ws@^7.2.0, ws@^7.4.5, ws@^7.4.6, ws@^7.5.1: version "7.5.9" resolved "https://registry.yarnpkg.com/ws/-/ws-7.5.9.tgz#54fa7db29f4c7cec68b1ddd3a89de099942bb591" integrity sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q== @@ -24182,14 +23970,6 @@ yargs-parser@^10.0.0: dependencies: camelcase "^4.1.0" -yargs-parser@^13.1.2: - version "13.1.2" - resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-13.1.2.tgz#130f09702ebaeef2650d54ce6e3e5706f7a4fb38" - integrity sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg== - dependencies: - camelcase "^5.0.0" - decamelize "^1.2.0" - yargs-parser@^18.1.2, yargs-parser@^18.1.3: version "18.1.3" resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-18.1.3.tgz#be68c4975c6b2abf469236b0c870362fab09a7b0" @@ -24203,22 +23983,6 @@ yargs-parser@^20.2.2, yargs-parser@^20.2.3, yargs-parser@^20.2.9: resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.9.tgz#2eb7dc3b0289718fc295f362753845c41a0c94ee" integrity sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w== -yargs@^13.2.4: - version "13.3.2" - resolved "https://registry.yarnpkg.com/yargs/-/yargs-13.3.2.tgz#ad7ffefec1aa59565ac915f82dccb38a9c31a2dd" - integrity sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw== - dependencies: - cliui "^5.0.0" - find-up "^3.0.0" - get-caller-file "^2.0.1" - require-directory "^2.1.1" - require-main-filename "^2.0.0" - set-blocking "^2.0.0" - string-width "^3.0.0" - which-module "^2.0.0" - y18n "^4.0.0" - yargs-parser "^13.1.2" - yargs@^15.3.1, yargs@^15.4.1: version "15.4.1" resolved "https://registry.yarnpkg.com/yargs/-/yargs-15.4.1.tgz#0d87a16de01aee9d8bec2bfbf74f67851730f4f8" @@ -24296,9 +24060,9 @@ z-schema@~5.0.2: optionalDependencies: commander "^10.0.0" -zustand@^4.3.5: - version "4.3.9" - resolved "https://registry.yarnpkg.com/zustand/-/zustand-4.3.9.tgz#a7d4332bbd75dfd25c6848180b3df1407217f2ad" - integrity sha512-Tat5r8jOMG1Vcsj8uldMyqYKC5IZvQif8zetmLHs9WoZlntTHmIoNM8TpLRY31ExncuUvUOXehd0kvahkuHjDw== +zustand@4.4.0: + version "4.4.0" + resolved "https://registry.yarnpkg.com/zustand/-/zustand-4.4.0.tgz#13b3e8ca959dd53d536034440aec382ff91b65c3" + integrity sha512-2dq6wq4dSxbiPTamGar0NlIG/av0wpyWZJGeQYtUOLegIUvhM2Bf86ekPlmgpUtS5uR7HyetSiktYrGsdsyZgQ== dependencies: use-sync-external-store "1.2.0"