From 436b8b0d337115bbce177b437750f31da005ac1f Mon Sep 17 00:00:00 2001 From: Evgeny Taktarov Date: Thu, 27 Jun 2024 11:12:28 +0700 Subject: [PATCH 01/61] feat: add cors to all external endpoints --- pages/api/eth-apr.ts | 2 ++ pages/api/eth-price.ts | 2 ++ pages/api/ldo-stats.ts | 2 ++ pages/api/lido-stats.ts | 2 ++ pages/api/lidostats.ts | 2 ++ pages/api/sma-steth-apr.ts | 2 ++ pages/api/totalsupply.ts | 2 ++ utilsApi/nextApiWrappers.ts | 12 ++++++++---- 8 files changed, 22 insertions(+), 4 deletions(-) diff --git a/pages/api/eth-apr.ts b/pages/api/eth-apr.ts index fc7638a32..8b66eb650 100644 --- a/pages/api/eth-apr.ts +++ b/pages/api/eth-apr.ts @@ -16,6 +16,7 @@ import { sunsetBy, httpMethodGuard, HttpMethod, + cors, } from 'utilsApi'; import Metrics from 'utilsApi/metrics'; @@ -39,6 +40,7 @@ const ethApr: API = async (_, res) => { export default wrapNextRequest([ httpMethodGuard([HttpMethod.GET]), + cors({ origin: ['*'], methods: [HttpMethod.GET] }), rateLimit, responseTimeMetric(Metrics.request.apiTimings, API_ROUTES.ETH_APR), sunsetBy({ diff --git a/pages/api/eth-price.ts b/pages/api/eth-price.ts index 7529d1700..9f978438f 100644 --- a/pages/api/eth-price.ts +++ b/pages/api/eth-price.ts @@ -13,6 +13,7 @@ import { rateLimit, httpMethodGuard, HttpMethod, + cors, } from 'utilsApi'; import Metrics from 'utilsApi/metrics'; import { API } from 'types'; @@ -39,6 +40,7 @@ const ethPrice: API = async (req, res) => { export default wrapNextRequest([ httpMethodGuard([HttpMethod.GET]), + cors({ origin: ['*'], methods: [HttpMethod.GET] }), rateLimit, responseTimeMetric(Metrics.request.apiTimings, API_ROUTES.ETH_PRICE), cacheControl({ headers: config.CACHE_ETH_PRICE_HEADERS }), diff --git a/pages/api/ldo-stats.ts b/pages/api/ldo-stats.ts index 912f56681..42555b972 100644 --- a/pages/api/ldo-stats.ts +++ b/pages/api/ldo-stats.ts @@ -12,6 +12,7 @@ import { sunsetBy, httpMethodGuard, HttpMethod, + cors, } from 'utilsApi'; import Metrics from 'utilsApi/metrics'; import { API } from 'types'; @@ -41,6 +42,7 @@ const ldoStats: API = async (req, res) => { export default wrapNextRequest([ httpMethodGuard([HttpMethod.GET]), + cors({ origin: ['*'], methods: [HttpMethod.GET] }), rateLimit, responseTimeMetric(Metrics.request.apiTimings, API_ROUTES.LDO_STATS), sunsetBy({ diff --git a/pages/api/lido-stats.ts b/pages/api/lido-stats.ts index a7dc64c5d..9eab96005 100644 --- a/pages/api/lido-stats.ts +++ b/pages/api/lido-stats.ts @@ -11,6 +11,7 @@ import { sunsetBy, httpMethodGuard, HttpMethod, + cors, } from 'utilsApi'; import Metrics from 'utilsApi/metrics'; import { API } from 'types'; @@ -39,6 +40,7 @@ const lidoStats: API = async (req, res) => { export default wrapNextRequest([ httpMethodGuard([HttpMethod.GET]), + cors({ origin: ['*'], methods: [HttpMethod.GET] }), rateLimit, responseTimeMetric(Metrics.request.apiTimings, API_ROUTES.LIDO_STATS), sunsetBy({ diff --git a/pages/api/lidostats.ts b/pages/api/lidostats.ts index a9135d9e7..bfd434083 100644 --- a/pages/api/lidostats.ts +++ b/pages/api/lidostats.ts @@ -11,6 +11,7 @@ import { sunsetBy, httpMethodGuard, HttpMethod, + cors, } from 'utilsApi'; import Metrics from 'utilsApi/metrics'; import { API } from 'types'; @@ -40,6 +41,7 @@ const lidoStats: API = async (req, res) => { export default wrapNextRequest([ httpMethodGuard([HttpMethod.GET]), + cors({ origin: ['*'], methods: [HttpMethod.GET] }), rateLimit, responseTimeMetric(Metrics.request.apiTimings, API_ROUTES.LIDOSTATS), sunsetBy({ diff --git a/pages/api/sma-steth-apr.ts b/pages/api/sma-steth-apr.ts index c3e3dc607..261a027f5 100644 --- a/pages/api/sma-steth-apr.ts +++ b/pages/api/sma-steth-apr.ts @@ -16,6 +16,7 @@ import { sunsetBy, httpMethodGuard, HttpMethod, + cors, } from 'utilsApi'; import Metrics from 'utilsApi/metrics'; @@ -41,6 +42,7 @@ const smaStethApr: API = async (_, res) => { export default wrapNextRequest([ httpMethodGuard([HttpMethod.GET]), + cors({ origin: ['*'], methods: [HttpMethod.GET] }), rateLimit, responseTimeMetric(Metrics.request.apiTimings, API_ROUTES.SMA_STETH_APR), sunsetBy({ diff --git a/pages/api/totalsupply.ts b/pages/api/totalsupply.ts index 2621bd811..c65499cdd 100644 --- a/pages/api/totalsupply.ts +++ b/pages/api/totalsupply.ts @@ -13,6 +13,7 @@ import { rateLimit, httpMethodGuard, HttpMethod, + cors, } from 'utilsApi'; import Metrics from 'utilsApi/metrics'; import { API } from 'types'; @@ -39,6 +40,7 @@ const totalSupply: API = async (req, res) => { export default wrapNextRequest([ httpMethodGuard([HttpMethod.GET]), + cors({ origin: ['*'], methods: [HttpMethod.GET] }), rateLimit, responseTimeMetric(Metrics.request.apiTimings, API_ROUTES.TOTALSUPPLY), cacheControl({ headers: config.CACHE_TOTAL_SUPPLY_HEADERS }), diff --git a/utilsApi/nextApiWrappers.ts b/utilsApi/nextApiWrappers.ts index e4987dbb7..88c78ca38 100644 --- a/utilsApi/nextApiWrappers.ts +++ b/utilsApi/nextApiWrappers.ts @@ -61,8 +61,8 @@ export const cors = res.setHeader('Access-Control-Allow-Credentials', String(credentials)); res.setHeader('Access-Control-Allow-Origin', origin); - res.setHeader('Access-Control-Allow-Methods', methods.toString()); - res.setHeader('Access-Control-Allow-Headers', allowedHeaders.toString()); + res.setHeader('Access-Control-Allow-Methods', methods.join(', ')); + res.setHeader('Access-Control-Allow-Headers', allowedHeaders.join(', ')); if (req.method === HttpMethod.OPTIONS) { // In preflight just need return a CORS headers @@ -81,8 +81,12 @@ export const httpMethodGuard = !req.method || !Object.values(methodAllowList).includes(req.method as HttpMethod) ) { - res.status(405); - throw new Error(`You can use only: ${methodAllowList.toString()}`); + // allow OPTIONS to pass trough but still add Allow header + res.setHeader('Allow', methodAllowList.join(', ')); + if (req.method !== HttpMethod.OPTIONS) { + res.status(405); + throw new Error(`You can use only: ${methodAllowList.toString()}`); + } } await next?.(req, res, next); From b92b1672c6c6fbe71eaef8778460b07df53f6171 Mon Sep 17 00:00:00 2001 From: Anton Shalimov Date: Thu, 27 Jun 2024 11:36:56 +0300 Subject: [PATCH 02/61] feat: error boundary --- features/stake/stake.tsx | 12 ++++++++++ .../wsteth/unwrap/unwrap-form/unwrap-form.tsx | 7 +++++- package.json | 1 + pages/_app.tsx | 8 ++++++- .../error-boundary/error-boundary.tsx | 22 +++++++++++++++++++ shared/components/error-boundary/index.ts | 1 + yarn.lock | 14 ++++++++++++ 7 files changed, 63 insertions(+), 2 deletions(-) create mode 100644 shared/components/error-boundary/error-boundary.tsx create mode 100644 shared/components/error-boundary/index.ts diff --git a/features/stake/stake.tsx b/features/stake/stake.tsx index bdf554b15..b18568bf0 100644 --- a/features/stake/stake.tsx +++ b/features/stake/stake.tsx @@ -1,3 +1,5 @@ +import { useErrorBoundary } from 'react-error-boundary'; + import { FaqPlaceholder } from 'features/ipfs'; import { useWeb3Key } from 'shared/hooks/useWeb3Key'; import NoSSRWrapper from 'shared/components/no-ssr-wrapper'; @@ -10,8 +12,18 @@ import { StakeForm } from './stake-form'; export const Stake = () => { const key = useWeb3Key(); + const { showBoundary } = useErrorBoundary(); + return ( <> + {/* TODO: DEMO, delete later */} + diff --git a/features/wsteth/unwrap/unwrap-form/unwrap-form.tsx b/features/wsteth/unwrap/unwrap-form/unwrap-form.tsx index 27befa33e..d6ea90cf3 100644 --- a/features/wsteth/unwrap/unwrap-form/unwrap-form.tsx +++ b/features/wsteth/unwrap/unwrap-form/unwrap-form.tsx @@ -1,4 +1,4 @@ -import { memo, FC } from 'react'; +import { FC, memo, useEffect } from 'react'; import { useFeatureFlag, VAULTS_BANNER_IS_ENABLED } from 'config/feature-flags'; import { MATOMO_CLICK_EVENTS } from 'consts/matomo-click-events'; @@ -14,6 +14,11 @@ import { SubmitButtonUnwrap } from '../unwrap-form-controls/submit-button-unwrap export const UnwrapForm: FC = memo(() => { const { vaultsBannerIsEnabled } = useFeatureFlag(VAULTS_BANNER_IS_ENABLED); + // TODO: DEMO, delete later + useEffect(() => { + throw new Error('UnwrapForm -> useEffect'); + }, []); + return ( diff --git a/package.json b/package.json index 0737100b0..3561f39fb 100644 --- a/package.json +++ b/package.json @@ -64,6 +64,7 @@ "react": "^18.2.0", "react-device-detect": "^1.17.0", "react-dom": "^18.2.0", + "react-error-boundary": "^4.0.13", "react-hook-form": "^7.45.2", "react-is": "^18.2.0", "react-transition-group": "^4.4.2", diff --git a/pages/_app.tsx b/pages/_app.tsx index e016045d4..32a0b7c15 100644 --- a/pages/_app.tsx +++ b/pages/_app.tsx @@ -1,4 +1,5 @@ import { memo } from 'react'; +import { ErrorBoundary } from 'react-error-boundary'; import { AppProps } from 'next/app'; import 'nprogress/nprogress.css'; import Head from 'next/head'; @@ -15,6 +16,7 @@ import { withCsp } from 'config/csp'; import { SecurityStatusBanner } from 'features/ipfs'; import { Providers } from 'providers'; import { BackgroundGradient } from 'shared/components/background-gradient/background-gradient'; +import { ErrorBoundaryFallback } from 'shared/components/error-boundary'; import NoSsrWrapper from 'shared/components/no-ssr-wrapper'; import { nprogress, COOKIES_ALLOWED_FULL_KEY } from 'utils'; @@ -30,7 +32,11 @@ nprogress(); const App = (props: AppProps) => { const { Component, pageProps } = props; - return ; + return ( + + + + ); }; const MemoApp = memo(App); diff --git a/shared/components/error-boundary/error-boundary.tsx b/shared/components/error-boundary/error-boundary.tsx new file mode 100644 index 000000000..dfdb7b201 --- /dev/null +++ b/shared/components/error-boundary/error-boundary.tsx @@ -0,0 +1,22 @@ +import Head from 'next/head'; +import { ServicePage, Button } from '@lidofinance/lido-ui'; + +export const ErrorBoundaryFallback = () => { + return ( + + + Lido | Client Side Error + +

Something went wrong

+ +
+ ); +}; diff --git a/shared/components/error-boundary/index.ts b/shared/components/error-boundary/index.ts new file mode 100644 index 000000000..39d945d40 --- /dev/null +++ b/shared/components/error-boundary/index.ts @@ -0,0 +1 @@ +export * from './error-boundary'; diff --git a/yarn.lock b/yarn.lock index e85d5b36e..2635fd4a4 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1000,6 +1000,13 @@ resolved "https://registry.yarnpkg.com/@babel/regjsgen/-/regjsgen-0.8.0.tgz#f0ba69b075e1f05fb2825b7fad991e7adbb18310" integrity sha512-x/rqGMdzj+fWZvCOYForTghzbtqPDZ5gPwaoNGHdgDfF2QA/XZbCBp4Moo5scrkAMPhB7z26XM/AaHuIJdgauA== +"@babel/runtime@^7.12.5": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.24.7.tgz#f4f0d5530e8dbdf59b3451b9b3e594b6ba082e12" + integrity sha512-UwgBRMjJP+xv857DCngvqXI3Iq6J4v0wXmwc6sapg+zyhbwmQX67LUEFrkK5tbyJ30jGuG3ZvWpBiB9LCy1kWw== + dependencies: + regenerator-runtime "^0.14.0" + "@babel/runtime@^7.17.2", "@babel/runtime@^7.23.2", "@babel/runtime@^7.23.4", "@babel/runtime@^7.5.5", "@babel/runtime@^7.8.4", "@babel/runtime@^7.8.7": version "7.23.9" resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.23.9.tgz#47791a15e4603bb5f905bc0753801cf21d6345f7" @@ -9093,6 +9100,13 @@ react-dom@^18.2.0: loose-envify "^1.1.0" scheduler "^0.23.0" +react-error-boundary@^4.0.13: + version "4.0.13" + resolved "https://registry.yarnpkg.com/react-error-boundary/-/react-error-boundary-4.0.13.tgz#80386b7b27b1131c5fbb7368b8c0d983354c7947" + integrity sha512-b6PwbdSv8XeOSYvjt8LpgpKrZ0yGdtZokYwkwV2wlcZbxgopHX/hgPl5VgpnoVOWd868n1hktM8Qm4b+02MiLQ== + dependencies: + "@babel/runtime" "^7.12.5" + react-hook-form@^7.45.2: version "7.49.3" resolved "https://registry.yarnpkg.com/react-hook-form/-/react-hook-form-7.49.3.tgz#576a4567f8a774830812f4855e89f5da5830435c" From a6f224df93146a5885063b808d47724db009ae9f Mon Sep 17 00:00:00 2001 From: Anton Shalimov Date: Wed, 3 Jul 2024 10:13:36 +0300 Subject: [PATCH 03/61] chore: remove demo and todos --- features/stake/stake.tsx | 11 ----------- features/wsteth/unwrap/unwrap-form/unwrap-form.tsx | 6 +----- 2 files changed, 1 insertion(+), 16 deletions(-) diff --git a/features/stake/stake.tsx b/features/stake/stake.tsx index b18568bf0..4bb58ee3a 100644 --- a/features/stake/stake.tsx +++ b/features/stake/stake.tsx @@ -1,5 +1,3 @@ -import { useErrorBoundary } from 'react-error-boundary'; - import { FaqPlaceholder } from 'features/ipfs'; import { useWeb3Key } from 'shared/hooks/useWeb3Key'; import NoSSRWrapper from 'shared/components/no-ssr-wrapper'; @@ -12,18 +10,9 @@ import { StakeForm } from './stake-form'; export const Stake = () => { const key = useWeb3Key(); - const { showBoundary } = useErrorBoundary(); return ( <> - {/* TODO: DEMO, delete later */} - diff --git a/features/wsteth/unwrap/unwrap-form/unwrap-form.tsx b/features/wsteth/unwrap/unwrap-form/unwrap-form.tsx index d6ea90cf3..311a52235 100644 --- a/features/wsteth/unwrap/unwrap-form/unwrap-form.tsx +++ b/features/wsteth/unwrap/unwrap-form/unwrap-form.tsx @@ -1,4 +1,4 @@ -import { FC, memo, useEffect } from 'react'; +import { FC, memo } from 'react'; import { useFeatureFlag, VAULTS_BANNER_IS_ENABLED } from 'config/feature-flags'; import { MATOMO_CLICK_EVENTS } from 'consts/matomo-click-events'; @@ -14,10 +14,6 @@ import { SubmitButtonUnwrap } from '../unwrap-form-controls/submit-button-unwrap export const UnwrapForm: FC = memo(() => { const { vaultsBannerIsEnabled } = useFeatureFlag(VAULTS_BANNER_IS_ENABLED); - // TODO: DEMO, delete later - useEffect(() => { - throw new Error('UnwrapForm -> useEffect'); - }, []); return ( From e3be992fe6d67380d593c68c8ebde4b072a119c4 Mon Sep 17 00:00:00 2001 From: Anton Shalimov Date: Wed, 3 Jul 2024 10:14:58 +0300 Subject: [PATCH 04/61] feat: change text --- shared/components/error-boundary/error-boundary.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shared/components/error-boundary/error-boundary.tsx b/shared/components/error-boundary/error-boundary.tsx index dfdb7b201..dc0949bd9 100644 --- a/shared/components/error-boundary/error-boundary.tsx +++ b/shared/components/error-boundary/error-boundary.tsx @@ -15,7 +15,7 @@ export const ErrorBoundaryFallback = () => { size={'xxs'} color={'secondary'} > - Restart the page + Reload page ); From 48afa9683490e21448e253e1a48eeea964f19c8d Mon Sep 17 00:00:00 2001 From: Evgeny Taktarov Date: Wed, 3 Jul 2024 17:28:10 +0700 Subject: [PATCH 05/61] feat: proxy endpoints to eth-api --- config/get-secret-config.ts | 5 - consts/api.ts | 16 +-- global.d.ts | 7 -- next.config.mjs | 7 -- pages/api/eth-apr.ts | 31 ++---- pages/api/eth-price.ts | 42 ++++---- pages/api/lido-stats.ts | 2 +- pages/api/lidostats.ts | 29 +----- pages/api/oneinch-rate.ts | 131 ++++--------------------- pages/api/rewards.ts | 53 ++-------- pages/api/short-lido-stats.ts | 62 ++++-------- pages/api/sma-steth-apr.ts | 33 ++----- pages/api/totalsupply.ts | 44 ++++----- utils/index.ts | 1 - utils/parallelizePromises.ts | 11 --- utilsApi/apiHelpers.ts | 9 -- utilsApi/cached-proxy.ts | 97 ++++++++++++++++++ utilsApi/get-one-inch-rate.ts | 54 ---------- utilsApi/getEthApr.ts | 97 ------------------ utilsApi/getEthPrice.ts | 27 ----- utilsApi/getLidoHoldersViaSubgraphs.ts | 92 ----------------- utilsApi/getSmaStethApr.ts | 60 ----------- utilsApi/getStEthPrice.ts | 31 ------ utilsApi/getSubgraphUrl.ts | 13 --- utilsApi/getTotalStaked.ts | 41 -------- utilsApi/index.ts | 8 -- utilsApi/nextApiWrappers.ts | 2 +- 27 files changed, 212 insertions(+), 793 deletions(-) delete mode 100644 utils/parallelizePromises.ts delete mode 100644 utilsApi/apiHelpers.ts create mode 100644 utilsApi/cached-proxy.ts delete mode 100644 utilsApi/get-one-inch-rate.ts delete mode 100644 utilsApi/getEthApr.ts delete mode 100644 utilsApi/getEthPrice.ts delete mode 100644 utilsApi/getLidoHoldersViaSubgraphs.ts delete mode 100644 utilsApi/getSmaStethApr.ts delete mode 100644 utilsApi/getStEthPrice.ts delete mode 100644 utilsApi/getSubgraphUrl.ts delete mode 100644 utilsApi/getTotalStaked.ts diff --git a/config/get-secret-config.ts b/config/get-secret-config.ts index 0c9c055d4..45187cceb 100644 --- a/config/get-secret-config.ts +++ b/config/get-secret-config.ts @@ -14,8 +14,6 @@ export type SecretConfigType = Modify< cspReportOnly: boolean; - subgraphRequestTimeout: number; - rateLimit: number; rateLimitTimeFrame: number; } @@ -49,9 +47,6 @@ export const getSecretConfig = (): SecretConfigType => { cspReportOnly: toBoolean(serverRuntimeConfig.cspReportOnly), - subgraphRequestTimeout: - Number(serverRuntimeConfig.subgraphRequestTimeout) || 5000, - rateLimit: Number(serverRuntimeConfig.rateLimit) || 100, rateLimitTimeFrame: Number(serverRuntimeConfig.rateLimitTimeFrame) || 60, // 1 minute; }; diff --git a/consts/api.ts b/consts/api.ts index 6ea658d8a..c8463e40a 100644 --- a/consts/api.ts +++ b/consts/api.ts @@ -26,19 +26,23 @@ export const enum API_ROUTES { } const getEthApiOrigin = (path: string) => { - const { hostname, protocol } = new URL(config.rootOrigin); - return protocol + '//' + 'eth-api.' + hostname + path; + return config.ethAPIBasePath + path; }; -export const getReplacementLink = ( - apiRoute: API_ROUTES, -): string | undefined => { +export const getReplacementLink = (apiRoute: API_ROUTES): string => { switch (apiRoute) { case API_ROUTES.ETH_APR: return getEthApiOrigin('/v1/protocol/eth/apr/last'); + case API_ROUTES.ETH_PRICE: + return getEthApiOrigin('/v1/protocol/eth/price'); + case API_ROUTES.TOTALSUPPLY: + case API_ROUTES.SHORT_LIDO_STATS: + return getEthApiOrigin('/v1/protocol/steth/stats'); case API_ROUTES.SMA_STETH_APR: return getEthApiOrigin('/v1/protocol/steth/apr/sma'); + case API_ROUTES.ONEINCH_RATE: + return getEthApiOrigin('/v1/swap/one-inch'); default: - return; + throw new Error(`No replacement link found for route: ${apiRoute}`); } }; diff --git a/global.d.ts b/global.d.ts index 7197c454c..6c1111f33 100644 --- a/global.d.ts +++ b/global.d.ts @@ -30,17 +30,10 @@ declare module 'next/config' { rpcUrls_17000: string | undefined; ethplorerApiKey: string | undefined; - oneInchApiKey: string | undefined; - cspTrustedHosts: string | undefined; cspReportUri: string | undefined; cspReportOnly: string | undefined; - subgraphMainnet: string | undefined; - subgraphGoerli: string | undefined; - subgraphHolesky: string | undefined; - subgraphRequestTimeout: string | undefined; - rateLimit: string; rateLimitTimeFrame: string; diff --git a/next.config.mjs b/next.config.mjs index f5299b6b1..be121bb84 100644 --- a/next.config.mjs +++ b/next.config.mjs @@ -148,17 +148,10 @@ export default withBundleAnalyzer({ rpcUrls_17000: process.env.EL_RPC_URLS_17000, ethplorerApiKey: process.env.ETHPLORER_API_KEY, - oneInchApiKey: process.env.ONE_INCH_API_KEY, - cspTrustedHosts: process.env.CSP_TRUSTED_HOSTS, cspReportUri: process.env.CSP_REPORT_URI, cspReportOnly: process.env.CSP_REPORT_ONLY, - subgraphMainnet: process.env.SUBGRAPH_MAINNET, - subgraphGoerli: process.env.SUBGRAPH_GOERLI, - subgraphHolesky: process.env.SUBGRAPH_HOLESKY, - subgraphRequestTimeout: process.env.SUBGRAPH_REQUEST_TIMEOUT, - rateLimit: process.env.RATE_LIMIT, rateLimitTimeFrame: process.env.RATE_LIMIT_TIME_FRAME, diff --git a/pages/api/eth-apr.ts b/pages/api/eth-apr.ts index fc7638a32..3c0e96bb5 100644 --- a/pages/api/eth-apr.ts +++ b/pages/api/eth-apr.ts @@ -1,7 +1,5 @@ -import { Cache } from 'memory-cache'; import { wrapRequest as wrapNextRequest } from '@lidofinance/next-api-wrapper'; -import { API } from 'types'; import { config } from 'config'; import { API_DEFAULT_SUNSET_TIMESTAMP, @@ -9,7 +7,6 @@ import { getReplacementLink, } from 'consts/api'; import { - getEthApr, errorAndCacheDefaultWrappers, responseTimeMetric, rateLimit, @@ -18,24 +15,7 @@ import { HttpMethod, } from 'utilsApi'; import Metrics from 'utilsApi/metrics'; - -const cache = new Cache(); - -// Proxy for third-party API. -// Returns eth annual percentage rate -// TODO: delete after viewing grafana -const ethApr: API = async (_, res) => { - const cachedEthApr = cache.get(config.CACHE_ETH_APR_KEY); - - if (cachedEthApr) { - res.json(cachedEthApr); - } else { - const ethApr = await getEthApr(); - cache.put(config.CACHE_ETH_APR_KEY, ethApr, config.CACHE_ETH_APR_TTL); - - res.json(ethApr); - } -}; +import { createEthApiProxy } from 'utilsApi/cached-proxy'; export default wrapNextRequest([ httpMethodGuard([HttpMethod.GET]), @@ -46,4 +26,11 @@ export default wrapNextRequest([ replacementLink: getReplacementLink(API_ROUTES.ETH_APR), }), ...errorAndCacheDefaultWrappers, -])(ethApr); +])( + createEthApiProxy({ + cacheTTL: config.CACHE_ETH_APR_TTL, + endpoint: '/v1/protocol/eth/apr/last', + ignoreParams: true, + transformData: (data) => data.data.apr.toFixed(1), + }), +); diff --git a/pages/api/eth-price.ts b/pages/api/eth-price.ts index 7529d1700..4a34e0ed5 100644 --- a/pages/api/eth-price.ts +++ b/pages/api/eth-price.ts @@ -1,46 +1,40 @@ -import { Cache } from 'memory-cache'; import { wrapRequest as wrapNextRequest, cacheControl, } from '@lidofinance/next-api-wrapper'; import { config } from 'config'; -import { API_ROUTES } from 'consts/api'; import { - getEthPrice, + API_DEFAULT_SUNSET_TIMESTAMP, + API_ROUTES, + getReplacementLink, +} from 'consts/api'; +import { defaultErrorHandler, responseTimeMetric, rateLimit, httpMethodGuard, HttpMethod, + sunsetBy, } from 'utilsApi'; import Metrics from 'utilsApi/metrics'; -import { API } from 'types'; - -const cache = new Cache(); - -// Proxy for third-party API. -const ethPrice: API = async (req, res) => { - const cachedEthPrice = cache.get(config.CACHE_ETH_PRICE_KEY); - - if (cachedEthPrice) { - res.json(cachedEthPrice); - } else { - const ethPrice = await getEthPrice(); - cache.put( - config.CACHE_ETH_PRICE_KEY, - { price: ethPrice }, - config.CACHE_ETH_PRICE_TTL, - ); - res.json({ price: ethPrice }); - } -}; +import { createEthApiProxy } from 'utilsApi/cached-proxy'; export default wrapNextRequest([ httpMethodGuard([HttpMethod.GET]), rateLimit, responseTimeMetric(Metrics.request.apiTimings, API_ROUTES.ETH_PRICE), cacheControl({ headers: config.CACHE_ETH_PRICE_HEADERS }), + sunsetBy({ + sunsetTimestamp: API_DEFAULT_SUNSET_TIMESTAMP, + replacementLink: getReplacementLink(API_ROUTES.ETH_PRICE), + }), defaultErrorHandler, -])(ethPrice); +])( + createEthApiProxy({ + cacheTTL: config.CACHE_ETH_PRICE_TTL, + endpoint: '/v1/protocol/eth/price', + ignoreParams: true, + }), +); diff --git a/pages/api/lido-stats.ts b/pages/api/lido-stats.ts index a7dc64c5d..64342a75c 100644 --- a/pages/api/lido-stats.ts +++ b/pages/api/lido-stats.ts @@ -20,7 +20,7 @@ const cache = new Cache(); // Proxy for third-party API. // Returns steth token information // DEPRECATED: In future will be delete!!! -const lidoStats: API = async (req, res) => { +export const lidoStats: API = async (req, res) => { const cachedLidoStats = cache.get(config.CACHE_LIDO_STATS_KEY); if (cachedLidoStats) { diff --git a/pages/api/lidostats.ts b/pages/api/lidostats.ts index a9135d9e7..d6beb7fbd 100644 --- a/pages/api/lidostats.ts +++ b/pages/api/lidostats.ts @@ -1,10 +1,7 @@ -import { Cache } from 'memory-cache'; import { wrapRequest as wrapNextRequest } from '@lidofinance/next-api-wrapper'; -import { config } from 'config'; import { API_DEFAULT_SUNSET_TIMESTAMP, API_ROUTES } from 'consts/api'; import { - getLidoStats, responseTimeMetric, errorAndCacheDefaultWrappers, rateLimit, @@ -13,31 +10,9 @@ import { HttpMethod, } from 'utilsApi'; import Metrics from 'utilsApi/metrics'; -import { API } from 'types'; - -const cache = new Cache(); - -// Proxy for third-party API. -// Returns steth token information -// Mirror of /api/lido-stats -// DEPRECATED: In future will be delete!!! -const lidoStats: API = async (req, res) => { - const cachedLidoStats = cache.get(config.CACHE_LIDO_STATS_KEY); - - if (cachedLidoStats) { - res.json(cachedLidoStats); - } else { - const lidoStats = await getLidoStats(); - cache.put( - config.CACHE_LIDO_STATS_KEY, - { data: lidoStats }, - config.CACHE_LIDO_STATS_TTL, - ); - - res.json({ data: lidoStats }); - } -}; +import lidoStats from './lido-stats'; +// Mirror for /lido-stats export default wrapNextRequest([ httpMethodGuard([HttpMethod.GET]), rateLimit, diff --git a/pages/api/oneinch-rate.ts b/pages/api/oneinch-rate.ts index 605a9b79e..6a625dcd5 100644 --- a/pages/api/oneinch-rate.ts +++ b/pages/api/oneinch-rate.ts @@ -1,132 +1,37 @@ -import { Cache } from 'memory-cache'; -import { NextApiRequest, NextApiResponse } from 'next'; -import { BigNumber } from 'ethers'; -import invariant from 'tiny-invariant'; - -import { parseEther } from '@ethersproject/units'; -import { Zero } from '@ethersproject/constants'; import { wrapRequest as wrapNextRequest } from '@lidofinance/next-api-wrapper'; -import { CHAINS, TOKENS, getTokenAddress } from '@lido-sdk/constants'; import { config } from 'config'; -import { API_ROUTES } from 'consts/api'; import { - getOneInchRate, + API_DEFAULT_SUNSET_TIMESTAMP, + API_ROUTES, + getReplacementLink, +} from 'consts/api'; +import { responseTimeMetric, errorAndCacheDefaultWrappers, rateLimit, httpMethodGuard, HttpMethod, cors, + sunsetBy, } from 'utilsApi'; import Metrics from 'utilsApi/metrics'; -import { FetcherError } from 'utils/fetcherError'; -import { API } from 'types'; - -type OneInchRateResponse = { - rate: number; - toReceive: string; -}; - -const cache = new Cache(); - -const DEFAULT_AMOUNT = parseEther('1'); -const TOKEN_ETH = 'ETH'; -// Amounts larger make 1inch API return 500 -const MAX_BIGINT = BigNumber.from( - '10000000000000000000000000000000000000000000000000000000000000000000', -); -const TOKEN_ALLOWED_LIST = [TOKEN_ETH, TOKENS.STETH, TOKENS.WSTETH]; -const ETH_DUMMY_ADDRESS = '0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee'; -const PASSTHROUGH_CODES = [400, 422, 429]; - -const validateAndParseParams = (req: NextApiRequest, res: NextApiResponse) => { - let token = req.query?.token || TOKEN_ETH; - let amount = DEFAULT_AMOUNT; - try { - // Token can be array - /api/oneinch-rate?token=eth&token=eth&token=eth - if (Array.isArray(token)) { - throw new Error(`Token must be a string`); - } - - token = token.toLocaleUpperCase(); - if (!TOKEN_ALLOWED_LIST.includes(token)) { - throw new Error(`You can only use ${TOKEN_ALLOWED_LIST.toString()}`); - } - - if (req.query.amount) { - if (token === 'ETH') { - throw new Error(`Amount is not allowed to token ETH`); - } - if (Array.isArray(req.query.amount)) { - throw new Error(`Amount must be a string`); - } - try { - amount = BigNumber.from(req.query.amount); - } catch { - throw new Error(`Amount must be a valid BigNumber string`); - } - if (amount.lte(Zero)) throw new Error(`Amount must be positive`); - if (amount.gt(MAX_BIGINT)) throw new Error('Amount too large'); - } - } catch (e) { - const message = e instanceof Error ? e.message : 'invalid request'; - res.status(422).json({ error: message }); - throw e; - } - - return { token, amount }; -}; - -// Proxy for third-party API. -// Query params: -// * (optional) token: see TOKEN_ALLOWED_LIST above. Default see TOKEN_ETH above. -// * (optional) amount: BigNumber string. Default see DEFAULT_AMOUNT above. -// Returns 1inch rate -const oneInchRate: API = async (req, res) => { - const { token, amount } = validateAndParseParams(req, res); - const cacheKey = `${config.CACHE_ONE_INCH_RATE_KEY}-${token}-${amount}`; - const cachedOneInchRate = cache.get(cacheKey); - - if (cachedOneInchRate) { - res.status(200).json(cachedOneInchRate); - return; - } - - // for ETH, ETH -> STETH - // else, TOKEN -> ETH - const fromToken = - token === TOKEN_ETH - ? ETH_DUMMY_ADDRESS - : getTokenAddress(CHAINS.Mainnet, token as TOKENS); - const toToken = - token === TOKEN_ETH - ? getTokenAddress(CHAINS.Mainnet, TOKENS.STETH) - : ETH_DUMMY_ADDRESS; - - try { - const oneInchRate = await getOneInchRate(fromToken, toToken, amount); - invariant(oneInchRate); - const result = { - rate: oneInchRate.rate, - toReceive: oneInchRate.toAmount.toString(), - }; - cache.put(cacheKey, result, config.CACHE_ONE_INCH_RATE_TTL); - res.status(200).json(result); - } catch (err) { - if (err instanceof FetcherError && PASSTHROUGH_CODES.includes(err.status)) { - res.status(err.status).json({ message: err.message }); - return; - } - console.error('[oneInchRate] Request to 1inch failed', err); - throw err; - } -}; +import { createEthApiProxy } from 'utilsApi/cached-proxy'; export default wrapNextRequest([ httpMethodGuard([HttpMethod.GET]), cors({ origin: ['*'], methods: [HttpMethod.GET] }), rateLimit, responseTimeMetric(Metrics.request.apiTimings, API_ROUTES.ONEINCH_RATE), + sunsetBy({ + sunsetTimestamp: API_DEFAULT_SUNSET_TIMESTAMP, + replacementLink: getReplacementLink(API_ROUTES.ONEINCH_RATE), + }), ...errorAndCacheDefaultWrappers, -])(oneInchRate); +])( + createEthApiProxy({ + cacheTTL: config.CACHE_ONE_INCH_RATE_TTL, + endpoint: '/v1/swap/one-inch', + ignoreParams: false, + }), +); diff --git a/pages/api/rewards.ts b/pages/api/rewards.ts index 04cd3225c..7947ceb83 100644 --- a/pages/api/rewards.ts +++ b/pages/api/rewards.ts @@ -5,57 +5,16 @@ import { import { config, secretConfig } from 'config'; import { API_ROUTES } from 'consts/api'; -import { API } from 'types'; import { defaultErrorHandler, responseTimeMetric, rateLimit, - responseTimeExternalMetricWrapper, httpMethodGuard, HttpMethod, cors, } from 'utilsApi'; import Metrics from 'utilsApi/metrics'; -import { standardFetcher } from 'utils/standardFetcher'; - -const TIMEOUT = 10_000; - -const rewards: API = async (req, res) => { - if (!req.query.address) { - res.status(400).json({ status: 'invalid request' }); - return; - } - - const controller = new AbortController(); - const timeoutId = setTimeout(() => controller.abort(), TIMEOUT); - - const query = req.query; - const params = new URLSearchParams(); - - Object.entries(query).forEach( - ([k, v]) => - v && params.append(k, Array.isArray(v) ? v[0].toString() : v.toString()), - ); - - const result = await responseTimeExternalMetricWrapper({ - payload: secretConfig.rewardsBackendAPI, - request: () => - standardFetcher( - `${secretConfig.rewardsBackendAPI}/?${params.toString()}`, - { - headers: { - Accept: 'application/json', - 'Content-Type': 'application/json', - }, - signal: controller.signal, - }, - ), - }); - - res.status(200).json(result); - - clearTimeout(timeoutId); -}; +import { createCachedProxy } from 'utilsApi/cached-proxy'; export default wrapNextRequest([ httpMethodGuard([HttpMethod.GET]), @@ -64,4 +23,12 @@ export default wrapNextRequest([ responseTimeMetric(Metrics.request.apiTimings, API_ROUTES.REWARDS), cacheControl({ headers: config.CACHE_REWARDS_HEADERS }), defaultErrorHandler, -])(rewards); +])( + createCachedProxy({ + proxyUrl: (secretConfig.rewardsBackendAPI as string) + '/', + cacheTTL: 1000, + ignoreParams: false, + metricsHost: secretConfig.rewardsBackendAPI, + timeout: 10_000, + }), +); diff --git a/pages/api/short-lido-stats.ts b/pages/api/short-lido-stats.ts index f114dc26a..cb9253746 100644 --- a/pages/api/short-lido-stats.ts +++ b/pages/api/short-lido-stats.ts @@ -1,64 +1,38 @@ -import { Cache } from 'memory-cache'; import { wrapRequest as wrapNextRequest } from '@lidofinance/next-api-wrapper'; import { config } from 'config'; -import { API_ROUTES } from 'consts/api'; +import { + API_DEFAULT_SUNSET_TIMESTAMP, + API_ROUTES, + getReplacementLink, +} from 'consts/api'; -import { API, SubgraphChains } from 'types'; import { cors, errorAndCacheDefaultWrappers, - getLidoHoldersViaSubgraphs, - getStEthPrice, - getTotalStaked, HttpMethod, httpMethodGuard, rateLimit, responseTimeMetric, + sunsetBy, } from 'utilsApi'; import Metrics from 'utilsApi/metrics'; -import { parallelizePromises } from 'utils'; - -const cache = new Cache(); - -// Proxy for third-party API. -// Returns stETH token information -const shortLidoStats: API = async (req, res) => { - const chainId = - (Number(req.query.chainId) as SubgraphChains) || config.defaultChain; - const cacheKey = `${config.CACHE_LIDO_SHORT_STATS_KEY}_${chainId}`; - - const cachedLidoStats = cache.get(cacheKey); - if (cachedLidoStats) { - res.status(200).json(cachedLidoStats); - } else { - const [lidoHolders, totalStaked, stEthPrice] = await parallelizePromises([ - getLidoHoldersViaSubgraphs(chainId), - getTotalStaked(chainId), - getStEthPrice(), - ]); - - const shortLidoStats = { - uniqueAnytimeHolders: lidoHolders?.data?.stats?.uniqueAnytimeHolders, - uniqueHolders: lidoHolders?.data?.stats?.uniqueHolders, - totalStaked, - marketCap: Number(totalStaked) * stEthPrice, - }; - - // set the cache if there is all the data - // because right now there is no request error handling in parallelizePromises - if (lidoHolders && totalStaked && stEthPrice) { - cache.put(cacheKey, shortLidoStats, config.CACHE_LIDO_SHORT_STATS_TTL); - } - - res.status(200).json(shortLidoStats); - } -}; +import { createEthApiProxy } from 'utilsApi/cached-proxy'; export default wrapNextRequest([ httpMethodGuard([HttpMethod.GET]), cors({ origin: ['*'], methods: [HttpMethod.GET] }), rateLimit, responseTimeMetric(Metrics.request.apiTimings, API_ROUTES.SHORT_LIDO_STATS), + sunsetBy({ + sunsetTimestamp: API_DEFAULT_SUNSET_TIMESTAMP, + replacementLink: getReplacementLink(API_ROUTES.SHORT_LIDO_STATS), + }), ...errorAndCacheDefaultWrappers, -])(shortLidoStats); +])( + createEthApiProxy({ + cacheTTL: config.CACHE_LIDO_SHORT_STATS_TTL, + endpoint: '/v1/protocol/steth/stats', + ignoreParams: true, + }), +); diff --git a/pages/api/sma-steth-apr.ts b/pages/api/sma-steth-apr.ts index c3e3dc607..b6776818f 100644 --- a/pages/api/sma-steth-apr.ts +++ b/pages/api/sma-steth-apr.ts @@ -1,7 +1,5 @@ -import { Cache } from 'memory-cache'; import { wrapRequest as wrapNextRequest } from '@lidofinance/next-api-wrapper'; -import { API } from 'types'; import { config } from 'config'; import { API_DEFAULT_SUNSET_TIMESTAMP, @@ -12,32 +10,12 @@ import { responseTimeMetric, errorAndCacheDefaultWrappers, rateLimit, - getSmaStethApr, sunsetBy, httpMethodGuard, HttpMethod, } from 'utilsApi'; import Metrics from 'utilsApi/metrics'; - -const cache = new Cache(); - -// TODO: deprecated, will be delete after check grafana dashboards -const smaStethApr: API = async (_, res) => { - const cachedStethApr = cache.get(config.CACHE_SMA_STETH_APR_KEY); - - if (cachedStethApr) { - res.json(cachedStethApr); - } else { - const smaStethApr = await getSmaStethApr(); - cache.put( - config.CACHE_SMA_STETH_APR_KEY, - smaStethApr, - config.CACHE_SMA_STETH_APR_TTL, - ); - - res.json(smaStethApr); - } -}; +import { createEthApiProxy } from 'utilsApi/cached-proxy'; export default wrapNextRequest([ httpMethodGuard([HttpMethod.GET]), @@ -48,4 +26,11 @@ export default wrapNextRequest([ replacementLink: getReplacementLink(API_ROUTES.SMA_STETH_APR), }), ...errorAndCacheDefaultWrappers, -])(smaStethApr); +])( + createEthApiProxy({ + cacheTTL: config.CACHE_SMA_STETH_APR_TTL, + endpoint: '/v1/protocol/steth/apr/sma', + ignoreParams: true, + transformData: (data) => data.data.smaApr.toFixed(1), + }), +); diff --git a/pages/api/totalsupply.ts b/pages/api/totalsupply.ts index 2621bd811..d65c192a4 100644 --- a/pages/api/totalsupply.ts +++ b/pages/api/totalsupply.ts @@ -1,46 +1,40 @@ -import { Cache } from 'memory-cache'; import { wrapRequest as wrapNextRequest, cacheControl, } from '@lidofinance/next-api-wrapper'; import { config } from 'config'; -import { API_ROUTES } from 'consts/api'; import { - getTotalStaked, + API_DEFAULT_SUNSET_TIMESTAMP, + API_ROUTES, + getReplacementLink, +} from 'consts/api'; +import { defaultErrorHandler, responseTimeMetric, rateLimit, httpMethodGuard, HttpMethod, + sunsetBy, } from 'utilsApi'; import Metrics from 'utilsApi/metrics'; -import { API } from 'types'; - -const cache = new Cache(); - -// Proxy for third-party API. -const totalSupply: API = async (req, res) => { - const cachedTotalSupply = cache.get(config.CACHE_TOTAL_SUPPLY_KEY); - - if (cachedTotalSupply) { - res.json(cachedTotalSupply); - } else { - const totalSupply = await getTotalStaked(); - cache.put( - config.CACHE_TOTAL_SUPPLY_KEY, - totalSupply, - config.CACHE_TOTAL_SUPPLY_TTL, - ); - - res.json(totalSupply); - } -}; +import { createEthApiProxy } from 'utilsApi/cached-proxy'; export default wrapNextRequest([ httpMethodGuard([HttpMethod.GET]), rateLimit, responseTimeMetric(Metrics.request.apiTimings, API_ROUTES.TOTALSUPPLY), cacheControl({ headers: config.CACHE_TOTAL_SUPPLY_HEADERS }), + sunsetBy({ + sunsetTimestamp: API_DEFAULT_SUNSET_TIMESTAMP, + replacementLink: getReplacementLink(API_ROUTES.TOTALSUPPLY), + }), defaultErrorHandler, -])(totalSupply); +])( + createEthApiProxy({ + cacheTTL: config.CACHE_TOTAL_SUPPLY_TTL, + endpoint: '/v1/protocol/steth/stats', + ignoreParams: true, + transformData: (data) => data.totalStaked, + }), +); diff --git a/utils/index.ts b/utils/index.ts index f05898ef4..34f4e3ba3 100644 --- a/utils/index.ts +++ b/utils/index.ts @@ -6,7 +6,6 @@ export * from './prependBasePath'; export * from './weiToEth'; export * from './nprogress'; export * from './getErrorMessage'; -export * from './parallelizePromises'; export * from './extractErrorMessage'; export * from './swrAbortableMiddleware'; export * from './getNFTUrl'; diff --git a/utils/parallelizePromises.ts b/utils/parallelizePromises.ts deleted file mode 100644 index 5876325a3..000000000 --- a/utils/parallelizePromises.ts +++ /dev/null @@ -1,11 +0,0 @@ -// eslint-disable-next-line @typescript-eslint/no-explicit-any -export const parallelizePromises = (promises: Array>) => { - return Promise.allSettled(promises).then((settledResults) => - settledResults.map((settled) => { - // TODO: add error handler, think about error in parallel requests - // if (settled.status === 'rejected') throw new Error(settled.reason); - if (settled.status === 'rejected') console.error(settled.reason); - return settled.status === 'fulfilled' && settled.value; - }), - ); -}; diff --git a/utilsApi/apiHelpers.ts b/utilsApi/apiHelpers.ts deleted file mode 100644 index eac47a1b4..000000000 --- a/utilsApi/apiHelpers.ts +++ /dev/null @@ -1,9 +0,0 @@ -export type ParamErrorReason = { [param_key: string]: string }; - -export class ParamError extends Error { - params: ParamErrorReason; - constructor(params: ParamErrorReason, options?: ErrorOptions) { - super('invalid params', options); - this.params = params; - } -} diff --git a/utilsApi/cached-proxy.ts b/utilsApi/cached-proxy.ts new file mode 100644 index 000000000..d1947a8e5 --- /dev/null +++ b/utilsApi/cached-proxy.ts @@ -0,0 +1,97 @@ +import { API } from '@lidofinance/next-api-wrapper'; +import { Cache } from 'memory-cache'; +import { responseTimeExternalMetricWrapper } from './fetchApiWrapper'; +import { standardFetcher } from 'utils/standardFetcher'; +import { secretConfig } from 'config'; +import { FetcherError } from 'utils/fetcherError'; + +type ProxyOptions = { + proxyUrl: string; + cacheTTL: number; + timeout?: number; + ignoreParams?: boolean; + transformData?: (data: any) => any; + metricsHost?: string; +}; + +export const createCachedProxy = ({ + cacheTTL, + proxyUrl, + ignoreParams, + timeout = 5000, + transformData = (data) => data, + metricsHost = proxyUrl, +}: ProxyOptions): API => { + const cache = new Cache(); + return async (req, res) => { + const params = + ignoreParams || Object.keys(req.query).length === 0 + ? null + : new URLSearchParams( + Object.entries(req.query).reduce( + (obj, [k, v]) => { + if (typeof v === 'string') obj[k] = v; + return obj; + }, + {} as Record, + ), + ); + const cacheKey = `${proxyUrl}-${params?.toString() ?? ''}`; + + const cachedValue = cache.get(cacheKey); + if (cachedValue) return cachedValue; + + const url = proxyUrl + (params ? `?${params.toString()}` : ''); + + try { + const data = await responseTimeExternalMetricWrapper({ + payload: metricsHost, + request: () => + standardFetcher(url, { + signal: AbortSignal.timeout(timeout), + headers: { + Accept: 'application/json', + 'Content-Type': 'application/json', + }, + }), + }); + + const transformedData = transformData(data) ?? data; + + cache.put(cacheKey, transformedData, cacheTTL); + + res.status(200).json(transformedData); + } catch (e) { + if (e instanceof FetcherError && e.status >= 400 && e.status < 500) { + console.warn(`[CachedProxy]Forwarding ${e.status} error from ${url}`); + res.status(e.status); + } + console.warn(`[CachedProxy] Failed to proxy from ${url}`, e); + res.status(500); + throw e; + } + }; +}; + +type EthApiProxyOptions = Pick< + ProxyOptions, + 'transformData' | 'ignoreParams' | 'cacheTTL' +> & { + endpoint: string; +}; + +export const createEthApiProxy = ({ + endpoint, + cacheTTL, + ignoreParams, + transformData, +}: EthApiProxyOptions): API => { + return createCachedProxy({ + cacheTTL, + ignoreParams, + transformData, + proxyUrl: `${secretConfig.ethAPIBasePath}${endpoint}`, + metricsHost: secretConfig.ethAPIBasePath, + timeout: 5000, + }); +}; diff --git a/utilsApi/get-one-inch-rate.ts b/utilsApi/get-one-inch-rate.ts deleted file mode 100644 index 21e52889e..000000000 --- a/utilsApi/get-one-inch-rate.ts +++ /dev/null @@ -1,54 +0,0 @@ -import { BigNumber } from 'ethers'; - -import { secretConfig } from 'config'; -import { standardFetcher } from 'utils/standardFetcher'; -import { responseTimeExternalMetricWrapper } from 'utilsApi'; - -const ONE_INCH_API_KEY = secretConfig.oneInchApiKey as string; -const ONE_INCH_API_ENDPOINT = 'https://api.1inch.dev/swap/v5.2/1/quote'; -const RATE_PRECISION = 1000000; - -export type OneInchFetchResponse = { - toAmount: string; -}; - -export type GetOneInchRateResult = { rate: number; toAmount: BigNumber }; - -export type GetOneInchRateStats = ( - fromTokenAddress: string, - toTokenAddress: string, - amount: BigNumber, -) => Promise; - -export const getOneInchRate: GetOneInchRateStats = async ( - fromTokenAddress, - toTokenAddress, - amount, -) => { - console.debug('[getOneInchRate] Started fetching...'); - if (!ONE_INCH_API_KEY) console.warn('[getOneInchRate] missing 1inch Api Key'); - - const query = new URLSearchParams({ - src: fromTokenAddress, - dst: toTokenAddress, - amount: amount.toString(), - }); - const url = `${ONE_INCH_API_ENDPOINT}?${query.toString()}`; - - const respData = await responseTimeExternalMetricWrapper({ - payload: ONE_INCH_API_ENDPOINT, - request: () => - standardFetcher(url, { - headers: { Authorization: `Bearer ${ONE_INCH_API_KEY}` }, - }), - }); - - const toAmount = BigNumber.from(respData.toAmount); - - const rate = - toAmount.mul(BigNumber.from(RATE_PRECISION)).div(amount).toNumber() / - RATE_PRECISION; - - console.debug('[getOneInchRate] Rate on 1inch:', rate); - return { rate, toAmount }; -}; diff --git a/utilsApi/getEthApr.ts b/utilsApi/getEthApr.ts deleted file mode 100644 index 646b07816..000000000 --- a/utilsApi/getEthApr.ts +++ /dev/null @@ -1,97 +0,0 @@ -import { iterateUrls } from '@lidofinance/rpc'; -import { CHAINS } from 'consts/chains'; -import { getStaticRpcBatchProvider } from './rpcProviders'; -import { rpcUrls } from './rpcUrls'; - -export const getEthApr = async (): Promise => { - console.debug('Getting eth apr...'); - const urls = rpcUrls[CHAINS.Mainnet]; - - const totalAtStake = await iterateUrls( - urls, - getTotalAtStakeWithFallbacks, - console.error, - ); - - const ethApr = calculateStakingRewards({ - totalAtStake, - }); - - console.debug('Eth apr: ' + ethApr); - - return (ethApr * 1e11).toFixed(1); -}; - -const getTotalAtStakeWithFallbacks = async (url: string): Promise => { - console.debug('Fetching currently deposited eth2...'); - const eth2DepositContractAddress = - '0x00000000219ab540356cBB839Cbe05303d7705Fa'; - - const chainId = CHAINS.Mainnet; - - const staticProvider = getStaticRpcBatchProvider(chainId, url); - - const currentlyDeposited = await staticProvider.getBalance( - eth2DepositContractAddress, - ); - - console.debug('Currently deposited in eth2:', +currentlyDeposited); - - return Number(currentlyDeposited); -}; - -export interface CalculateStakingRewardsParams { - slotTimeInSec?: number; - slotsInEpoch?: number; - baseRewardFactor?: number; - totalAtStake?: number; // ETH - averageNetworkPctOnline?: number; - vaildatorUptime?: number; - validatorDeposit?: number; // ETH - effectiveBalanceIncrement?: number; // gwei - weightDenominator?: number; - proposerWeight?: number; -} - -const calculateStakingRewards = ({ - slotTimeInSec = 12, - slotsInEpoch = 32, - baseRewardFactor = 64, - totalAtStake = 1_000_000, // ETH - averageNetworkPctOnline = 0.95, - vaildatorUptime = 0.99, - validatorDeposit = 32, // ETH - effectiveBalanceIncrement = 1_000_000_000, // gwei - weightDenominator = 64, - proposerWeight = 8, -}: CalculateStakingRewardsParams): number => { - // Calculate number of epochs per year - const avgSecInYear = 31556908.8; // 60 * 60 * 24 * 365.242 - const epochPerYear = avgSecInYear / (slotTimeInSec * slotsInEpoch); - const baseRewardPerIncrement = - (effectiveBalanceIncrement * baseRewardFactor) / - (totalAtStake * 10e8) ** 0.5; - - // Calculate base reward for full validator (in gwei) - const baseGweiRewardFullValidator = - ((validatorDeposit * 10e8) / effectiveBalanceIncrement) * - baseRewardPerIncrement; - - // Calculate offline per-validator penalty per epoch (in gwei) - // Note: Inactivity penalty is not included in this simple calculation - const offlineEpochGweiPentalty = - baseGweiRewardFullValidator * - ((weightDenominator - proposerWeight) / weightDenominator); - - // Calculate online per-validator reward per epoch (in gwei) - const onlineEpochGweiReward = - baseGweiRewardFullValidator * averageNetworkPctOnline; - - // Calculate net yearly staking reward (in gwei) - const reward = onlineEpochGweiReward * vaildatorUptime; - const penalty = offlineEpochGweiPentalty * (1 - vaildatorUptime); - const netRewardPerYear = epochPerYear * (reward - penalty); - - // Return net yearly staking reward percentage - return netRewardPerYear / 10e8 / validatorDeposit; -}; diff --git a/utilsApi/getEthPrice.ts b/utilsApi/getEthPrice.ts deleted file mode 100644 index ce47bc025..000000000 --- a/utilsApi/getEthPrice.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { iterateUrls } from '@lidofinance/rpc'; -import { getAggregatorContract } from '@lido-sdk/contracts'; -import { CHAINS, getAggregatorAddress } from '@lido-sdk/constants'; - -import { getStaticRpcBatchProvider } from './rpcProviders'; -import { rpcUrls } from './rpcUrls'; - -export const getEthPrice = async (): Promise => { - const urls = rpcUrls[CHAINS.Mainnet]; - return iterateUrls(urls, (url) => getEthPriceWithFallbacks(url)); -}; - -const getEthPriceWithFallbacks = async (url: string): Promise => { - const address = getAggregatorAddress(CHAINS.Mainnet); - const chainId = CHAINS.Mainnet; - const staticProvider = getStaticRpcBatchProvider(chainId, url); - - const contract = getAggregatorContract(address, staticProvider); - - // TODO: maybe without Promise.all - const [decimals, latestAnswer] = await Promise.all([ - contract.decimals(), - contract.latestAnswer(), - ]); - - return latestAnswer.toNumber() / 10 ** decimals; -}; diff --git a/utilsApi/getLidoHoldersViaSubgraphs.ts b/utilsApi/getLidoHoldersViaSubgraphs.ts deleted file mode 100644 index 8c122a7dc..000000000 --- a/utilsApi/getLidoHoldersViaSubgraphs.ts +++ /dev/null @@ -1,92 +0,0 @@ -import ms from 'ms'; -import { Cache } from 'memory-cache'; - -import { config, secretConfig } from 'config'; -import { SubgraphChains } from 'types'; -import Metrics from 'utilsApi/metrics'; -import { standardFetcher } from 'utils/standardFetcher'; - -import { getSubgraphUrl } from './getSubgraphUrl'; - -const SUBGRAPH_ERROR_MESSAGE = - '[getLidoHoldersViaSubgraphs] Subgraph request failed.'; - -interface LidoHolders extends Response { - data: { - stats: { - uniqueAnytimeHolders: string; - uniqueHolders: string; - }; - }; -} - -const cache = new Cache(); - -type GetLidoHoldersViaSubgraphs = ( - chainId: SubgraphChains, -) => Promise; - -export const getLidoHoldersViaSubgraphs: GetLidoHoldersViaSubgraphs = async ( - chainId: SubgraphChains, -) => { - const cacheKey = `${config.CACHE_LIDO_HOLDERS_VIA_SUBGRAPHS_KEY}_${chainId}`; - - console.debug('[getLidoHoldersViaSubgraphs] Started fetching... '); - const query = ` - query { - stats (id: "") { - uniqueHolders - uniqueAnytimeHolders - } - } - `; - - const controller = new AbortController(); - - const TIMEOUT = +secretConfig.subgraphRequestTimeout || ms('5s'); - const timeoutId = setTimeout(() => controller.abort(), TIMEOUT); - - const params = { - method: 'POST', - body: JSON.stringify({ query }), - signal: controller.signal, - }; - - const endMetric = Metrics.subgraph.subgraphsResponseTime.startTimer(); - - const url = getSubgraphUrl(chainId); - - if (!url) { - throw new Error(`Error: subgraph chain is not supported ${chainId}`); - } - - try { - const responseJsoned = await standardFetcher(url, params); - - endMetric(); - clearTimeout(timeoutId); - - console.debug('[getLidoHoldersViaSubgraphs] Lido holders:', responseJsoned); - - cache.put( - cacheKey, - responseJsoned, - config.CACHE_LIDO_HOLDERS_VIA_SUBGRAPHS_TTL, - ); - - return responseJsoned; - } catch (error) { - const data = cache.get(cacheKey); - - if (data) { - console.error(`${SUBGRAPH_ERROR_MESSAGE} Using long-term cache...`); - return data; - } - - if (error instanceof Error) { - throw new Error(error.message ?? SUBGRAPH_ERROR_MESSAGE); - } else { - throw new Error(SUBGRAPH_ERROR_MESSAGE); - } - } -}; diff --git a/utilsApi/getSmaStethApr.ts b/utilsApi/getSmaStethApr.ts deleted file mode 100644 index f7236803b..000000000 --- a/utilsApi/getSmaStethApr.ts +++ /dev/null @@ -1,60 +0,0 @@ -import { secretConfig } from 'config'; -import { CHAINS } from 'consts/chains'; - -import { standardFetcher } from 'utils/standardFetcher'; -import { responseTimeExternalMetricWrapper } from 'utilsApi'; - -type SMA_APR_RESPONSE = { - data: { - aprs: [ - { - timeUnix: number; - apr: number; - }, - { - timeUnix: number; - apr: number; - }, - { - timeUnix: number; - apr: number; - }, - { - timeUnix: number; - apr: number; - }, - { - timeUnix: number; - apr: number; - }, - { - timeUnix: number; - apr: number; - }, - { - timeUnix: number; - apr: number; - }, - { - timeUnix: number; - apr: number; - }, - ]; - smaApr: number; - }; - meta: { - symbol: 'stETH'; - address: string; - chainId: CHAINS; - }; -}; - -export const getSmaStethApr = async (): Promise => { - const url = `${secretConfig.ethAPIBasePath}/v1/protocol/steth/apr/sma`; - const data = await responseTimeExternalMetricWrapper({ - payload: secretConfig.ethAPIBasePath, - request: () => standardFetcher(url), - }); - - return data?.data.smaApr.toFixed(1); -}; diff --git a/utilsApi/getStEthPrice.ts b/utilsApi/getStEthPrice.ts deleted file mode 100644 index 3963f10e1..000000000 --- a/utilsApi/getStEthPrice.ts +++ /dev/null @@ -1,31 +0,0 @@ -import { iterateUrls } from '@lidofinance/rpc'; -import { CHAINS } from '@lido-sdk/constants'; -import { getAggregatorContract } from '@lido-sdk/contracts'; - -import { getAggregatorStEthUsdPriceFeedAddress } from 'consts/aggregator'; - -import { getStaticRpcBatchProvider } from './rpcProviders'; -import { rpcUrls } from './rpcUrls'; - -export const getStEthPrice = async (): Promise => { - const urls = rpcUrls[CHAINS.Mainnet]; - return iterateUrls( - urls, - (url) => getStEthPriceWithFallbacks(url), - console.error, - ); -}; - -const getStEthPriceWithFallbacks = async (url: string): Promise => { - const address = getAggregatorStEthUsdPriceFeedAddress(CHAINS.Mainnet); - const staticProvider = getStaticRpcBatchProvider(CHAINS.Mainnet, url); - - const contract = getAggregatorContract(address, staticProvider); - - const [decimals, latestAnswer] = await Promise.all([ - contract.decimals(), - contract.latestAnswer(), - ]); - - return latestAnswer.toNumber() / 10 ** decimals; -}; diff --git a/utilsApi/getSubgraphUrl.ts b/utilsApi/getSubgraphUrl.ts deleted file mode 100644 index e9d00dcaf..000000000 --- a/utilsApi/getSubgraphUrl.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { secretConfig } from 'config'; -import { CHAINS } from 'consts/chains'; -import { SubgraphChains } from 'types'; - -export const SUBGRAPH_URL = { - [CHAINS.Mainnet]: secretConfig.subgraphMainnet, - [CHAINS.Goerli]: secretConfig.subgraphGoerli, - [CHAINS.Holesky]: secretConfig.subgraphHolesky, -} as const; - -export const getSubgraphUrl = (chainId: SubgraphChains): string | undefined => { - return SUBGRAPH_URL[chainId]; -}; diff --git a/utilsApi/getTotalStaked.ts b/utilsApi/getTotalStaked.ts deleted file mode 100644 index b924a9982..000000000 --- a/utilsApi/getTotalStaked.ts +++ /dev/null @@ -1,41 +0,0 @@ -import { formatEther } from '@ethersproject/units'; -import { StethAbiFactory } from '@lido-sdk/contracts'; -import { getTokenAddress, TOKENS } from '@lido-sdk/constants'; - -import { HEALTHY_RPC_SERVICES_ARE_OVER } from 'consts/api'; -import { CHAINS } from 'consts/chains'; - -import { getStaticRpcBatchProvider } from './rpcProviders'; -import { rpcUrls } from './rpcUrls'; - -export const getTotalStaked = async ( - chainId = CHAINS.Mainnet, -): Promise => { - const urls = rpcUrls[chainId]; - return getTotalStakedWithFallbacks(urls, 0, chainId); -}; - -const getTotalStakedWithFallbacks = async ( - urls: Array, - urlIndex: number, - chainId = CHAINS.Mainnet, -): Promise => { - try { - const staticProvider = getStaticRpcBatchProvider(chainId, urls[urlIndex]); - - const stethAddress = getTokenAddress(chainId as number, TOKENS.STETH); - const stethContract = StethAbiFactory.connect(stethAddress, staticProvider); - - const totalSupplyStWei = await stethContract.totalSupply(); - - const totalSupplyStEth = formatEther(totalSupplyStWei); - return Number(totalSupplyStEth).toFixed(8); - } catch (error) { - if (urlIndex >= urls.length - 1) { - const error = `[getTotalStaked] ${HEALTHY_RPC_SERVICES_ARE_OVER}`; - console.error(error); - throw new Error(error); - } - return await getTotalStakedWithFallbacks(urls, urlIndex + 1, chainId); - } -}; diff --git a/utilsApi/index.ts b/utilsApi/index.ts index 9f0b0595f..837b1e119 100644 --- a/utilsApi/index.ts +++ b/utilsApi/index.ts @@ -1,15 +1,7 @@ export * from './fetchRPC'; -export * from './getEthApr'; -export * from './getStEthPrice'; -export * from './getTotalStaked'; -export * from './getLidoHoldersViaSubgraphs'; export * from './getLdoStats'; export * from './getLidoStats'; -export * from './get-one-inch-rate'; -export * from './getEthPrice'; -export * from './getSubgraphUrl'; export * from './rpcProviders'; export * from './rpcUrls'; export * from './nextApiWrappers'; export * from './fetchApiWrapper'; -export * from './getSmaStethApr'; diff --git a/utilsApi/nextApiWrappers.ts b/utilsApi/nextApiWrappers.ts index e4987dbb7..badd7f6ec 100644 --- a/utilsApi/nextApiWrappers.ts +++ b/utilsApi/nextApiWrappers.ts @@ -210,7 +210,7 @@ type sunsetByArgs = { export const sunsetBy = ({ replacementLink, sunsetTimestamp }: sunsetByArgs): RequestWrapper => async (req, res, next) => { - console.warn('Request to deprecated endpoint:', req.url); + console.warn(`Request to deprecated endpoint: ${req.url}`); const shouldDisable = Date.now() > sunsetTimestamp; if (shouldDisable) { From b424cda0b0d5cf562b6bd37765ac0134928141d4 Mon Sep 17 00:00:00 2001 From: Evgeny Taktarov Date: Wed, 3 Jul 2024 17:58:31 +0700 Subject: [PATCH 06/61] chore: clean up --- abi/steth.abi.json | 726 -------------------------- config/groups/cache.ts | 17 +- features/rewards/fetchers/rpcFetch.ts | 20 - pages/api/rpc.ts | 17 +- test/consts.ts | 11 +- types/hooks.ts | 1 - types/index.ts | 1 - types/subgraph.ts | 3 - utilsApi/cached-proxy.ts | 5 +- utilsApi/fetchRPC.ts | 8 - utilsApi/index.ts | 3 - utilsApi/rpcProviders.ts | 16 - utilsApi/rpcUrls.ts | 8 - 13 files changed, 24 insertions(+), 812 deletions(-) delete mode 100644 abi/steth.abi.json delete mode 100644 types/hooks.ts delete mode 100644 types/subgraph.ts delete mode 100644 utilsApi/fetchRPC.ts delete mode 100644 utilsApi/rpcProviders.ts delete mode 100644 utilsApi/rpcUrls.ts diff --git a/abi/steth.abi.json b/abi/steth.abi.json deleted file mode 100644 index 292a45375..000000000 --- a/abi/steth.abi.json +++ /dev/null @@ -1,726 +0,0 @@ -[ - { - "constant": false, - "inputs": [], - "name": "resume", - "outputs": [], - "payable": false, - "stateMutability": "nonpayable", - "type": "function" - }, - { - "constant": true, - "inputs": [], - "name": "name", - "outputs": [{ "name": "", "type": "string" }], - "payable": false, - "stateMutability": "pure", - "type": "function" - }, - { - "constant": false, - "inputs": [], - "name": "stop", - "outputs": [], - "payable": false, - "stateMutability": "nonpayable", - "type": "function" - }, - { - "constant": true, - "inputs": [], - "name": "hasInitialized", - "outputs": [{ "name": "", "type": "bool" }], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { - "constant": false, - "inputs": [ - { "name": "_spender", "type": "address" }, - { "name": "_amount", "type": "uint256" } - ], - "name": "approve", - "outputs": [{ "name": "", "type": "bool" }], - "payable": false, - "stateMutability": "nonpayable", - "type": "function" - }, - { - "constant": false, - "inputs": [ - { "name": "depositContract", "type": "address" }, - { "name": "_oracle", "type": "address" }, - { "name": "_operators", "type": "address" }, - { "name": "_treasury", "type": "address" }, - { "name": "_insuranceFund", "type": "address" } - ], - "name": "initialize", - "outputs": [], - "payable": false, - "stateMutability": "nonpayable", - "type": "function" - }, - { - "constant": true, - "inputs": [], - "name": "getInsuranceFund", - "outputs": [{ "name": "", "type": "address" }], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { - "constant": true, - "inputs": [], - "name": "totalSupply", - "outputs": [{ "name": "", "type": "uint256" }], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { - "constant": true, - "inputs": [{ "name": "_ethAmount", "type": "uint256" }], - "name": "getSharesByPooledEth", - "outputs": [{ "name": "", "type": "uint256" }], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { - "constant": false, - "inputs": [ - { "name": "_sender", "type": "address" }, - { "name": "_recipient", "type": "address" }, - { "name": "_amount", "type": "uint256" } - ], - "name": "transferFrom", - "outputs": [{ "name": "", "type": "bool" }], - "payable": false, - "stateMutability": "nonpayable", - "type": "function" - }, - { - "constant": true, - "inputs": [], - "name": "getOperators", - "outputs": [{ "name": "", "type": "address" }], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { - "constant": true, - "inputs": [{ "name": "_script", "type": "bytes" }], - "name": "getEVMScriptExecutor", - "outputs": [{ "name": "", "type": "address" }], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { - "constant": true, - "inputs": [], - "name": "decimals", - "outputs": [{ "name": "", "type": "uint8" }], - "payable": false, - "stateMutability": "pure", - "type": "function" - }, - { - "constant": true, - "inputs": [], - "name": "getRecoveryVault", - "outputs": [{ "name": "", "type": "address" }], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { - "constant": true, - "inputs": [], - "name": "DEPOSIT_SIZE", - "outputs": [{ "name": "", "type": "uint256" }], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { - "constant": true, - "inputs": [], - "name": "getTotalPooledEther", - "outputs": [{ "name": "", "type": "uint256" }], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { - "constant": true, - "inputs": [], - "name": "PAUSE_ROLE", - "outputs": [{ "name": "", "type": "bytes32" }], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { - "constant": false, - "inputs": [ - { "name": "_spender", "type": "address" }, - { "name": "_addedValue", "type": "uint256" } - ], - "name": "increaseAllowance", - "outputs": [{ "name": "", "type": "bool" }], - "payable": false, - "stateMutability": "nonpayable", - "type": "function" - }, - { - "constant": true, - "inputs": [], - "name": "getTreasury", - "outputs": [{ "name": "", "type": "address" }], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { - "constant": true, - "inputs": [], - "name": "SET_ORACLE", - "outputs": [{ "name": "", "type": "bytes32" }], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { - "constant": true, - "inputs": [], - "name": "isStopped", - "outputs": [{ "name": "", "type": "bool" }], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { - "constant": true, - "inputs": [], - "name": "MANAGE_WITHDRAWAL_KEY", - "outputs": [{ "name": "", "type": "bytes32" }], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { - "constant": true, - "inputs": [], - "name": "getBufferedEther", - "outputs": [{ "name": "", "type": "uint256" }], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { - "constant": true, - "inputs": [], - "name": "SIGNATURE_LENGTH", - "outputs": [{ "name": "", "type": "uint256" }], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { - "constant": true, - "inputs": [], - "name": "getWithdrawalCredentials", - "outputs": [{ "name": "", "type": "bytes32" }], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { - "constant": true, - "inputs": [{ "name": "_account", "type": "address" }], - "name": "balanceOf", - "outputs": [{ "name": "", "type": "uint256" }], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { - "constant": true, - "inputs": [], - "name": "getFeeDistribution", - "outputs": [ - { "name": "treasuryFeeBasisPoints", "type": "uint16" }, - { "name": "insuranceFeeBasisPoints", "type": "uint16" }, - { "name": "operatorsFeeBasisPoints", "type": "uint16" } - ], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { - "constant": true, - "inputs": [{ "name": "_sharesAmount", "type": "uint256" }], - "name": "getPooledEthByShares", - "outputs": [{ "name": "", "type": "uint256" }], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { - "constant": false, - "inputs": [{ "name": "_oracle", "type": "address" }], - "name": "setOracle", - "outputs": [], - "payable": false, - "stateMutability": "nonpayable", - "type": "function" - }, - { - "constant": true, - "inputs": [{ "name": "token", "type": "address" }], - "name": "allowRecoverability", - "outputs": [{ "name": "", "type": "bool" }], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { - "constant": true, - "inputs": [], - "name": "appId", - "outputs": [{ "name": "", "type": "bytes32" }], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { - "constant": true, - "inputs": [], - "name": "getOracle", - "outputs": [{ "name": "", "type": "address" }], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { - "constant": true, - "inputs": [], - "name": "getInitializationBlock", - "outputs": [{ "name": "", "type": "uint256" }], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { - "constant": false, - "inputs": [ - { "name": "_treasuryFeeBasisPoints", "type": "uint16" }, - { "name": "_insuranceFeeBasisPoints", "type": "uint16" }, - { "name": "_operatorsFeeBasisPoints", "type": "uint16" } - ], - "name": "setFeeDistribution", - "outputs": [], - "payable": false, - "stateMutability": "nonpayable", - "type": "function" - }, - { - "constant": false, - "inputs": [{ "name": "_feeBasisPoints", "type": "uint16" }], - "name": "setFee", - "outputs": [], - "payable": false, - "stateMutability": "nonpayable", - "type": "function" - }, - { - "constant": false, - "inputs": [{ "name": "_maxDeposits", "type": "uint256" }], - "name": "depositBufferedEther", - "outputs": [], - "payable": false, - "stateMutability": "nonpayable", - "type": "function" - }, - { - "constant": true, - "inputs": [], - "name": "symbol", - "outputs": [{ "name": "", "type": "string" }], - "payable": false, - "stateMutability": "pure", - "type": "function" - }, - { - "constant": true, - "inputs": [], - "name": "MANAGE_FEE", - "outputs": [{ "name": "", "type": "bytes32" }], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { - "constant": false, - "inputs": [{ "name": "_token", "type": "address" }], - "name": "transferToVault", - "outputs": [], - "payable": false, - "stateMutability": "nonpayable", - "type": "function" - }, - { - "constant": true, - "inputs": [], - "name": "SET_TREASURY", - "outputs": [{ "name": "", "type": "bytes32" }], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { - "constant": true, - "inputs": [ - { "name": "_sender", "type": "address" }, - { "name": "_role", "type": "bytes32" }, - { "name": "_params", "type": "uint256[]" } - ], - "name": "canPerform", - "outputs": [{ "name": "", "type": "bool" }], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { - "constant": false, - "inputs": [{ "name": "_referral", "type": "address" }], - "name": "submit", - "outputs": [{ "name": "", "type": "uint256" }], - "payable": true, - "stateMutability": "payable", - "type": "function" - }, - { - "constant": true, - "inputs": [], - "name": "WITHDRAWAL_CREDENTIALS_LENGTH", - "outputs": [{ "name": "", "type": "uint256" }], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { - "constant": false, - "inputs": [ - { "name": "_spender", "type": "address" }, - { "name": "_subtractedValue", "type": "uint256" } - ], - "name": "decreaseAllowance", - "outputs": [{ "name": "", "type": "bool" }], - "payable": false, - "stateMutability": "nonpayable", - "type": "function" - }, - { - "constant": true, - "inputs": [], - "name": "getEVMScriptRegistry", - "outputs": [{ "name": "", "type": "address" }], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { - "constant": true, - "inputs": [], - "name": "PUBKEY_LENGTH", - "outputs": [{ "name": "", "type": "uint256" }], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { - "constant": false, - "inputs": [ - { "name": "_amount", "type": "uint256" }, - { "name": "_pubkeyHash", "type": "bytes32" } - ], - "name": "withdraw", - "outputs": [], - "payable": false, - "stateMutability": "nonpayable", - "type": "function" - }, - { - "constant": false, - "inputs": [ - { "name": "_recipient", "type": "address" }, - { "name": "_amount", "type": "uint256" } - ], - "name": "transfer", - "outputs": [{ "name": "", "type": "bool" }], - "payable": false, - "stateMutability": "nonpayable", - "type": "function" - }, - { - "constant": true, - "inputs": [], - "name": "getDepositContract", - "outputs": [{ "name": "", "type": "address" }], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { - "constant": true, - "inputs": [], - "name": "getBeaconStat", - "outputs": [ - { "name": "depositedValidators", "type": "uint256" }, - { "name": "beaconValidators", "type": "uint256" }, - { "name": "beaconBalance", "type": "uint256" } - ], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { - "constant": true, - "inputs": [], - "name": "BURN_ROLE", - "outputs": [{ "name": "", "type": "bytes32" }], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { - "constant": false, - "inputs": [{ "name": "_insuranceFund", "type": "address" }], - "name": "setInsuranceFund", - "outputs": [], - "payable": false, - "stateMutability": "nonpayable", - "type": "function" - }, - { - "constant": true, - "inputs": [], - "name": "getFee", - "outputs": [{ "name": "feeBasisPoints", "type": "uint16" }], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { - "constant": true, - "inputs": [], - "name": "SET_INSURANCE_FUND", - "outputs": [{ "name": "", "type": "bytes32" }], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { - "constant": true, - "inputs": [], - "name": "kernel", - "outputs": [{ "name": "", "type": "address" }], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { - "constant": true, - "inputs": [], - "name": "getTotalShares", - "outputs": [{ "name": "", "type": "uint256" }], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { - "constant": true, - "inputs": [ - { "name": "_owner", "type": "address" }, - { "name": "_spender", "type": "address" } - ], - "name": "allowance", - "outputs": [{ "name": "", "type": "uint256" }], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { - "constant": true, - "inputs": [], - "name": "isPetrified", - "outputs": [{ "name": "", "type": "bool" }], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { - "constant": false, - "inputs": [{ "name": "_withdrawalCredentials", "type": "bytes32" }], - "name": "setWithdrawalCredentials", - "outputs": [], - "payable": false, - "stateMutability": "nonpayable", - "type": "function" - }, - { - "constant": false, - "inputs": [], - "name": "depositBufferedEther", - "outputs": [], - "payable": false, - "stateMutability": "nonpayable", - "type": "function" - }, - { - "constant": false, - "inputs": [ - { "name": "_account", "type": "address" }, - { "name": "_sharesAmount", "type": "uint256" } - ], - "name": "burnShares", - "outputs": [{ "name": "newTotalShares", "type": "uint256" }], - "payable": false, - "stateMutability": "nonpayable", - "type": "function" - }, - { - "constant": false, - "inputs": [{ "name": "_treasury", "type": "address" }], - "name": "setTreasury", - "outputs": [], - "payable": false, - "stateMutability": "nonpayable", - "type": "function" - }, - { - "constant": false, - "inputs": [ - { "name": "_beaconValidators", "type": "uint256" }, - { "name": "_beaconBalance", "type": "uint256" } - ], - "name": "pushBeacon", - "outputs": [], - "payable": false, - "stateMutability": "nonpayable", - "type": "function" - }, - { - "constant": true, - "inputs": [{ "name": "_account", "type": "address" }], - "name": "sharesOf", - "outputs": [{ "name": "", "type": "uint256" }], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { "payable": true, "stateMutability": "payable", "type": "fallback" }, - { - "anonymous": false, - "inputs": [ - { "indexed": true, "name": "executor", "type": "address" }, - { "indexed": false, "name": "script", "type": "bytes" }, - { "indexed": false, "name": "input", "type": "bytes" }, - { "indexed": false, "name": "returnData", "type": "bytes" } - ], - "name": "ScriptResult", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { "indexed": true, "name": "vault", "type": "address" }, - { "indexed": true, "name": "token", "type": "address" }, - { "indexed": false, "name": "amount", "type": "uint256" } - ], - "name": "RecoverToVault", - "type": "event" - }, - { "anonymous": false, "inputs": [], "name": "Stopped", "type": "event" }, - { "anonymous": false, "inputs": [], "name": "Resumed", "type": "event" }, - { - "anonymous": false, - "inputs": [ - { "indexed": true, "name": "from", "type": "address" }, - { "indexed": true, "name": "to", "type": "address" }, - { "indexed": false, "name": "value", "type": "uint256" } - ], - "name": "Transfer", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { "indexed": true, "name": "owner", "type": "address" }, - { "indexed": true, "name": "spender", "type": "address" }, - { "indexed": false, "name": "value", "type": "uint256" } - ], - "name": "Approval", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { "indexed": false, "name": "feeBasisPoints", "type": "uint16" } - ], - "name": "FeeSet", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { "indexed": false, "name": "treasuryFeeBasisPoints", "type": "uint16" }, - { "indexed": false, "name": "insuranceFeeBasisPoints", "type": "uint16" }, - { "indexed": false, "name": "operatorsFeeBasisPoints", "type": "uint16" } - ], - "name": "FeeDistributionSet", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { "indexed": false, "name": "withdrawalCredentials", "type": "bytes32" } - ], - "name": "WithdrawalCredentialsSet", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { "indexed": true, "name": "sender", "type": "address" }, - { "indexed": false, "name": "amount", "type": "uint256" }, - { "indexed": false, "name": "referral", "type": "address" } - ], - "name": "Submitted", - "type": "event" - }, - { - "anonymous": false, - "inputs": [{ "indexed": false, "name": "amount", "type": "uint256" }], - "name": "Unbuffered", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { "indexed": true, "name": "sender", "type": "address" }, - { "indexed": false, "name": "tokenAmount", "type": "uint256" }, - { "indexed": false, "name": "sentFromBuffer", "type": "uint256" }, - { "indexed": true, "name": "pubkeyHash", "type": "bytes32" }, - { "indexed": false, "name": "etherAmount", "type": "uint256" } - ], - "name": "Withdrawal", - "type": "event" - } -] diff --git a/config/groups/cache.ts b/config/groups/cache.ts index 9d0a050e5..ffdfbe42b 100644 --- a/config/groups/cache.ts +++ b/config/groups/cache.ts @@ -1,29 +1,16 @@ import ms from 'ms'; -export const CACHE_STETH_APR_KEY = 'cache-steth-apr'; export const CACHE_STETH_APR_TTL = ms('1h'); - -export const CACHE_SMA_STETH_APR_KEY = 'cache-sma-steth-apr'; export const CACHE_SMA_STETH_APR_TTL = ms('30m'); - -export const CACHE_ETH_APR_KEY = 'cache-eth-apr'; export const CACHE_ETH_APR_TTL = ms('1h'); export const CACHE_LIDO_STATS_KEY = 'cache-lido-stats'; export const CACHE_LIDO_STATS_TTL = ms('1h'); - -export const CACHE_LIDO_SHORT_STATS_KEY = 'cache-short-lido-stats'; export const CACHE_LIDO_SHORT_STATS_TTL = ms('1h'); - -export const CACHE_LIDO_HOLDERS_VIA_SUBGRAPHS_KEY = - 'cache-lido-holders-via-subgraphs'; -export const CACHE_LIDO_HOLDERS_VIA_SUBGRAPHS_TTL = ms('7d'); - -export const CACHE_LDO_STATS_KEY = 'cache-ldo-stats'; export const CACHE_LDO_STATS_TTL = ms('1h'); - -export const CACHE_ETH_PRICE_KEY = 'cache-eth-price'; +export const CACHE_LDO_STATS_KEY = 'cache-ldo-stats'; export const CACHE_ETH_PRICE_TTL = ms('1m'); + export const CACHE_ETH_PRICE_HEADERS = 'public, max-age=60, stale-if-error=1200, stale-while-revalidate=30'; diff --git a/features/rewards/fetchers/rpcFetch.ts b/features/rewards/fetchers/rpcFetch.ts index 716a67ed7..ccf007dde 100644 --- a/features/rewards/fetchers/rpcFetch.ts +++ b/features/rewards/fetchers/rpcFetch.ts @@ -5,8 +5,6 @@ import get from 'lodash/get'; import { StaticJsonRpcBatchProvider } from '@lidofinance/eth-providers'; import { CHAINS } from '@lido-sdk/constants'; -import STETH_ABI from 'abi/steth.abi.json'; - const CURVE_ABI = [ { name: 'get_dy', @@ -39,32 +37,14 @@ export const TOKENS_BY_CHAIN_ID = { export const TOKEN_ADDRESS_BY_CHAIN_ID = { [CHAINS.Mainnet]: { - [TOKENS.STETH]: '0xae7ab96520de3a18e5e111b5eaab095312d7fe84', [TOKENS.CURVE]: '0xDC24316b9AE028F1497c275EB9192a3Ea0f67022', }, - [CHAINS.Ropsten]: {}, - [CHAINS.Rinkeby]: { - [TOKENS.STETH]: '0xbA453033d328bFdd7799a4643611b616D80ddd97', - }, - [CHAINS.Goerli]: { - [TOKENS.STETH]: '0x1643e812ae58766192cf7d2cf9567df2c37e9b7f', - }, - [CHAINS.Kovan]: {}, } as const; export const TOKEN_ABI_BY_CHAIN_ID = { [CHAINS.Mainnet]: { - [TOKENS.STETH]: STETH_ABI, [TOKENS.CURVE]: CURVE_ABI, }, - [CHAINS.Ropsten]: {}, - [CHAINS.Rinkeby]: { - [TOKENS.STETH]: STETH_ABI, - }, - [CHAINS.Goerli]: { - [TOKENS.STETH]: STETH_ABI, - }, - [CHAINS.Kovan]: {}, } as const; export const getTokenAddress = ( diff --git a/pages/api/rpc.ts b/pages/api/rpc.ts index a23c8950c..a8f0455fd 100644 --- a/pages/api/rpc.ts +++ b/pages/api/rpc.ts @@ -1,11 +1,12 @@ import { rpcFactory } from '@lidofinance/next-pages'; +import { CHAINS } from '@lido-sdk/constants'; import { wrapRequest as wrapNextRequest } from '@lidofinance/next-api-wrapper'; +import { trackedFetchRpcFactory } from '@lidofinance/api-rpc'; -import { config } from 'config'; +import { config, secretConfig } from 'config'; import { API_ROUTES } from 'consts/api'; import { METRICS_PREFIX } from 'consts/metrics'; import { - fetchRPC, rateLimit, responseTimeMetric, defaultErrorHandler, @@ -14,10 +15,12 @@ import { HttpMethod, } from 'utilsApi'; import Metrics from 'utilsApi/metrics'; -import { rpcUrls } from 'utilsApi/rpcUrls'; const rpc = rpcFactory({ - fetchRPC, + fetchRPC: trackedFetchRpcFactory({ + registry: Metrics.registry, + prefix: METRICS_PREFIX, + }), serverLogger: console, metrics: { prefix: METRICS_PREFIX, @@ -42,7 +45,11 @@ const rpc = rpcFactory({ 'net_version', ], defaultChain: `${config.defaultChain}`, - providers: rpcUrls, + providers: { + [CHAINS.Mainnet]: secretConfig.rpcUrls_1, + [CHAINS.Goerli]: secretConfig.rpcUrls_5, + [CHAINS.Holesky]: secretConfig.rpcUrls_17000, + }, }); export default wrapNextRequest([ diff --git a/test/consts.ts b/test/consts.ts index 295fc7eaa..fa9024e3d 100644 --- a/test/consts.ts +++ b/test/consts.ts @@ -165,19 +165,22 @@ const LIDO_STATS_SCHEMA = { export const GET_REQUESTS: GetRequest[] = [ { - uri: '/api/oneinch-rate', + uri: '/api/oneinch-rate?token=ETH', + isDeprecated: true, schema: { type: 'object', properties: { rate: { type: 'number', min: 0 }, toReceive: { type: 'string' }, + fromAmount: { type: 'string' }, }, - required: ['rate', 'toReceive'], + required: ['rate', 'toReceive', 'fromAmount'], additionalProperties: false, }, }, { uri: `/api/short-lido-stats?chainId=${CONFIG.STAND_CONFIG.chainId}`, + isDeprecated: true, schema: { type: 'object', properties: { @@ -192,7 +195,7 @@ export const GET_REQUESTS: GetRequest[] = [ 'uniqueAnytimeHolders', 'uniqueHolders', ], - additionalProperties: false, + additionalProperties: true, }, }, { @@ -202,6 +205,7 @@ export const GET_REQUESTS: GetRequest[] = [ }, { uri: '/api/totalsupply', + isDeprecated: true, schema: { type: 'string', pattern: FLOAT_REGEX }, }, { @@ -216,6 +220,7 @@ export const GET_REQUESTS: GetRequest[] = [ }, { uri: '/api/eth-price', + isDeprecated: true, schema: { type: 'object', properties: { diff --git a/types/hooks.ts b/types/hooks.ts deleted file mode 100644 index cb0ff5c3b..000000000 --- a/types/hooks.ts +++ /dev/null @@ -1 +0,0 @@ -export {}; diff --git a/types/index.ts b/types/index.ts index e921cf979..01c00f203 100644 --- a/types/index.ts +++ b/types/index.ts @@ -1,4 +1,3 @@ export * from './components'; export * from './api'; -export * from './subgraph'; export * from './limit'; diff --git a/types/subgraph.ts b/types/subgraph.ts deleted file mode 100644 index 2aed7a1c9..000000000 --- a/types/subgraph.ts +++ /dev/null @@ -1,3 +0,0 @@ -import { CHAINS } from 'consts/chains'; - -export type SubgraphChains = CHAINS; diff --git a/utilsApi/cached-proxy.ts b/utilsApi/cached-proxy.ts index d1947a8e5..9fba2f0b2 100644 --- a/utilsApi/cached-proxy.ts +++ b/utilsApi/cached-proxy.ts @@ -59,15 +59,14 @@ export const createCachedProxy = ({ const transformedData = transformData(data) ?? data; cache.put(cacheKey, transformedData, cacheTTL); - - res.status(200).json(transformedData); + res.json(transformedData); } catch (e) { if (e instanceof FetcherError && e.status >= 400 && e.status < 500) { console.warn(`[CachedProxy]Forwarding ${e.status} error from ${url}`); res.status(e.status); } console.warn(`[CachedProxy] Failed to proxy from ${url}`, e); - res.status(500); + res.status(500).end(); throw e; } }; diff --git a/utilsApi/fetchRPC.ts b/utilsApi/fetchRPC.ts deleted file mode 100644 index 152a16e19..000000000 --- a/utilsApi/fetchRPC.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { trackedFetchRpcFactory } from '@lidofinance/api-rpc'; -import { METRICS_PREFIX } from 'consts/metrics'; -import Metrics from 'utilsApi/metrics'; - -export const fetchRPC = trackedFetchRpcFactory({ - registry: Metrics.registry, - prefix: METRICS_PREFIX, -}); diff --git a/utilsApi/index.ts b/utilsApi/index.ts index 837b1e119..de210ed39 100644 --- a/utilsApi/index.ts +++ b/utilsApi/index.ts @@ -1,7 +1,4 @@ -export * from './fetchRPC'; export * from './getLdoStats'; export * from './getLidoStats'; -export * from './rpcProviders'; -export * from './rpcUrls'; export * from './nextApiWrappers'; export * from './fetchApiWrapper'; diff --git a/utilsApi/rpcProviders.ts b/utilsApi/rpcProviders.ts deleted file mode 100644 index b72fc57ad..000000000 --- a/utilsApi/rpcProviders.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { - providerFactory, - StaticJsonRpcBatchProvider, -} from '@lidofinance/eth-providers'; -import { trackedJsonRpcProvider } from '@lidofinance/eth-api-providers'; - -import { METRICS_PREFIX } from 'consts/metrics'; -import Metrics from 'utilsApi/metrics'; - -export const getStaticRpcBatchProvider = providerFactory( - trackedJsonRpcProvider({ - prefix: METRICS_PREFIX, - registry: Metrics.registry, - Provider: StaticJsonRpcBatchProvider, - }), -); diff --git a/utilsApi/rpcUrls.ts b/utilsApi/rpcUrls.ts deleted file mode 100644 index e13f422a5..000000000 --- a/utilsApi/rpcUrls.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { CHAINS } from 'consts/chains'; -import { secretConfig } from 'config'; - -export const rpcUrls: Record = { - [CHAINS.Mainnet]: secretConfig.rpcUrls_1, - [CHAINS.Goerli]: secretConfig.rpcUrls_5, - [CHAINS.Holesky]: secretConfig.rpcUrls_17000, -}; From 262b8cc98b5a7b3087fdbbdf442c84a0adbbd005 Mon Sep 17 00:00:00 2001 From: Evgeny Taktarov Date: Wed, 3 Jul 2024 18:07:09 +0700 Subject: [PATCH 07/61] feat: switch widget api to eth api --- README.md | 2 ++ shared/hooks/useLidoStats.ts | 12 ++++-------- utils/get-one-inch-rate.ts | 9 ++------- utils/index.ts | 1 - utils/prependBasePath.ts | 5 ----- 5 files changed, 8 insertions(+), 21 deletions(-) delete mode 100644 utils/prependBasePath.ts diff --git a/README.md b/README.md index 46903a392..f04e5f36c 100644 --- a/README.md +++ b/README.md @@ -66,6 +66,8 @@ yarn build:ipfs ## Adding a new route API +**Deprecated: do not add new endpoints to next api** + - create a new file in `pages/api/` folder - use `wrapRequest` function from `@lidofinance/next-api-wrapper` package. - use default wrappers from `utilsApi/nextApiWrappers.ts` if needed (e.g. `defaultErrorHandler` for handle errors) diff --git a/shared/hooks/useLidoStats.ts b/shared/hooks/useLidoStats.ts index 08105d736..afbb8f322 100644 --- a/shared/hooks/useLidoStats.ts +++ b/shared/hooks/useLidoStats.ts @@ -1,13 +1,12 @@ import { useMemo } from 'react'; -import { useSDK, useLidoSWR } from '@lido-sdk/react'; +import { useLidoSWR } from '@lido-sdk/react'; import { config } from 'config'; import { DATA_UNAVAILABLE } from 'consts/text'; import { STRATEGY_LAZY } from 'consts/swr-strategies'; -import { prependBasePath } from 'utils'; import { standardFetcher } from 'utils/standardFetcher'; -export type ResponseData = { +type ResponseData = { uniqueAnytimeHolders: string; uniqueHolders: string; totalStaked: string; @@ -22,12 +21,9 @@ export const useLidoStats = (): { }; initialLoading: boolean; } => { - const { chainId } = useSDK(); - const apiShortLidoStatsPath = `api/short-lido-stats?chainId=${chainId}`; + const url = `${config.ethAPIBasePath}/v1/protocol/steth/stats`; const lidoStats = useLidoSWR( - config.ipfsMode - ? `${config.widgetApiBasePathForIpfs}/${apiShortLidoStatsPath}` - : prependBasePath(apiShortLidoStatsPath), + url, standardFetcher, STRATEGY_LAZY, ); diff --git a/utils/get-one-inch-rate.ts b/utils/get-one-inch-rate.ts index 2608152a7..52924b76a 100644 --- a/utils/get-one-inch-rate.ts +++ b/utils/get-one-inch-rate.ts @@ -2,7 +2,6 @@ import { BigNumber } from 'ethers'; import { TOKENS } from '@lido-sdk/constants'; import { config } from 'config'; import { standardFetcher } from './standardFetcher'; -import { prependBasePath } from './prependBasePath'; type GetOneInchRateParams = { token: TOKENS.STETH | TOKENS.WSTETH | 'ETH'; @@ -15,15 +14,11 @@ export const getOneInchRate = async ({ }: GetOneInchRateParams) => { const params = new URLSearchParams({ token }); if (amount) params.append('amount', amount.toString()); - const apiOneInchRatePath = `api/oneinch-rate?${params.toString()}`; + const url = `${config.ethAPIBasePath}/v1/swap/one-inch?${params.toString()}`; const data = await standardFetcher<{ rate: number; toReceive: string; - }>( - config.ipfsMode - ? `${config.widgetApiBasePathForIpfs}/${apiOneInchRatePath}` - : prependBasePath(apiOneInchRatePath), - ); + }>(url); return { rate: data.rate, toReceive: BigNumber.from(data.toReceive), diff --git a/utils/index.ts b/utils/index.ts index 34f4e3ba3..4bb0f1b78 100644 --- a/utils/index.ts +++ b/utils/index.ts @@ -2,7 +2,6 @@ export * from './appCookies'; export * from './formatBalance'; export * from './formatBalanceString'; export * from './logger'; -export * from './prependBasePath'; export * from './weiToEth'; export * from './nprogress'; export * from './getErrorMessage'; diff --git a/utils/prependBasePath.ts b/utils/prependBasePath.ts deleted file mode 100644 index a08050e9b..000000000 --- a/utils/prependBasePath.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { config } from 'config'; - -export const prependBasePath = (route: string): string => { - return `${config.basePath ?? ''}/${route}`; -}; From b41f0e67be34c77a2b44ca538e9b1396f09448f8 Mon Sep 17 00:00:00 2001 From: Evgeny Taktarov Date: Wed, 3 Jul 2024 18:50:15 +0700 Subject: [PATCH 08/61] chore: migrate rewards to typechain --- abi/partialCurveAbi.abi.json | 13 ++ features/rewards/components/export/Export.tsx | 2 +- features/rewards/components/stats/Stats.tsx | 2 +- .../fetchers/{requesters/json => }/backend.ts | 0 features/rewards/fetchers/requesters/index.ts | 2 - .../rewards/fetchers/requesters/json/index.ts | 1 - .../rewards/fetchers/requesters/rpc/index.ts | 1 - .../fetchers/requesters/rpc/stEthEth.ts | 25 ---- features/rewards/fetchers/rpcFetch.ts | 121 ------------------ features/rewards/hooks/use-steth-eth-rate.ts | 32 ++--- 10 files changed, 32 insertions(+), 167 deletions(-) create mode 100644 abi/partialCurveAbi.abi.json rename features/rewards/fetchers/{requesters/json => }/backend.ts (100%) delete mode 100644 features/rewards/fetchers/requesters/index.ts delete mode 100644 features/rewards/fetchers/requesters/json/index.ts delete mode 100644 features/rewards/fetchers/requesters/rpc/index.ts delete mode 100644 features/rewards/fetchers/requesters/rpc/stEthEth.ts delete mode 100644 features/rewards/fetchers/rpcFetch.ts diff --git a/abi/partialCurveAbi.abi.json b/abi/partialCurveAbi.abi.json new file mode 100644 index 000000000..7bac8cdaa --- /dev/null +++ b/abi/partialCurveAbi.abi.json @@ -0,0 +1,13 @@ +[ + { + "name": "get_dy", + "outputs": [{ "type": "uint256", "name": "" }], + "inputs": [ + { "type": "int128", "name": "i" }, + { "type": "int128", "name": "j" }, + { "type": "uint256", "name": "dx" } + ], + "stateMutability": "view", + "type": "function" + } +] diff --git a/features/rewards/components/export/Export.tsx b/features/rewards/components/export/Export.tsx index f75ea36a9..cb59ca184 100644 --- a/features/rewards/components/export/Export.tsx +++ b/features/rewards/components/export/Export.tsx @@ -1,6 +1,6 @@ import { genExportData, saveAsCSV } from 'features/rewards/utils'; import { useRewardsHistory } from 'features/rewards/hooks'; -import { backendRequest } from 'features/rewards/fetchers/requesters'; +import { backendRequest } from 'features/rewards/fetchers/backend'; import { ButtonStyle } from './Exportstyled'; diff --git a/features/rewards/components/stats/Stats.tsx b/features/rewards/components/stats/Stats.tsx index 9bff50b72..b8e11f708 100644 --- a/features/rewards/components/stats/Stats.tsx +++ b/features/rewards/components/stats/Stats.tsx @@ -18,7 +18,7 @@ export const Stats: React.FC = () => { data, initialLoading: pending, } = useRewardsHistory(); - const { data: stEthEth } = useStethEthRate(); + const stEthEth = useStethEthRate(); const { data: balanceData } = useRewardsBalanceData(); return ( diff --git a/features/rewards/fetchers/requesters/json/backend.ts b/features/rewards/fetchers/backend.ts similarity index 100% rename from features/rewards/fetchers/requesters/json/backend.ts rename to features/rewards/fetchers/backend.ts diff --git a/features/rewards/fetchers/requesters/index.ts b/features/rewards/fetchers/requesters/index.ts deleted file mode 100644 index e46c9311b..000000000 --- a/features/rewards/fetchers/requesters/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from './json'; -export * from './rpc'; diff --git a/features/rewards/fetchers/requesters/json/index.ts b/features/rewards/fetchers/requesters/json/index.ts deleted file mode 100644 index 581a3f8d8..000000000 --- a/features/rewards/fetchers/requesters/json/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './backend'; diff --git a/features/rewards/fetchers/requesters/rpc/index.ts b/features/rewards/fetchers/requesters/rpc/index.ts deleted file mode 100644 index a59537dbd..000000000 --- a/features/rewards/fetchers/requesters/rpc/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './stEthEth'; diff --git a/features/rewards/fetchers/requesters/rpc/stEthEth.ts b/features/rewards/fetchers/requesters/rpc/stEthEth.ts deleted file mode 100644 index 4882d7bea..000000000 --- a/features/rewards/fetchers/requesters/rpc/stEthEth.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { constants } from 'ethers'; -import type { BigNumber as EthersBigNumber } from 'ethers'; -import { StaticJsonRpcBatchProvider } from '@lidofinance/eth-providers'; - -import { config } from 'config'; -import rpcFetch from 'features/rewards/fetchers/rpcFetch'; - -const MAINNET_CURVE = '0xDC24316b9AE028F1497c275EB9192a3Ea0f67022'; - -/** -Return dynamic price only on mainnet -For testnet simply provide 1-1 ratio for UI to work -**/ - -export const stEthEthRequest = (mainnetProvider: StaticJsonRpcBatchProvider) => - config.defaultChain === 1 - ? rpcFetch( - mainnetProvider, - MAINNET_CURVE, - 'get_dy', - 0, - 1, - String(10 ** 18), - ) - : constants.WeiPerEther; diff --git a/features/rewards/fetchers/rpcFetch.ts b/features/rewards/fetchers/rpcFetch.ts deleted file mode 100644 index ccf007dde..000000000 --- a/features/rewards/fetchers/rpcFetch.ts +++ /dev/null @@ -1,121 +0,0 @@ -import { BigNumber, ContractInterface, Contract } from 'ethers'; -import { isAddress } from 'ethers/lib/utils'; -import get from 'lodash/get'; - -import { StaticJsonRpcBatchProvider } from '@lidofinance/eth-providers'; -import { CHAINS } from '@lido-sdk/constants'; - -const CURVE_ABI = [ - { - name: 'get_dy', - outputs: [{ type: 'uint256', name: '' }], - inputs: [ - { type: 'int128', name: 'i' }, - { type: 'int128', name: 'j' }, - { type: 'uint256', name: 'dx' }, - ], - stateMutability: 'view', - type: 'function', - }, -]; - -const TOKENS = { - ETH: 'ETH', - STETH: 'stETH', - WSTETH: 'wstETH', - CURVE: 'curve', - LDO: 'LDO', - LDO_REWARDS: 'LDO_Rewards', -} as const; -export type TOKENS = (typeof TOKENS)[keyof typeof TOKENS]; - -export const TOKENS_BY_CHAIN_ID = { - [CHAINS.Mainnet]: [TOKENS.STETH, TOKENS.WSTETH, TOKENS.CURVE], - [CHAINS.Rinkeby]: [TOKENS.STETH, TOKENS.WSTETH], - [CHAINS.Goerli]: [TOKENS.STETH, TOKENS.LDO_REWARDS, TOKENS.WSTETH], -} as const; - -export const TOKEN_ADDRESS_BY_CHAIN_ID = { - [CHAINS.Mainnet]: { - [TOKENS.CURVE]: '0xDC24316b9AE028F1497c275EB9192a3Ea0f67022', - }, -} as const; - -export const TOKEN_ABI_BY_CHAIN_ID = { - [CHAINS.Mainnet]: { - [TOKENS.CURVE]: CURVE_ABI, - }, -} as const; - -export const getTokenAddress = ( - chainId: CHAINS, - token: TOKENS, -): string | undefined => get(TOKEN_ADDRESS_BY_CHAIN_ID, [chainId, token]); - -export const getTokenAbi = ( - chainId: CHAINS, - token: TOKENS, -): ContractInterface | undefined => - get(TOKEN_ABI_BY_CHAIN_ID, [chainId, token]); - -// Transforms into [[address, abi], ...] -export const getSwrTokenConfig = (chainId: CHAINS) => { - const tokens = get(TOKENS_BY_CHAIN_ID, chainId, []) as TOKENS[]; - const config = tokens.reduce<[string, ContractInterface][]>( - (arr, tokenName) => { - const address = getTokenAddress(chainId, tokenName); - const abi = getTokenAbi(chainId, tokenName); - if (address && abi) arr.push([address, abi]); - return arr; - }, - [], - ); - return config; -}; - -// Returns { address, abi } by tokenName -export const getTokenConfig = (chainId: CHAINS, tokenName: TOKENS) => ({ - address: getTokenAddress(chainId, tokenName), - abi: getTokenAbi(chainId, tokenName), -}); - -export const GAS_LIMITS_BY_TOKEN = { - [TOKENS.STETH]: { - submit: BigNumber.from(120000), - }, -}; - -// TODO: Migrate to typechain for properly methods and arguments typings -// eslint-disable-next-line @typescript-eslint/no-explicit-any -const rpcFetcher = ( - mainnetProvider: StaticJsonRpcBatchProvider, - ...args: any[] -): Promise => { - mainnetProvider.pollingInterval = 30000; - const ABIs = new Map(getSwrTokenConfig(1)); - - const [arg1, arg2, ...params] = args; - - // it's a contract - if (isAddress(arg1)) { - if (!ABIs) throw new Error('ABI repo not found'); - if (!ABIs.get) throw new Error("ABI repo isn't a Map"); - - const address = arg1; - const method = arg2; - const abi = ABIs.get(address); - - if (!abi) throw new Error(`ABI not found for ${address}`); - const contract = new Contract(address, abi, mainnetProvider); - return contract[method](...params); - } - - // it's a eth call - const method = arg1; - - // TODO: Migrate to typechain for properly methods and arguments typings - // eslint-disable-next-line @typescript-eslint/no-explicit-any - return (mainnetProvider as any)[method](arg2, ...params); -}; - -export default rpcFetcher; diff --git a/features/rewards/hooks/use-steth-eth-rate.ts b/features/rewards/hooks/use-steth-eth-rate.ts index 414e0f3be..c4fcd063e 100644 --- a/features/rewards/hooks/use-steth-eth-rate.ts +++ b/features/rewards/hooks/use-steth-eth-rate.ts @@ -1,26 +1,28 @@ -import { useLidoSWR, useSDK } from '@lido-sdk/react'; +import { useContractSWR, useSDK } from '@lido-sdk/react'; import { STRATEGY_LAZY } from 'consts/swr-strategies'; import { useMainnetStaticRpcProvider } from 'shared/hooks/use-mainnet-static-rpc-provider'; -import { stEthEthRequest } from 'features/rewards/fetchers/requesters'; import { constants } from 'ethers'; +import { PartialCurveAbiAbi__factory } from 'generated'; +import { createContractGetter } from '@lido-sdk/contracts'; + +const getCurveContract = createContractGetter(PartialCurveAbiAbi__factory); +const MAINNET_CURVE = '0xDC24316b9AE028F1497c275EB9192a3Ea0f67022'; export const useStethEthRate = () => { const { chainId } = useSDK(); const mainnetStaticRpcProvider = useMainnetStaticRpcProvider(); - const swrResult = useLidoSWR( - `steth-eth-${chainId}`, - async () => { - if (chainId !== 1) { - return constants.WeiPerEther; - } else { - const stEthEth = await stEthEthRequest(mainnetStaticRpcProvider); - return stEthEth; - } - }, - STRATEGY_LAZY, - ); + const contract = getCurveContract(MAINNET_CURVE, mainnetStaticRpcProvider); + + const swr = useContractSWR({ + contract, + method: 'get_dy', + params: [0, 1, String(10 ** 18)], + config: STRATEGY_LAZY, + shouldFetch: chainId === 1, + }); - return swrResult; + if (chainId !== 1) return constants.WeiPerEther; + return swr.data; }; From bdb0cff230308b66a25ad174e241b7c539bb27e5 Mon Sep 17 00:00:00 2001 From: Evgeny Taktarov Date: Wed, 3 Jul 2024 19:11:45 +0700 Subject: [PATCH 09/61] chore: remove unused code --- features/rewards/types/Event.ts | 4 +- features/rewards/types/TotalRewardsItem.ts | 12 ------ .../request/form/options/styles.ts | 5 --- shared/components/index.ts | 1 - shared/components/logos/logos.tsx | 10 +---- shared/components/logos/styles.tsx | 11 ----- shared/hooks/index.ts | 4 -- shared/hooks/useAsyncMemo.ts | 29 -------------- shared/hooks/useENSAddress.ts | 33 --------------- shared/hooks/useElementResize.ts | 32 --------------- shared/hooks/usePrevious.ts | 12 ------ types/api.ts | 40 ------------------- types/components.ts | 5 --- utils/__tests__/maxNumberValidation.test.ts | 19 --------- utils/index.ts | 1 - utils/maxNumberValidation.ts | 8 ---- utils/rpcProviders.ts | 8 ---- 17 files changed, 3 insertions(+), 231 deletions(-) delete mode 100644 features/rewards/types/TotalRewardsItem.ts delete mode 100644 shared/hooks/useAsyncMemo.ts delete mode 100644 shared/hooks/useENSAddress.ts delete mode 100644 shared/hooks/useElementResize.ts delete mode 100644 shared/hooks/usePrevious.ts delete mode 100644 utils/__tests__/maxNumberValidation.test.ts delete mode 100644 utils/maxNumberValidation.ts delete mode 100644 utils/rpcProviders.ts diff --git a/features/rewards/types/Event.ts b/features/rewards/types/Event.ts index 8c936ea5e..16ac13511 100644 --- a/features/rewards/types/Event.ts +++ b/features/rewards/types/Event.ts @@ -1,6 +1,6 @@ -import { LidoSubmission, LidoTransfer, TotalReward } from '.'; +import { LidoTransfer, TotalReward } from '.'; -export type SubgraphData = LidoSubmission | LidoTransfer | TotalReward; +export type SubgraphData = LidoTransfer | TotalReward; export type AdditionalData = { type: string; diff --git a/features/rewards/types/TotalRewardsItem.ts b/features/rewards/types/TotalRewardsItem.ts deleted file mode 100644 index 7491dfefb..000000000 --- a/features/rewards/types/TotalRewardsItem.ts +++ /dev/null @@ -1,12 +0,0 @@ -export type TotalRewardsItem = { - id: string; - - totalPooledEtherBefore: string; - totalPooledEtherAfter: string; - totalSharesBefore: string; - totalSharesAfter: string; - - block: string; - blockTime: string; - logIndex: string; -}; diff --git a/features/withdrawals/request/form/options/styles.ts b/features/withdrawals/request/form/options/styles.ts index 795d1b941..a17fc704f 100644 --- a/features/withdrawals/request/form/options/styles.ts +++ b/features/withdrawals/request/form/options/styles.ts @@ -14,11 +14,6 @@ export const LidoIcon = styled.img.attrs({ display: block; `; -export const OptionAmountRow = styled.div` - display: flex; - align-items: center; -`; - // LIDO OPTION export const LidoOptionContainer = styled.div` diff --git a/shared/components/index.ts b/shared/components/index.ts index aa2e84933..a783aa8cb 100644 --- a/shared/components/index.ts +++ b/shared/components/index.ts @@ -3,7 +3,6 @@ export { Faq } from './faq/faq'; export { BackgroundGradient } from './background-gradient/background-gradient'; export { Section } from './section/section'; export { TokenToWallet } from './token-to-wallet/token-to-wallet'; -export { LogoLDO, LogoLDOPL } from './logos/logos'; export { TooltipHoverable } from './tooltip-hoverable/tooltip-hoverable'; export { MatomoLink } from './matomo-link/matomo-link'; export { InfoBox } from './info-box/info-box'; diff --git a/shared/components/logos/logos.tsx b/shared/components/logos/logos.tsx index ac6e5fbde..b3d01e00b 100644 --- a/shared/components/logos/logos.tsx +++ b/shared/components/logos/logos.tsx @@ -4,18 +4,10 @@ import { LidoLogo } from '@lidofinance/lido-ui'; import { config } from 'config'; -import { LogoLDOPLStyle, LogoLDOStyle, LogoLidoStyle } from './styles'; +import { LogoLidoStyle } from './styles'; export type LogoComponent = FC, 'ref'>>; -export const LogoLDO: LogoComponent = (props) => { - return ; -}; - -export const LogoLDOPL: LogoComponent = (props) => { - return ; -}; - export const LogoLido: FC> = (props) => ( diff --git a/shared/components/logos/styles.tsx b/shared/components/logos/styles.tsx index 2d2a62fac..60e23086c 100644 --- a/shared/components/logos/styles.tsx +++ b/shared/components/logos/styles.tsx @@ -1,16 +1,5 @@ -import { Ldo, Ldopl } from '@lidofinance/lido-ui'; import styled from 'styled-components'; -export const LogoLDOStyle = styled((props) => )` - width: 40px; - height: 40px; -`; - -export const LogoLDOPLStyle = styled((props) => )` - width: 40px; - height: 40px; -`; - export const LogoLidoStyle = styled.div` overflow: hidden; display: flex; diff --git a/shared/hooks/index.ts b/shared/hooks/index.ts index b8a307802..bc624cfab 100644 --- a/shared/hooks/index.ts +++ b/shared/hooks/index.ts @@ -1,8 +1,6 @@ export * from './useCopyToClipboard'; -export * from './useENSAddress'; export * from './useLidoStats'; export * from './useLidoApr'; -export * from './usePrevious'; export * from './useMaxGasPrice'; export * from './useWstethBySteth'; export * from './useStethByWsteth'; @@ -11,7 +9,5 @@ export * from './useLidoSwr'; export * from './useStakingLimitInfo'; export * from './useMatomoEventHandle'; export * from './useERC20PermitSignature'; -export * from './useAsyncMemo'; -export * from './useElementResize'; export * from './useDebouncedValue'; export * from './useIsContract'; diff --git a/shared/hooks/useAsyncMemo.ts b/shared/hooks/useAsyncMemo.ts deleted file mode 100644 index 671eeab7e..000000000 --- a/shared/hooks/useAsyncMemo.ts +++ /dev/null @@ -1,29 +0,0 @@ -import { DependencyList, useState, useEffect } from 'react'; - -/* - Slightly modified version of use-async-memo - Author: awmleer - Date: 2023 - Version: 1.2.4 - Availability :https://github.com/awmleer/use-async-memo/blob/master/src/index.ts -*/ - -export const useAsyncMemo = ( - callback: () => Promise, - deps: DependencyList, -) => { - const [result, setResult] = useState(undefined); - useEffect(() => { - let shouldCancel = false; - void callback().then((val) => { - if (!shouldCancel) { - setResult(val); - } - }); - return () => { - shouldCancel = true; - }; - // eslint-disable-next-line react-hooks/exhaustive-deps - }, deps); - return result; -}; diff --git a/shared/hooks/useENSAddress.ts b/shared/hooks/useENSAddress.ts deleted file mode 100644 index 8148a0566..000000000 --- a/shared/hooks/useENSAddress.ts +++ /dev/null @@ -1,33 +0,0 @@ -import { useSDK } from '@lido-sdk/react'; -import { useCallback, useEffect, useState } from 'react'; - -export const useENSAddress = (): string | undefined => { - const [ensAddress, setEnsAddress] = useState(); - - const { account, providerRpc } = useSDK(); - - const getEnsAddress = useCallback(async () => { - if (!providerRpc || !account) { - return; - } - - try { - const _ensAddress = await providerRpc.lookupAddress(account); - - if (_ensAddress) { - setEnsAddress(_ensAddress); - } else { - setEnsAddress(account); - } - } catch (e) { - console.error(e); - setEnsAddress(account); - } - }, [providerRpc, account]); - - useEffect(() => { - void getEnsAddress(); - }, [getEnsAddress, account]); - - return ensAddress; -}; diff --git a/shared/hooks/useElementResize.ts b/shared/hooks/useElementResize.ts deleted file mode 100644 index a7b6737e0..000000000 --- a/shared/hooks/useElementResize.ts +++ /dev/null @@ -1,32 +0,0 @@ -import { useRef, useCallback, useEffect } from 'react'; - -export const useElementResize = ( - onResize: (value: { width: number; height: number }) => (() => void) | void, -): React.MutableRefObject => { - const elementRef = useRef(null); - const observerRef = useRef(null); - - const handleResize = useCallback(() => { - if (!elementRef.current) return; - - const { width, height } = elementRef.current.getBoundingClientRect(); - - return onResize({ width, height }); - }, [onResize]); - - useEffect(() => { - if (!elementRef.current) return; - - observerRef.current = new ResizeObserver(handleResize); - observerRef.current.observe(elementRef.current); - const disposer = handleResize(); - - return (): void => { - observerRef.current?.disconnect(); - observerRef.current = null; - if (disposer) disposer(); - }; - }, [handleResize, elementRef]); - - return elementRef; -}; diff --git a/shared/hooks/usePrevious.ts b/shared/hooks/usePrevious.ts deleted file mode 100644 index 9366cfbd2..000000000 --- a/shared/hooks/usePrevious.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { useRef, useEffect } from 'react'; -import type { MutableRefObject } from 'react'; - -export const usePrevious = ( - value: T, -): MutableRefObject['current'] => { - const ref = useRef(); - useEffect(() => { - ref.current = value; - }, [value]); - return ref.current; -}; diff --git a/types/api.ts b/types/api.ts index 9e597487f..bc1bb550c 100644 --- a/types/api.ts +++ b/types/api.ts @@ -4,43 +4,3 @@ export type API = ( req: NextApiRequest, res: NextApiResponse, ) => Promise; - -export type EthplorerResponse = { - address: string; - decimals: string; - name: string; - symbol: string; - totalSupply: string; - transfersCount: number; - lastUpdated: number; - slot: number; - issuancesCount: number; - holdersCount: number; - website: string; - telegram: string; - twitter: string; - reddit: string; - image: string; - coingecko: string; - ethTransfersCount: 0; - price: { - rate: number; - diff: number; - diff7d: number; - ts: number; - marketCapUsd: number; - availableSupply: number; - volume24h: number; - volDiff1: number; - volDiff7: number; - volDiff30: number; - diff30d: number; - currency: string; - }; - publicTags: string[]; - countOps: number; -}; - -export type EthplorerWrappedDataResponse = { - data: EthplorerResponse; -}; diff --git a/types/components.ts b/types/components.ts index 30b5fde16..9fcd134fe 100644 --- a/types/components.ts +++ b/types/components.ts @@ -9,8 +9,3 @@ export type Component< T extends keyof JSX.IntrinsicElements, P extends Record = { children?: ReactNode }, > = FC>; - -export type Override< - T extends Record, - P extends Record, -> = Omit & P; diff --git a/utils/__tests__/maxNumberValidation.test.ts b/utils/__tests__/maxNumberValidation.test.ts deleted file mode 100644 index 48f412384..000000000 --- a/utils/__tests__/maxNumberValidation.test.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { maxNumberValidation } from '../maxNumberValidation'; - -describe('maxNumberValidation', () => { - it('should return "0" if input is not a number', () => { - expect(maxNumberValidation('not a number')).toBe('0'); - }); - - it('should return maximum safe integer if input is infinite', () => { - expect(maxNumberValidation('Infinity')).toBe('9007199254740991'); - }); - - it('should return the input if it is a valid number', () => { - expect(maxNumberValidation('123')).toBe('123'); - }); - - it('should return the maximum safe integer if input is greater than the maximum safe integer', () => { - expect(maxNumberValidation('9007199254740992')).toBe('9007199254740991'); - }); -}); diff --git a/utils/index.ts b/utils/index.ts index 4bb0f1b78..69b979ca7 100644 --- a/utils/index.ts +++ b/utils/index.ts @@ -8,5 +8,4 @@ export * from './getErrorMessage'; export * from './extractErrorMessage'; export * from './swrAbortableMiddleware'; export * from './getNFTUrl'; -export * from './maxNumberValidation'; export * from './shortenTokenValue'; diff --git a/utils/maxNumberValidation.ts b/utils/maxNumberValidation.ts deleted file mode 100644 index 006e21c97..000000000 --- a/utils/maxNumberValidation.ts +++ /dev/null @@ -1,8 +0,0 @@ -export const maxNumberValidation = (input: string) => { - if (Number.isNaN(Number(input))) return '0'; - if (Number.isFinite(input)) return '0'; - if (Math.abs(Number(input)) > Number.MAX_SAFE_INTEGER) - return String(Number.MAX_SAFE_INTEGER); - - return input; -}; diff --git a/utils/rpcProviders.ts b/utils/rpcProviders.ts deleted file mode 100644 index 4c47e6296..000000000 --- a/utils/rpcProviders.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { - providerFactory, - StaticJsonRpcBatchProvider, -} from '@lidofinance/eth-providers'; - -export const getStaticRpcBatchProvider = providerFactory( - StaticJsonRpcBatchProvider, -); From c0e0f4df45f76a984e0a2ccaa9f23d12809dcfb8 Mon Sep 17 00:00:00 2001 From: Evgeny Taktarov Date: Thu, 4 Jul 2024 11:18:04 +0700 Subject: [PATCH 10/61] chore: refactor eth api urls --- consts/api.ts | 33 +++++++++++++++++++++++++------- pages/api/eth-apr.ts | 3 ++- pages/api/eth-price.ts | 3 ++- pages/api/oneinch-rate.ts | 3 ++- pages/api/short-lido-stats.ts | 3 ++- pages/api/sma-steth-apr.ts | 3 ++- pages/api/totalsupply.ts | 3 ++- shared/banners/curve/useCurve.ts | 5 ++--- shared/hooks/useLidoApr.ts | 4 ++-- shared/hooks/useLidoStats.ts | 4 ++-- utils/get-one-inch-rate.ts | 4 ++-- utilsApi/cached-proxy.ts | 9 +++++---- 12 files changed, 51 insertions(+), 26 deletions(-) diff --git a/consts/api.ts b/consts/api.ts index c8463e40a..2c3108125 100644 --- a/consts/api.ts +++ b/consts/api.ts @@ -25,23 +25,42 @@ export const enum API_ROUTES { REWARDS = 'api/rewards', } -const getEthApiOrigin = (path: string) => { - return config.ethAPIBasePath + path; +export const enum ETH_API_ROUTES { + ETH_APR = '/v1/protocol/eth/apr/last', + ETH_PRICE = '/v1/protocol/eth/price', + STETH_STATS = '/v1/protocol/steth/stats', + STETH_SMA_APR = '/v1/protocol/steth/apr/sma', + SWAP_ONE_INCH = '/v1/swap/one-inch', + CURVE_APR = '/v1/pool/curve/steth-eth/apr/last', +} + +export const getEthApiPath = ( + endpoint: ETH_API_ROUTES, + params?: + | string + | string[][] + | Record + | URLSearchParams + | undefined, +) => { + let search = new URLSearchParams(params).toString(); + search = search ? '?' + search : ''; + return config.ethAPIBasePath + endpoint + search; }; export const getReplacementLink = (apiRoute: API_ROUTES): string => { switch (apiRoute) { case API_ROUTES.ETH_APR: - return getEthApiOrigin('/v1/protocol/eth/apr/last'); + return getEthApiPath(ETH_API_ROUTES.ETH_APR); case API_ROUTES.ETH_PRICE: - return getEthApiOrigin('/v1/protocol/eth/price'); + return getEthApiPath(ETH_API_ROUTES.ETH_PRICE); case API_ROUTES.TOTALSUPPLY: case API_ROUTES.SHORT_LIDO_STATS: - return getEthApiOrigin('/v1/protocol/steth/stats'); + return getEthApiPath(ETH_API_ROUTES.STETH_STATS); case API_ROUTES.SMA_STETH_APR: - return getEthApiOrigin('/v1/protocol/steth/apr/sma'); + return getEthApiPath(ETH_API_ROUTES.STETH_SMA_APR); case API_ROUTES.ONEINCH_RATE: - return getEthApiOrigin('/v1/swap/one-inch'); + return getEthApiPath(ETH_API_ROUTES.SWAP_ONE_INCH); default: throw new Error(`No replacement link found for route: ${apiRoute}`); } diff --git a/pages/api/eth-apr.ts b/pages/api/eth-apr.ts index 3c0e96bb5..01cb56035 100644 --- a/pages/api/eth-apr.ts +++ b/pages/api/eth-apr.ts @@ -4,6 +4,7 @@ import { config } from 'config'; import { API_DEFAULT_SUNSET_TIMESTAMP, API_ROUTES, + ETH_API_ROUTES, getReplacementLink, } from 'consts/api'; import { @@ -29,7 +30,7 @@ export default wrapNextRequest([ ])( createEthApiProxy({ cacheTTL: config.CACHE_ETH_APR_TTL, - endpoint: '/v1/protocol/eth/apr/last', + endpoint: ETH_API_ROUTES.ETH_APR, ignoreParams: true, transformData: (data) => data.data.apr.toFixed(1), }), diff --git a/pages/api/eth-price.ts b/pages/api/eth-price.ts index 4a34e0ed5..13fb37bc2 100644 --- a/pages/api/eth-price.ts +++ b/pages/api/eth-price.ts @@ -7,6 +7,7 @@ import { config } from 'config'; import { API_DEFAULT_SUNSET_TIMESTAMP, API_ROUTES, + ETH_API_ROUTES, getReplacementLink, } from 'consts/api'; import { @@ -34,7 +35,7 @@ export default wrapNextRequest([ ])( createEthApiProxy({ cacheTTL: config.CACHE_ETH_PRICE_TTL, - endpoint: '/v1/protocol/eth/price', + endpoint: ETH_API_ROUTES.ETH_PRICE, ignoreParams: true, }), ); diff --git a/pages/api/oneinch-rate.ts b/pages/api/oneinch-rate.ts index 6a625dcd5..b36a1e146 100644 --- a/pages/api/oneinch-rate.ts +++ b/pages/api/oneinch-rate.ts @@ -4,6 +4,7 @@ import { config } from 'config'; import { API_DEFAULT_SUNSET_TIMESTAMP, API_ROUTES, + ETH_API_ROUTES, getReplacementLink, } from 'consts/api'; import { @@ -31,7 +32,7 @@ export default wrapNextRequest([ ])( createEthApiProxy({ cacheTTL: config.CACHE_ONE_INCH_RATE_TTL, - endpoint: '/v1/swap/one-inch', + endpoint: ETH_API_ROUTES.SWAP_ONE_INCH, ignoreParams: false, }), ); diff --git a/pages/api/short-lido-stats.ts b/pages/api/short-lido-stats.ts index cb9253746..a1f187bc0 100644 --- a/pages/api/short-lido-stats.ts +++ b/pages/api/short-lido-stats.ts @@ -4,6 +4,7 @@ import { config } from 'config'; import { API_DEFAULT_SUNSET_TIMESTAMP, API_ROUTES, + ETH_API_ROUTES, getReplacementLink, } from 'consts/api'; @@ -32,7 +33,7 @@ export default wrapNextRequest([ ])( createEthApiProxy({ cacheTTL: config.CACHE_LIDO_SHORT_STATS_TTL, - endpoint: '/v1/protocol/steth/stats', + endpoint: ETH_API_ROUTES.STETH_STATS, ignoreParams: true, }), ); diff --git a/pages/api/sma-steth-apr.ts b/pages/api/sma-steth-apr.ts index b6776818f..9a274096f 100644 --- a/pages/api/sma-steth-apr.ts +++ b/pages/api/sma-steth-apr.ts @@ -4,6 +4,7 @@ import { config } from 'config'; import { API_DEFAULT_SUNSET_TIMESTAMP, API_ROUTES, + ETH_API_ROUTES, getReplacementLink, } from 'consts/api'; import { @@ -29,7 +30,7 @@ export default wrapNextRequest([ ])( createEthApiProxy({ cacheTTL: config.CACHE_SMA_STETH_APR_TTL, - endpoint: '/v1/protocol/steth/apr/sma', + endpoint: ETH_API_ROUTES.STETH_SMA_APR, ignoreParams: true, transformData: (data) => data.data.smaApr.toFixed(1), }), diff --git a/pages/api/totalsupply.ts b/pages/api/totalsupply.ts index d65c192a4..29db01999 100644 --- a/pages/api/totalsupply.ts +++ b/pages/api/totalsupply.ts @@ -7,6 +7,7 @@ import { config } from 'config'; import { API_DEFAULT_SUNSET_TIMESTAMP, API_ROUTES, + ETH_API_ROUTES, getReplacementLink, } from 'consts/api'; import { @@ -33,7 +34,7 @@ export default wrapNextRequest([ ])( createEthApiProxy({ cacheTTL: config.CACHE_TOTAL_SUPPLY_TTL, - endpoint: '/v1/protocol/steth/stats', + endpoint: ETH_API_ROUTES.STETH_STATS, ignoreParams: true, transformData: (data) => data.totalStaked, }), diff --git a/shared/banners/curve/useCurve.ts b/shared/banners/curve/useCurve.ts index cdc0bfccf..a10e6990c 100644 --- a/shared/banners/curve/useCurve.ts +++ b/shared/banners/curve/useCurve.ts @@ -1,14 +1,13 @@ import { useLidoSWR } from '@lido-sdk/react'; -import { config } from 'config'; - import { standardFetcher } from 'utils/standardFetcher'; import { CurveResponse } from './types'; +import { ETH_API_ROUTES, getEthApiPath } from 'consts/api'; export const useCurve = () => { return useLidoSWR( - `${config.ethAPIBasePath ?? ''}/v1/pool/curve/steth-eth/apr/last`, + getEthApiPath(ETH_API_ROUTES.CURVE_APR), standardFetcher, ); }; diff --git a/shared/hooks/useLidoApr.ts b/shared/hooks/useLidoApr.ts index 34d0a038d..89e01de73 100644 --- a/shared/hooks/useLidoApr.ts +++ b/shared/hooks/useLidoApr.ts @@ -1,9 +1,9 @@ import { SWRResponse, useLidoSWR } from '@lido-sdk/react'; import { CHAINS } from '@lido-sdk/constants'; -import { config } from 'config'; import { STRATEGY_LAZY } from 'consts/swr-strategies'; import { standardFetcher } from 'utils/standardFetcher'; +import { ETH_API_ROUTES, getEthApiPath } from 'consts/api'; type SMA_APR_RESPONSE = { data: { @@ -54,7 +54,7 @@ export const useLidoApr = (): SWRResponse & { apr?: string; } => { const { data, ...rest } = useLidoSWR( - `${config.ethAPIBasePath ?? ''}/v1/protocol/steth/apr/sma`, + getEthApiPath(ETH_API_ROUTES.STETH_SMA_APR), standardFetcher, STRATEGY_LAZY, ); diff --git a/shared/hooks/useLidoStats.ts b/shared/hooks/useLidoStats.ts index afbb8f322..a527fc7aa 100644 --- a/shared/hooks/useLidoStats.ts +++ b/shared/hooks/useLidoStats.ts @@ -1,10 +1,10 @@ import { useMemo } from 'react'; import { useLidoSWR } from '@lido-sdk/react'; -import { config } from 'config'; import { DATA_UNAVAILABLE } from 'consts/text'; import { STRATEGY_LAZY } from 'consts/swr-strategies'; import { standardFetcher } from 'utils/standardFetcher'; +import { ETH_API_ROUTES, getEthApiPath } from 'consts/api'; type ResponseData = { uniqueAnytimeHolders: string; @@ -21,7 +21,7 @@ export const useLidoStats = (): { }; initialLoading: boolean; } => { - const url = `${config.ethAPIBasePath}/v1/protocol/steth/stats`; + const url = getEthApiPath(ETH_API_ROUTES.STETH_STATS); const lidoStats = useLidoSWR( url, standardFetcher, diff --git a/utils/get-one-inch-rate.ts b/utils/get-one-inch-rate.ts index 52924b76a..30c289e67 100644 --- a/utils/get-one-inch-rate.ts +++ b/utils/get-one-inch-rate.ts @@ -1,7 +1,7 @@ import { BigNumber } from 'ethers'; import { TOKENS } from '@lido-sdk/constants'; -import { config } from 'config'; import { standardFetcher } from './standardFetcher'; +import { ETH_API_ROUTES, getEthApiPath } from 'consts/api'; type GetOneInchRateParams = { token: TOKENS.STETH | TOKENS.WSTETH | 'ETH'; @@ -14,7 +14,7 @@ export const getOneInchRate = async ({ }: GetOneInchRateParams) => { const params = new URLSearchParams({ token }); if (amount) params.append('amount', amount.toString()); - const url = `${config.ethAPIBasePath}/v1/swap/one-inch?${params.toString()}`; + const url = getEthApiPath(ETH_API_ROUTES.SWAP_ONE_INCH, params); const data = await standardFetcher<{ rate: number; toReceive: string; diff --git a/utilsApi/cached-proxy.ts b/utilsApi/cached-proxy.ts index 9fba2f0b2..3fb334a7d 100644 --- a/utilsApi/cached-proxy.ts +++ b/utilsApi/cached-proxy.ts @@ -2,8 +2,9 @@ import { API } from '@lidofinance/next-api-wrapper'; import { Cache } from 'memory-cache'; import { responseTimeExternalMetricWrapper } from './fetchApiWrapper'; import { standardFetcher } from 'utils/standardFetcher'; -import { secretConfig } from 'config'; +import { config } from 'config'; import { FetcherError } from 'utils/fetcherError'; +import { ETH_API_ROUTES, getEthApiPath } from 'consts/api'; type ProxyOptions = { proxyUrl: string; @@ -76,7 +77,7 @@ type EthApiProxyOptions = Pick< ProxyOptions, 'transformData' | 'ignoreParams' | 'cacheTTL' > & { - endpoint: string; + endpoint: ETH_API_ROUTES; }; export const createEthApiProxy = ({ @@ -89,8 +90,8 @@ export const createEthApiProxy = ({ cacheTTL, ignoreParams, transformData, - proxyUrl: `${secretConfig.ethAPIBasePath}${endpoint}`, - metricsHost: secretConfig.ethAPIBasePath, + proxyUrl: getEthApiPath(endpoint), + metricsHost: config.ethAPIBasePath, timeout: 5000, }); }; From 9e476501efd310edd7ed5b87c63a4f7ee192dee9 Mon Sep 17 00:00:00 2001 From: Evgeny Taktarov Date: Thu, 4 Jul 2024 11:20:02 +0700 Subject: [PATCH 11/61] test: fix api tests --- test/consts.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/consts.ts b/test/consts.ts index fa9024e3d..b070b3953 100644 --- a/test/consts.ts +++ b/test/consts.ts @@ -230,7 +230,7 @@ export const GET_REQUESTS: GetRequest[] = [ }, }, required: ['price'], - additionalProperties: false, + additionalProperties: true, }, }, { From 861d3d8643dbc7fa83057a0d144af8d138d76c62 Mon Sep 17 00:00:00 2001 From: Evgeny Taktarov Date: Wed, 10 Jul 2024 14:45:21 +0700 Subject: [PATCH 12/61] fix: move deprecation date --- consts/api.ts | 7 ++++++- pages/api/eth-price.ts | 4 ++-- pages/api/oneinch-rate.ts | 4 ++-- pages/api/short-lido-stats.ts | 4 ++-- pages/api/totalsupply.ts | 4 ++-- 5 files changed, 14 insertions(+), 9 deletions(-) diff --git a/consts/api.ts b/consts/api.ts index 2c3108125..c35dda051 100644 --- a/consts/api.ts +++ b/consts/api.ts @@ -5,11 +5,16 @@ export const ETHPLORER_TOKEN_ENDPOINT = export const HEALTHY_RPC_SERVICES_ARE_OVER = 'Healthy RPC services are over!'; -// 5rd August, Monday, middle of the working day +// 5th August, Monday, middle of the working day export const API_DEFAULT_SUNSET_TIMESTAMP = new Date( '2024-08-05T09:00:00', ).getTime(); +// 9th September, Monday, middle of the working day +export const API_LATER_SUNSET_TIMESTAMP = new Date( + '2024-09-09T09:00:00', +).getTime(); + export const enum API_ROUTES { ETH_APR = 'api/eth-apr', ETH_PRICE = 'api/eth-price', diff --git a/pages/api/eth-price.ts b/pages/api/eth-price.ts index 13fb37bc2..6eb81af11 100644 --- a/pages/api/eth-price.ts +++ b/pages/api/eth-price.ts @@ -5,7 +5,7 @@ import { import { config } from 'config'; import { - API_DEFAULT_SUNSET_TIMESTAMP, + API_LATER_SUNSET_TIMESTAMP, API_ROUTES, ETH_API_ROUTES, getReplacementLink, @@ -28,7 +28,7 @@ export default wrapNextRequest([ responseTimeMetric(Metrics.request.apiTimings, API_ROUTES.ETH_PRICE), cacheControl({ headers: config.CACHE_ETH_PRICE_HEADERS }), sunsetBy({ - sunsetTimestamp: API_DEFAULT_SUNSET_TIMESTAMP, + sunsetTimestamp: API_LATER_SUNSET_TIMESTAMP, replacementLink: getReplacementLink(API_ROUTES.ETH_PRICE), }), defaultErrorHandler, diff --git a/pages/api/oneinch-rate.ts b/pages/api/oneinch-rate.ts index b36a1e146..80132650b 100644 --- a/pages/api/oneinch-rate.ts +++ b/pages/api/oneinch-rate.ts @@ -2,7 +2,7 @@ import { wrapRequest as wrapNextRequest } from '@lidofinance/next-api-wrapper'; import { config } from 'config'; import { - API_DEFAULT_SUNSET_TIMESTAMP, + API_LATER_SUNSET_TIMESTAMP, API_ROUTES, ETH_API_ROUTES, getReplacementLink, @@ -25,7 +25,7 @@ export default wrapNextRequest([ rateLimit, responseTimeMetric(Metrics.request.apiTimings, API_ROUTES.ONEINCH_RATE), sunsetBy({ - sunsetTimestamp: API_DEFAULT_SUNSET_TIMESTAMP, + sunsetTimestamp: API_LATER_SUNSET_TIMESTAMP, replacementLink: getReplacementLink(API_ROUTES.ONEINCH_RATE), }), ...errorAndCacheDefaultWrappers, diff --git a/pages/api/short-lido-stats.ts b/pages/api/short-lido-stats.ts index a1f187bc0..b8b694e1c 100644 --- a/pages/api/short-lido-stats.ts +++ b/pages/api/short-lido-stats.ts @@ -2,7 +2,7 @@ import { wrapRequest as wrapNextRequest } from '@lidofinance/next-api-wrapper'; import { config } from 'config'; import { - API_DEFAULT_SUNSET_TIMESTAMP, + API_LATER_SUNSET_TIMESTAMP, API_ROUTES, ETH_API_ROUTES, getReplacementLink, @@ -26,7 +26,7 @@ export default wrapNextRequest([ rateLimit, responseTimeMetric(Metrics.request.apiTimings, API_ROUTES.SHORT_LIDO_STATS), sunsetBy({ - sunsetTimestamp: API_DEFAULT_SUNSET_TIMESTAMP, + sunsetTimestamp: API_LATER_SUNSET_TIMESTAMP, replacementLink: getReplacementLink(API_ROUTES.SHORT_LIDO_STATS), }), ...errorAndCacheDefaultWrappers, diff --git a/pages/api/totalsupply.ts b/pages/api/totalsupply.ts index 29db01999..e855c2ead 100644 --- a/pages/api/totalsupply.ts +++ b/pages/api/totalsupply.ts @@ -5,7 +5,7 @@ import { import { config } from 'config'; import { - API_DEFAULT_SUNSET_TIMESTAMP, + API_LATER_SUNSET_TIMESTAMP, API_ROUTES, ETH_API_ROUTES, getReplacementLink, @@ -27,7 +27,7 @@ export default wrapNextRequest([ responseTimeMetric(Metrics.request.apiTimings, API_ROUTES.TOTALSUPPLY), cacheControl({ headers: config.CACHE_TOTAL_SUPPLY_HEADERS }), sunsetBy({ - sunsetTimestamp: API_DEFAULT_SUNSET_TIMESTAMP, + sunsetTimestamp: API_LATER_SUNSET_TIMESTAMP, replacementLink: getReplacementLink(API_ROUTES.TOTALSUPPLY), }), defaultErrorHandler, From 2ecbfda6840e4e03711d1f541a7e94d0a443fb2e Mon Sep 17 00:00:00 2001 From: Anton Shalimov Date: Fri, 19 Jul 2024 14:17:49 +0300 Subject: [PATCH 13/61] refactor(reward): top card for connected wallet --- .../InputDescriptionStyles.ts | 12 +++++-- .../rewardsListContent/RewardsListContent.tsx | 14 +++++--- .../rewardsListContent/RewardsListsEmpty.tsx | 2 +- features/rewards/features/top-card/styles.tsx | 20 +++++++++++ features/rewards/features/top-card/wallet.tsx | 36 ++++++++----------- .../address-badge/address-badge.tsx | 11 +++--- 6 files changed, 62 insertions(+), 33 deletions(-) diff --git a/features/rewards/components/inputDescription/InputDescriptionStyles.ts b/features/rewards/components/inputDescription/InputDescriptionStyles.ts index b874bbfdd..1dca41906 100644 --- a/features/rewards/components/inputDescription/InputDescriptionStyles.ts +++ b/features/rewards/components/inputDescription/InputDescriptionStyles.ts @@ -1,10 +1,18 @@ import styled from 'styled-components'; export const WrapperStyle = styled.div` + flex: 1; padding: ${({ theme }) => theme.spaceMap.sm}px; + margin-right: ${({ theme }) => theme.spaceMap.xl}px; + border-radius: ${({ theme }) => theme.spaceMap.sm}px; - color: #ffac2f; + background-color: rgb(255, 172, 47, 0.1); + color: #ffac2f; text-align: center; - margin-top: 16px; + + ${({ theme }) => theme.mediaQueries.md} { + margin-right: 0; + margin-top: ${({ theme }) => theme.spaceMap.xl}px; + } `; diff --git a/features/rewards/components/rewardsListContent/RewardsListContent.tsx b/features/rewards/components/rewardsListContent/RewardsListContent.tsx index e74523842..ff5d9de6e 100644 --- a/features/rewards/components/rewardsListContent/RewardsListContent.tsx +++ b/features/rewards/components/rewardsListContent/RewardsListContent.tsx @@ -1,7 +1,13 @@ import { FC } from 'react'; import { Loader, Divider } from '@lidofinance/lido-ui'; +import { useSTETHBalance } from '@lido-sdk/react'; +import { Zero } from '@ethersproject/constants'; + +import { STRATEGY_LAZY } from 'consts/swr-strategies'; import { useRewardsHistory } from 'features/rewards/hooks'; import { ErrorBlockNoSteth } from 'features/rewards/components/errorBlocks/ErrorBlockNoSteth'; +import { RewardsTable } from 'features/rewards/components/rewardsTable'; +import { useDappStatus } from 'shared/hooks/use-dapp-status'; import { RewardsListsEmpty } from './RewardsListsEmpty'; import { RewardsListErrorMessage } from './RewardsListErrorMessage'; @@ -10,12 +16,9 @@ import { TableWrapperStyle, ErrorWrapper, } from './RewardsListContentStyles'; -import { RewardsTable } from 'features/rewards/components/rewardsTable'; -import { useSTETHBalance } from '@lido-sdk/react'; -import { STRATEGY_LAZY } from 'consts/swr-strategies'; -import { Zero } from '@ethersproject/constants'; export const RewardsListContent: FC = () => { + const { isDappActive } = useDappStatus(); const { error, initialLoading, @@ -29,7 +32,8 @@ export const RewardsListContent: FC = () => { useSTETHBalance(STRATEGY_LAZY); const hasSteth = stethBalance?.gt(Zero); - if (!data && !initialLoading && !error) return ; + if (!isDappActive || (!data && !initialLoading && !error)) + return ; // showing loading when canceling requests and empty response if ( (!data && !error) || diff --git a/features/rewards/components/rewardsListContent/RewardsListsEmpty.tsx b/features/rewards/components/rewardsListContent/RewardsListsEmpty.tsx index d418e9745..9aa9330dd 100644 --- a/features/rewards/components/rewardsListContent/RewardsListsEmpty.tsx +++ b/features/rewards/components/rewardsListContent/RewardsListsEmpty.tsx @@ -8,7 +8,7 @@ export const RewardsListsEmpty: FC = () => { <> - Connect your wallet to see the stats. + Connect your wallet to view your staking stats. ); diff --git a/features/rewards/features/top-card/styles.tsx b/features/rewards/features/top-card/styles.tsx index 2b03a3d26..d567d537f 100644 --- a/features/rewards/features/top-card/styles.tsx +++ b/features/rewards/features/top-card/styles.tsx @@ -1,5 +1,6 @@ import styled, { css } from 'styled-components'; import { WalletCardStyle } from 'shared/wallet/card/styles'; +import { AddressBadge } from 'shared/wallet/components/address-badge/address-badge'; export const WalletStyle = styled(WalletCardStyle)` background: linear-gradient( @@ -11,6 +12,25 @@ export const WalletStyle = styled(WalletCardStyle)` padding: 0 0 24px 0; `; +export const WalletContentStyle = styled.div` + display: flex; + flex-wrap: nowrap; + flex-direction: row; + align-items: center; + justify-content: space-between; + + padding: ${({ theme }) => theme.spaceMap.xxl}px; + + ${({ theme }) => theme.mediaQueries.md} { + align-items: end; + flex-direction: column-reverse; + } +`; + +export const WalletContentAddressBadgeStyle = styled(AddressBadge)` + background: #00000033; +`; + export const ConnectWalletStyle = styled(WalletCardStyle)` padding: 27px 27px 47px 27px; text-align: center; diff --git a/features/rewards/features/top-card/wallet.tsx b/features/rewards/features/top-card/wallet.tsx index b845facf3..53ec384ec 100644 --- a/features/rewards/features/top-card/wallet.tsx +++ b/features/rewards/features/top-card/wallet.tsx @@ -2,38 +2,32 @@ import { FC } from 'react'; import { ThemeProvider, themeDark } from '@lidofinance/lido-ui'; import { InputDescription } from 'features/rewards/components/inputDescription'; -import { AddressInput } from 'features/rewards/components/addressInput'; -import { InputWrapper } from 'features/rewards/components/inputWrapper'; import { useRewardsHistory } from 'features/rewards/hooks'; -import { WalletStyle } from './styles'; +import { + WalletStyle, + WalletContentStyle, + WalletContentAddressBadgeStyle, +} from './styles'; const INPUT_DESC_TEXT = 'Current balance may differ from last balance in the table due to rounding.'; export const Wallet: FC = () => { - const { - address, - addressError, - isAddressResolving, - inputValue, - setInputValue, - } = useRewardsHistory(); + const { address } = useRewardsHistory(); return ( - - - + + {INPUT_DESC_TEXT} - - + + + ); }; diff --git a/shared/wallet/components/address-badge/address-badge.tsx b/shared/wallet/components/address-badge/address-badge.tsx index 918ca5379..90f97e66b 100644 --- a/shared/wallet/components/address-badge/address-badge.tsx +++ b/shared/wallet/components/address-badge/address-badge.tsx @@ -1,19 +1,22 @@ import { useBreakpoint, IdenticonBadgeProps } from '@lidofinance/lido-ui'; -import { AddressBadgeStyle } from './styles'; import { Component } from 'types'; +import { AddressBadgeStyle } from './styles'; export type AddressBadgeComponent = Component< 'div', - Omit & { address?: string | null } + Omit & { address?: string | null } & { + symbolsMobile?: number; + symbolsDesktop?: number; + } >; export const AddressBadge: AddressBadgeComponent = (props) => { - const { address, ...rest } = props; + const { address, symbolsMobile = 3, symbolsDesktop = 6, ...rest } = props; const isMobile = useBreakpoint('md'); return ( From 624e61be80b74ba0308f2114803d33e42ae5851f Mon Sep 17 00:00:00 2001 From: Anton Shalimov Date: Fri, 19 Jul 2024 14:46:08 +0300 Subject: [PATCH 14/61] refactor: text color and margin --- features/rewards/components/stats/Item.tsx | 1 + features/rewards/components/stats/Stats.tsx | 6 +----- features/rewards/components/stats/Title.tsx | 1 - features/rewards/features/top-card/top-card.tsx | 1 + 4 files changed, 3 insertions(+), 6 deletions(-) diff --git a/features/rewards/components/stats/Item.tsx b/features/rewards/components/stats/Item.tsx index f47158b84..057337509 100644 --- a/features/rewards/components/stats/Item.tsx +++ b/features/rewards/components/stats/Item.tsx @@ -9,6 +9,7 @@ export const Item = ({ children, ...rest }: BoxProps) => ( width={['100%', '100%', 'initial']} display={['flex', 'flex', 'initial']} justifyContent={['space-between', 'space-between', null]} + marginBottom={['6px']} {...rest} > {children} diff --git a/features/rewards/components/stats/Stats.tsx b/features/rewards/components/stats/Stats.tsx index 9bff50b72..47e6c3b74 100644 --- a/features/rewards/components/stats/Stats.tsx +++ b/features/rewards/components/stats/Stats.tsx @@ -71,11 +71,7 @@ export const Stats: React.FC = () => { <Link href={`${config.rootOrigin}/ethereum#apr`}> - <Box - data-testid="moreInfo" - color="secondary" - style={{ textDecoration: 'underline' }} - > + <Box data-testid="moreInfo" style={{ textDecoration: 'underline' }}> More info </Box> </Link> diff --git a/features/rewards/components/stats/Title.tsx b/features/rewards/components/stats/Title.tsx index 14dd8176f..554af581b 100644 --- a/features/rewards/components/stats/Title.tsx +++ b/features/rewards/components/stats/Title.tsx @@ -8,7 +8,6 @@ type TitleProps = BoxProps & { // TODO: refactoring to style files export const Title = ({ children, hideMobile, ...rest }: TitleProps) => ( <Box - color="secondary" fontSize="14px" fontStyle="normal" fontWeight="normal" diff --git a/features/rewards/features/top-card/top-card.tsx b/features/rewards/features/top-card/top-card.tsx index c86ea39f2..548f441b7 100644 --- a/features/rewards/features/top-card/top-card.tsx +++ b/features/rewards/features/top-card/top-card.tsx @@ -18,6 +18,7 @@ export const TopCard: FC = () => { {!isDappActive && <Fallback />} {isDappActive && <Wallet />} + <StatsWrapper> <Stats /> </StatsWrapper> From 0d743557e1eb717209540829180c9ff9419e78f1 Mon Sep 17 00:00:00 2001 From: Anton Shalimov <a.shalimof@yandex.ru> Date: Tue, 30 Jul 2024 15:46:44 +0300 Subject: [PATCH 15/61] feat: add sepolia testnet --- .env.example | 5 +- config/get-secret-config.ts | 3 ++ config/user-config/types.ts | 1 + config/user-config/utils.ts | 1 + consts/chains.ts | 1 + consts/staking-router.ts | 1 + env-dynamics.mjs | 2 + global.d.ts | 2 + next.config.mjs | 2 + package.json | 12 ++--- utils/getNFTUrl.ts | 2 + utilsApi/getSubgraphUrl.ts | 1 + utilsApi/rpcUrls.ts | 1 + yarn.lock | 94 +++++++++++++++++++++++++------------ 14 files changed, 90 insertions(+), 38 deletions(-) diff --git a/.env.example b/.env.example index e207800ca..7377b198e 100644 --- a/.env.example +++ b/.env.example @@ -8,13 +8,15 @@ RESEARCH_ORIGIN=https://research.lido.fi # EL_RPC_URLS_{CHAIN_ID} list or URLs delimeted by commas, first entry is primary, else are fallbacks EL_RPC_URLS_1= EL_RPC_URLS_17000= +EL_RPC_URLS_11155111= # IPFS prefill RPC URLs - list of URLs delimited by commas PREFILL_UNSAFE_EL_RPC_URLS_1= PREFILL_UNSAFE_EL_RPC_URLS_17000= +PREFILL_UNSAFE_EL_RPC_URLS_11155111= # supported networks for connecting wallet -SUPPORTED_CHAINS=1,17000 +SUPPORTED_CHAINS=1,17000,11155111 # this chain uses when a wallet is not connected DEFAULT_CHAIN=1 @@ -35,6 +37,7 @@ CSP_REPORT_URI=https://stake.lido.fi/api/csp-report # Subgraph endpoint SUBGRAPH_MAINNET=https://gateway-arbitrum.network.thegraph.com/api/[api-key]/subgraphs/id/Sxx812XgeKyzQPaBpR5YZWmGV5fZuBaPdh7DFhzSwiQ SUBGRAPH_HOLESKY= +SUBGRAPH_SEPOLIA= SUBGRAPH_REQUEST_TIMEOUT=5000 diff --git a/config/get-secret-config.ts b/config/get-secret-config.ts index aa3e38d1b..5b5e692ac 100644 --- a/config/get-secret-config.ts +++ b/config/get-secret-config.ts @@ -10,6 +10,7 @@ export type SecretConfigType = Modify< rpcUrls_1: [string, ...string[]]; rpcUrls_17000: [string, ...string[]]; + rpcUrls_11155111: [string, ...string[]]; cspReportOnly: boolean; @@ -41,6 +42,8 @@ export const getSecretConfig = (): SecretConfigType => { string, ...string[], ], + rpcUrls_11155111: (serverRuntimeConfig.rpcUrls_11155111?.split(',') ?? + []) as [string, ...string[]], cspReportOnly: toBoolean(serverRuntimeConfig.cspReportOnly), diff --git a/config/user-config/types.ts b/config/user-config/types.ts index f4c09a4fc..6cfad9a69 100644 --- a/config/user-config/types.ts +++ b/config/user-config/types.ts @@ -6,6 +6,7 @@ export type UserConfigDefaultType = { prefillUnsafeElRpcUrls: { [CHAINS.Mainnet]: string[]; [CHAINS.Holesky]: string[]; + [CHAINS.Sepolia]: string[]; }; walletconnectProjectId: string | undefined; }; diff --git a/config/user-config/utils.ts b/config/user-config/utils.ts index bb8eaeb42..912411563 100644 --- a/config/user-config/utils.ts +++ b/config/user-config/utils.ts @@ -15,6 +15,7 @@ export const getUserConfigDefault = (): UserConfigDefaultType => { prefillUnsafeElRpcUrls: { [CHAINS.Mainnet]: config.prefillUnsafeElRpcUrls1, [CHAINS.Holesky]: config.prefillUnsafeElRpcUrls17000, + [CHAINS.Sepolia]: config.prefillUnsafeElRpcUrls11155111, }, walletconnectProjectId: config.walletconnectProjectId, }; diff --git a/consts/chains.ts b/consts/chains.ts index e6aa044f4..6a2458ac8 100644 --- a/consts/chains.ts +++ b/consts/chains.ts @@ -1,6 +1,7 @@ export enum CHAINS { Mainnet = 1, Holesky = 17000, + Sepolia = 11155111, } export enum L2_CHAINS { diff --git a/consts/staking-router.ts b/consts/staking-router.ts index 8cd8c95e1..3e16c4874 100644 --- a/consts/staking-router.ts +++ b/consts/staking-router.ts @@ -9,6 +9,7 @@ export const STAKING_ROUTER_BY_NETWORK: { } = { [CHAINS.Mainnet]: '0xFdDf38947aFB03C621C71b06C9C70bce73f12999', [CHAINS.Holesky]: '0xd6EbF043D30A7fe46D1Db32BA90a0A51207FE229', + [CHAINS.Sepolia]: '0x4F36aAEb18Ab56A4e380241bea6ebF215b9cb12c', }; export const getStakingRouterAddress = (chainId: CHAINS): string => { diff --git a/env-dynamics.mjs b/env-dynamics.mjs index d4588481e..4f761658a 100644 --- a/env-dynamics.mjs +++ b/env-dynamics.mjs @@ -50,6 +50,8 @@ export const supportedChains = process.env?.SUPPORTED_CHAINS?.split(',').map( export const prefillUnsafeElRpcUrls1 = process.env.PREFILL_UNSAFE_EL_RPC_URLS_1?.split(',') ?? []; /** @type string[] */ export const prefillUnsafeElRpcUrls17000 = process.env.PREFILL_UNSAFE_EL_RPC_URLS_17000?.split(',') ?? []; +/** @type string[] */ +export const prefillUnsafeElRpcUrls11155111 = process.env.PREFILL_UNSAFE_EL_RPC_URLS_11155111?.split(',') ?? []; /** @type boolean */ export const enableQaHelpers = toBoolean(process.env.ENABLE_QA_HELPERS); diff --git a/global.d.ts b/global.d.ts index 4c3724bb7..0407c995b 100644 --- a/global.d.ts +++ b/global.d.ts @@ -27,6 +27,7 @@ declare module 'next/config' { defaultChain: string; rpcUrls_1: string | undefined; rpcUrls_17000: string | undefined; + rpcUrls_11155111: string | undefined; ethplorerApiKey: string | undefined; oneInchApiKey: string | undefined; @@ -37,6 +38,7 @@ declare module 'next/config' { subgraphMainnet: string | undefined; subgraphHolesky: string | undefined; + subgraphSepolia: string | undefined; subgraphRequestTimeout: string | undefined; rateLimit: string; diff --git a/next.config.mjs b/next.config.mjs index 85e9475c4..7e1cb191f 100644 --- a/next.config.mjs +++ b/next.config.mjs @@ -145,6 +145,7 @@ export default withBundleAnalyzer({ defaultChain: process.env.DEFAULT_CHAIN, rpcUrls_1: process.env.EL_RPC_URLS_1, rpcUrls_17000: process.env.EL_RPC_URLS_17000, + rpcUrls_11155111: process.env.EL_RPC_URLS_11155111, ethplorerApiKey: process.env.ETHPLORER_API_KEY, oneInchApiKey: process.env.ONE_INCH_API_KEY, @@ -155,6 +156,7 @@ export default withBundleAnalyzer({ subgraphMainnet: process.env.SUBGRAPH_MAINNET, subgraphHolesky: process.env.SUBGRAPH_HOLESKY, + subgraphSepolia: process.env.SUBGRAPH_SEPOLIA, subgraphRequestTimeout: process.env.SUBGRAPH_REQUEST_TIMEOUT, rateLimit: process.env.RATE_LIMIT, diff --git a/package.json b/package.json index e53d76cea..c8f9f1612 100644 --- a/package.json +++ b/package.json @@ -27,12 +27,12 @@ "@ethersproject/contracts": "^5.7.0", "@ethersproject/providers": "^5.7.0", "@ethersproject/units": "^5.7.0", - "@lido-sdk/constants": "^3.2.1", - "@lido-sdk/contracts": "^3.0.4", - "@lido-sdk/fetch": "^2.1.12", - "@lido-sdk/helpers": "^1.5.1", - "@lido-sdk/providers": "^1.4.14", - "@lido-sdk/react": "^2.0.5", + "@lido-sdk/constants": "^3.3.0", + "@lido-sdk/contracts": "^3.0.5", + "@lido-sdk/fetch": "^2.2.0", + "@lido-sdk/helpers": "^1.6.0", + "@lido-sdk/providers": "^1.4.15", + "@lido-sdk/react": "^2.0.6", "@lidofinance/analytics-matomo": "^0.41.0", "@lidofinance/api-metrics": "^0.41.0", "@lidofinance/api-rpc": "^0.41.0", diff --git a/utils/getNFTUrl.ts b/utils/getNFTUrl.ts index 05ac9df64..b7de349a3 100644 --- a/utils/getNFTUrl.ts +++ b/utils/getNFTUrl.ts @@ -7,6 +7,8 @@ export const NFT_URL_PREFIX_BY_NETWORK: { `https://etherscan.io/nft/${contract}/${nftId}`, [CHAINS.Holesky]: (nftId, contract) => `https://holesky.etherscan.io/nft/${contract}/${nftId}`, + [CHAINS.Sepolia]: (nftId, contract) => + `https://sepolia.etherscan.io/nft/${contract}/${nftId}`, }; export const getNFTUrl = (tokenId: string, chainId?: CHAINS) => { diff --git a/utilsApi/getSubgraphUrl.ts b/utilsApi/getSubgraphUrl.ts index 566141251..531bcf8dc 100644 --- a/utilsApi/getSubgraphUrl.ts +++ b/utilsApi/getSubgraphUrl.ts @@ -5,6 +5,7 @@ import { SubgraphChains } from 'types'; export const SUBGRAPH_URL = { [CHAINS.Mainnet]: secretConfig.subgraphMainnet, [CHAINS.Holesky]: secretConfig.subgraphHolesky, + [CHAINS.Sepolia]: secretConfig.subgraphSepolia, } as const; export const getSubgraphUrl = (chainId: SubgraphChains): string | undefined => { diff --git a/utilsApi/rpcUrls.ts b/utilsApi/rpcUrls.ts index 7bdee28d8..c3ca01a0b 100644 --- a/utilsApi/rpcUrls.ts +++ b/utilsApi/rpcUrls.ts @@ -4,4 +4,5 @@ import { secretConfig } from 'config'; export const rpcUrls: Record<CHAINS, [string, ...string[]]> = { [CHAINS.Mainnet]: secretConfig.rpcUrls_1, [CHAINS.Holesky]: secretConfig.rpcUrls_17000, + [CHAINS.Sepolia]: secretConfig.rpcUrls_11155111, }; diff --git a/yarn.lock b/yarn.lock index 931fea377..98b03a9a7 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2110,53 +2110,53 @@ bignumber.js "^9.1.2" rxjs "^7.8.1" -"@lido-sdk/constants@3.2.1", "@lido-sdk/constants@^3.2.1": - version "3.2.1" - resolved "https://registry.yarnpkg.com/@lido-sdk/constants/-/constants-3.2.1.tgz#0c4582d7e76e4f8bc42e8f3c0d14dc0fbe481d77" - integrity sha512-zes0Mw0r1nEQYBNHV5fxK2H9Byowejy4haFy9LYDh1nL72aNJzzdh5S5iM+pKlEuLHQJHV5lVO/k9tunNJIKqQ== +"@lido-sdk/constants@3.3.0", "@lido-sdk/constants@^3.3.0": + version "3.3.0" + resolved "https://registry.yarnpkg.com/@lido-sdk/constants/-/constants-3.3.0.tgz#044b652a000a067b9ee0ae9f58814434779bb108" + integrity sha512-R5XINgj/EQvyBfPF+Zv9B/ycFCqARD8rbWDp3J4luAMDbSUP3ncGw0x7Aj836k96eVnrh+jfd2tz/c99Dm6IaA== dependencies: tiny-invariant "^1.1.0" -"@lido-sdk/contracts@3.0.4", "@lido-sdk/contracts@^3.0.4": - version "3.0.4" - resolved "https://registry.yarnpkg.com/@lido-sdk/contracts/-/contracts-3.0.4.tgz#85e3b203aa0a38841ecf22d7ac4e5f8d70848920" - integrity sha512-oW7gyHKcrss77sEPMmYm38M0CQ5+3GGlNewu9D+UJhtxRpLa+Jh3nWEd5tq/hMdMSN9cGoerVKFfBAhw6zKajg== +"@lido-sdk/contracts@3.0.5", "@lido-sdk/contracts@^3.0.5": + version "3.0.5" + resolved "https://registry.yarnpkg.com/@lido-sdk/contracts/-/contracts-3.0.5.tgz#9778e83258de241e26bcd5c76589ff010856afbb" + integrity sha512-piu5wKqxs9QS85qG9OrwXfdg5ZCg+xlggj6Q8PMo9qbAk0UzBVuU7CcXUalpKeJpTQMV4SnvcJ0dwZNR2weK8g== dependencies: - "@lido-sdk/constants" "3.2.1" + "@lido-sdk/constants" "3.3.0" tiny-invariant "^1.1.0" -"@lido-sdk/fetch@^2.1.12": - version "2.1.12" - resolved "https://registry.yarnpkg.com/@lido-sdk/fetch/-/fetch-2.1.12.tgz#aa0ef16212f4bad7ffed68928143e7cbdab94973" - integrity sha512-kFBrzCVxYnD3Q68cM4KY9E7w/4TAJk1BW2wAcPpJyWm1yQSRL1urhEZ6NGbwkp23QvayVStbNrQiezVOdDnzYw== +"@lido-sdk/fetch@^2.2.0": + version "2.2.0" + resolved "https://registry.yarnpkg.com/@lido-sdk/fetch/-/fetch-2.2.0.tgz#e0034083edaed471f29163ebfdccc9b10cd58ea7" + integrity sha512-Jwi2W5azP4uuhmsWexkk4al0Y+pMx5PpB74klIBzgX/eoVnK+NOTxLemJa6GDq4KTIlriAM79jscY0TJvJJWQA== dependencies: - "@lido-sdk/constants" "3.2.1" + "@lido-sdk/constants" "3.3.0" node-fetch "^2.6.7" tiny-invariant "^1.1.0" -"@lido-sdk/helpers@1.5.1", "@lido-sdk/helpers@^1.5.1": - version "1.5.1" - resolved "https://registry.yarnpkg.com/@lido-sdk/helpers/-/helpers-1.5.1.tgz#ced13f1df6e34a1d4ad551fde299524dc237b694" - integrity sha512-n8sTliverpxOy7PeTCUyG+bQPIJdg57AOON+6X2tZ19JxU3r6ZhHzo33x/9022aKu0A/Ya7edREDB6MadymdRg== +"@lido-sdk/helpers@1.6.0", "@lido-sdk/helpers@^1.6.0": + version "1.6.0" + resolved "https://registry.yarnpkg.com/@lido-sdk/helpers/-/helpers-1.6.0.tgz#551cde8aa1251b310d4e1f93f7ec12680992c639" + integrity sha512-rg8sV7l3SWebx8tiagaDf+Q1F+UfgZ2FS31NDPzBUtG++QKP+9V1hTOrpwLNsmJhqQ0zbNhm84+ykHbCmEO+Cw== dependencies: - "@lido-sdk/constants" "3.2.1" + "@lido-sdk/constants" "3.3.0" tiny-invariant "^1.1.0" -"@lido-sdk/providers@^1.4.14": - version "1.4.14" - resolved "https://registry.yarnpkg.com/@lido-sdk/providers/-/providers-1.4.14.tgz#b7c714aa753d662c0d51f71ee4990b3cb78ce790" - integrity sha512-m422uXuaGoXoUlF8oyFTIQsj8ljVet/x7nK0xF8UoURm/iuaAhTbEXpcxhmkx8JSSDli1928apJRAwxG0McgnQ== +"@lido-sdk/providers@^1.4.15": + version "1.4.15" + resolved "https://registry.yarnpkg.com/@lido-sdk/providers/-/providers-1.4.15.tgz#2640afbd247cff90952d6710888d8b6a3c2ad0cd" + integrity sha512-155BlcEgKWFlC17itMAeflhfRnF+ejrRUOONfexgIzjcOtam+PB1WNLzpXj8zkhcLbuMW11zYJ0cfIc4QsToag== dependencies: - "@lido-sdk/constants" "3.2.1" + "@lido-sdk/constants" "3.3.0" -"@lido-sdk/react@^2.0.5": - version "2.0.5" - resolved "https://registry.yarnpkg.com/@lido-sdk/react/-/react-2.0.5.tgz#13496354863bcd98f78cf223ac65254e9620419a" - integrity sha512-XRrO1Zg13IJO0TKhqT/TBJYTWuZg+2+8T+FPmegxwe7mfJSrg025lhtRPW8cjLHvPvVsW6RVgV/vW9iIeHvYpA== +"@lido-sdk/react@^2.0.6": + version "2.0.6" + resolved "https://registry.yarnpkg.com/@lido-sdk/react/-/react-2.0.6.tgz#f1a245803eb7136f396ceff695a598b0c92056dd" + integrity sha512-4Gwnl+6v/3JS6yyfbyyJj4P/r6slcfW8GESSl5XvPQcK3T/Jt54MN3vIv1tmFyPr1RM/vxtiR4doR+jKEItadA== dependencies: - "@lido-sdk/constants" "3.2.1" - "@lido-sdk/contracts" "3.0.4" - "@lido-sdk/helpers" "1.5.1" + "@lido-sdk/constants" "3.3.0" + "@lido-sdk/contracts" "3.0.5" + "@lido-sdk/helpers" "1.6.0" swr "^1.0.1" tiny-invariant "^1.1.0" tiny-warning "^1.0.3" @@ -3833,6 +3833,7 @@ eventemitter3 "5.0.1" mipd "0.0.5" zustand "4.4.1" + "@walletconnect/core@2.13.0": version "2.13.0" resolved "https://registry.yarnpkg.com/@walletconnect/core/-/core-2.13.0.tgz#6b79b039930643e8ee85a0f512b143a35fdb8b52" @@ -4122,6 +4123,11 @@ JSONStream@^1.3.5: jsonparse "^1.2.0" through ">=2.2.7 <3" +abitype@0.9.8: + version "0.9.8" + resolved "https://registry.yarnpkg.com/abitype/-/abitype-0.9.8.tgz#1f120b6b717459deafd213dfbf3a3dd1bf10ae8c" + integrity sha512-puLifILdm+8sjyss4S+fsUN09obiT1g2YW6CtcQF+QDzxR0euzgEB29MZujC6zMk2a6SVmtttq1fc6+YFA7WYQ== + abitype@1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/abitype/-/abitype-1.0.0.tgz#237176dace81d90d018bebf3a45cb42f2a2d9e97" @@ -7252,6 +7258,11 @@ isomorphic-unfetch@3.1.0: node-fetch "^2.6.1" unfetch "^4.2.0" +isows@1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/isows/-/isows-1.0.3.tgz#93c1cf0575daf56e7120bab5c8c448b0809d0d74" + integrity sha512-2cKei4vlmg2cxEjm3wVSqn8pcoRF/LX/wpifuuNquFO4SQmPwarClT+SUCA2lt+l581tTeZIPIZuIDo2jWN1fg== + isows@1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/isows/-/isows-1.0.4.tgz#810cd0d90cc4995c26395d2aa4cfa4037ebdf061" @@ -8392,6 +8403,13 @@ minimist@^1.2.0, minimist@^1.2.6: resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.8.tgz#c1a464e7693302e082a075cee0c057741ac4772c" integrity sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA== +mipd@0.0.5: + version "0.0.5" + resolved "https://registry.yarnpkg.com/mipd/-/mipd-0.0.5.tgz#367ee796531c23f0631f129038700b1406663aec" + integrity sha512-gbKA784D2WKb5H/GtqEv+Ofd1S9Zj+Z/PGDIl1u1QAbswkxD28BQ5bSXQxkeBzPBABg1iDSbiwGG1XqlOxRspA== + dependencies: + viem "^1.1.4" + mipd@0.0.7: version "0.0.7" resolved "https://registry.yarnpkg.com/mipd/-/mipd-0.0.7.tgz#bb5559e21fa18dc3d9fe1c08902ef14b7ce32fd9" @@ -10937,6 +10955,20 @@ viem@2.13.3: isows "1.0.4" ws "8.13.0" +viem@^1.1.4: + version "1.21.4" + resolved "https://registry.yarnpkg.com/viem/-/viem-1.21.4.tgz#883760e9222540a5a7e0339809202b45fe6a842d" + integrity sha512-BNVYdSaUjeS2zKQgPs+49e5JKocfo60Ib2yiXOWBT6LuVxY1I/6fFX3waEtpXvL1Xn4qu+BVitVtMh9lyThyhQ== + dependencies: + "@adraffy/ens-normalize" "1.10.0" + "@noble/curves" "1.2.0" + "@noble/hashes" "1.3.2" + "@scure/bip32" "1.3.2" + "@scure/bip39" "1.2.1" + abitype "0.9.8" + isows "1.0.3" + ws "8.13.0" + viem@^2.1.1: version "2.17.9" resolved "https://registry.yarnpkg.com/viem/-/viem-2.17.9.tgz#40ffd00a31621c8efdc4d49a58d5d30dc2d38d83" From 956f6c6c59ab080e2588ef83f6cf7a0f9609a804 Mon Sep 17 00:00:00 2001 From: Dmitrii Podlesnyi <rezed93@gmail.com> Date: Wed, 31 Jul 2024 16:19:17 +0700 Subject: [PATCH 16/61] feat: browser wallet and show more/less wallets metric events --- consts/matomo-click-events.ts | 12 +++++ consts/matomo-wallets-events.ts | 18 +++++++ package.json | 2 +- .../connect-wallet-modal.tsx | 8 +++ yarn.lock | 50 +++++++++++++++---- 5 files changed, 80 insertions(+), 10 deletions(-) diff --git a/consts/matomo-click-events.ts b/consts/matomo-click-events.ts index 4d72e7c8d..7dd2afba3 100644 --- a/consts/matomo-click-events.ts +++ b/consts/matomo-click-events.ts @@ -3,6 +3,8 @@ import { MatomoEventType } from '@lidofinance/analytics-matomo'; export const enum MATOMO_CLICK_EVENTS_TYPES { // Global connectWallet = 'connectWallet', + clickShowMoreWallets = 'clickShowMoreWallets', + clickShowLessWallets = 'clickShowLessWallets', clickCurvePool = 'clickCurvePool', clickBalancerPool = 'clickBalancerPool', clickExploreDeFi = 'clickExploreDeFi', @@ -79,6 +81,16 @@ export const MATOMO_CLICK_EVENTS: Record< 'Push "Connect wallet" button', 'eth_widget_connect_wallet', ], + [MATOMO_CLICK_EVENTS_TYPES.clickShowMoreWallets]: [ + 'Ethereum_Staking_Widget', + 'Push "More wallets" on wallet modal', + 'eth_widget_more_wallets', + ], + [MATOMO_CLICK_EVENTS_TYPES.clickShowLessWallets]: [ + 'Ethereum_Staking_Widget', + 'Push "Less wallets" on wallet modal', + 'eth_widget_less_wallets', + ], [MATOMO_CLICK_EVENTS_TYPES.clickCurvePool]: [ 'Ethereum_Staking_Widget', 'Push «Explore» in Curve section on Transaction success banner', diff --git a/consts/matomo-wallets-events.ts b/consts/matomo-wallets-events.ts index 7fd3e6572..18e8a500d 100644 --- a/consts/matomo-wallets-events.ts +++ b/consts/matomo-wallets-events.ts @@ -29,6 +29,8 @@ export const enum MATOMO_WALLETS_EVENTS_TYPES { onConnectOkx = 'onConnectOkx', onClickBitget = 'onClickBitget', onConnectBitget = 'onConnectBitget', + onClickBrowser = 'onClickBrowser', + onConnectBrowser = 'onConnectBrowser', } export const MATOMO_WALLETS_EVENTS: Record< @@ -165,6 +167,16 @@ export const MATOMO_WALLETS_EVENTS: Record< 'Connect BitGet wallet', 'eth_widget_connect_bitget', ], + [MATOMO_WALLETS_EVENTS_TYPES.onClickBrowser]: [ + 'Ethereum_Staking_Widget', + 'Click Browser wallet', + 'eth_widget_click_browser', + ], + [MATOMO_WALLETS_EVENTS_TYPES.onConnectBrowser]: [ + 'Ethereum_Staking_Widget', + 'Connect Browser wallet', + 'eth_widget_connect_browser', + ], }; const getMetricHandler = (event: Parameters<typeof trackEvent>) => () => @@ -187,6 +199,9 @@ export const walletsMetrics: Metrics<WalletIdsEthereum> = { xdefi: getMetricHandler(MATOMO_WALLETS_EVENTS.onClickXdefi), okx: getMetricHandler(MATOMO_WALLETS_EVENTS.onClickOkx), bitget: getMetricHandler(MATOMO_WALLETS_EVENTS.onClickBitget), + browserExtension: getMetricHandler( + MATOMO_WALLETS_EVENTS.onClickBrowser, + ), }, }, connect: { @@ -204,6 +219,9 @@ export const walletsMetrics: Metrics<WalletIdsEthereum> = { xdefi: getMetricHandler(MATOMO_WALLETS_EVENTS.onConnectXdefi), okx: getMetricHandler(MATOMO_WALLETS_EVENTS.onConnectOkx), bitget: getMetricHandler(MATOMO_WALLETS_EVENTS.onConnectBitget), + browserExtension: getMetricHandler( + MATOMO_WALLETS_EVENTS.onConnectBrowser, + ), }, }, }, diff --git a/package.json b/package.json index e53d76cea..ad92ad829 100644 --- a/package.json +++ b/package.json @@ -69,7 +69,7 @@ "react-hook-form": "^7.45.2", "react-is": "^18.2.0", "react-transition-group": "^4.4.2", - "reef-knot": "5.2.1", + "reef-knot": "5.2.3", "remark": "^13.0.0", "remark-external-links": "^8.0.0", "remark-html": "^13.0.1", diff --git a/shared/wallet/connect-wallet-modal/connect-wallet-modal.tsx b/shared/wallet/connect-wallet-modal/connect-wallet-modal.tsx index 56dfe19a6..b2fe8b02d 100644 --- a/shared/wallet/connect-wallet-modal/connect-wallet-modal.tsx +++ b/shared/wallet/connect-wallet-modal/connect-wallet-modal.tsx @@ -4,6 +4,8 @@ import { WalletIdsEthereum } from 'reef-knot/wallets'; import { config } from 'config'; import { walletsMetrics } from 'consts/matomo-wallets-events'; +import { trackEvent } from '@lidofinance/analytics-matomo'; +import { MATOMO_CLICK_EVENTS } from 'consts/matomo-click-events'; const WALLETS_PINNED: WalletIdsEthereum[] = ['okx', 'browserExtension']; @@ -17,6 +19,12 @@ export const ConnectWalletModal = () => { walletsPinned={WALLETS_PINNED} termsLink={`${config.rootOrigin}/terms-of-use`} privacyNoticeLink={`${config.rootOrigin}/privacy-notice`} + onClickWalletsMore={() => + trackEvent(...MATOMO_CLICK_EVENTS.clickShowMoreWallets) + } + onClickWalletsLess={() => + trackEvent(...MATOMO_CLICK_EVENTS.clickShowLessWallets) + } /> ); }; diff --git a/yarn.lock b/yarn.lock index 931fea377..e40811c91 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2734,10 +2734,10 @@ resolved "https://registry.yarnpkg.com/@polka/url/-/url-1.0.0-next.24.tgz#58601079e11784d20f82d0585865bb42305c4df3" integrity sha512-2LuNTFBIO0m7kKIQvvPHN6UE63VjpmL9rnEEaOOaiSPbZK+zUOYIzBAWcED+3XYzhYsd/0mD57VdxAEqqV52CQ== -"@reef-knot/connect-wallet-modal@5.2.0": - version "5.2.0" - resolved "https://registry.yarnpkg.com/@reef-knot/connect-wallet-modal/-/connect-wallet-modal-5.2.0.tgz#762d3b570b58405a6050b49eb16dbab5af009ab0" - integrity sha512-V75YfqrwHUrKWyo1McyuoMTFbGg/xFcc7pQSiQMxl1eRGBjL8nxtxj0Uj2Zv/3remCBCIq4VTP2J3DiGZQnUiw== +"@reef-knot/connect-wallet-modal@5.2.2": + version "5.2.2" + resolved "https://registry.yarnpkg.com/@reef-knot/connect-wallet-modal/-/connect-wallet-modal-5.2.2.tgz#519377324db27a4570df2801aa0c113dadad3d0a" + integrity sha512-0ZT7bjFnuSa2dfWcV4yLouInMnWV9gy/CVsETKxTdU5u7wjOU1l2KnaGrSZCctTi3OxkJFkDI0uimApPnhF/Uw== dependencies: "@ledgerhq/hw-app-eth" "^6.37.1" "@ledgerhq/hw-transport" "^6.31.0" @@ -3833,6 +3833,7 @@ eventemitter3 "5.0.1" mipd "0.0.5" zustand "4.4.1" + "@walletconnect/core@2.13.0": version "2.13.0" resolved "https://registry.yarnpkg.com/@walletconnect/core/-/core-2.13.0.tgz#6b79b039930643e8ee85a0f512b143a35fdb8b52" @@ -4122,6 +4123,11 @@ JSONStream@^1.3.5: jsonparse "^1.2.0" through ">=2.2.7 <3" +abitype@0.9.8: + version "0.9.8" + resolved "https://registry.yarnpkg.com/abitype/-/abitype-0.9.8.tgz#1f120b6b717459deafd213dfbf3a3dd1bf10ae8c" + integrity sha512-puLifILdm+8sjyss4S+fsUN09obiT1g2YW6CtcQF+QDzxR0euzgEB29MZujC6zMk2a6SVmtttq1fc6+YFA7WYQ== + abitype@1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/abitype/-/abitype-1.0.0.tgz#237176dace81d90d018bebf3a45cb42f2a2d9e97" @@ -7252,6 +7258,11 @@ isomorphic-unfetch@3.1.0: node-fetch "^2.6.1" unfetch "^4.2.0" +isows@1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/isows/-/isows-1.0.3.tgz#93c1cf0575daf56e7120bab5c8c448b0809d0d74" + integrity sha512-2cKei4vlmg2cxEjm3wVSqn8pcoRF/LX/wpifuuNquFO4SQmPwarClT+SUCA2lt+l581tTeZIPIZuIDo2jWN1fg== + isows@1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/isows/-/isows-1.0.4.tgz#810cd0d90cc4995c26395d2aa4cfa4037ebdf061" @@ -8392,6 +8403,13 @@ minimist@^1.2.0, minimist@^1.2.6: resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.8.tgz#c1a464e7693302e082a075cee0c057741ac4772c" integrity sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA== +mipd@0.0.5: + version "0.0.5" + resolved "https://registry.yarnpkg.com/mipd/-/mipd-0.0.5.tgz#367ee796531c23f0631f129038700b1406663aec" + integrity sha512-gbKA784D2WKb5H/GtqEv+Ofd1S9Zj+Z/PGDIl1u1QAbswkxD28BQ5bSXQxkeBzPBABg1iDSbiwGG1XqlOxRspA== + dependencies: + viem "^1.1.4" + mipd@0.0.7: version "0.0.7" resolved "https://registry.yarnpkg.com/mipd/-/mipd-0.0.7.tgz#bb5559e21fa18dc3d9fe1c08902ef14b7ce32fd9" @@ -9390,12 +9408,12 @@ redis-parser@^3.0.0: dependencies: redis-errors "^1.0.0" -reef-knot@5.2.1: - version "5.2.1" - resolved "https://registry.yarnpkg.com/reef-knot/-/reef-knot-5.2.1.tgz#18a7aa8817896d951d88d0a8212af91c12d65de4" - integrity sha512-3iZRohLSziJXrSqcA9bfGtrAqy3w+gmFlnrDEX7ryTpje1M7aksNZU/Y91AYxZJB0xv3Lv+5+2A/hhijYffSKA== +reef-knot@5.2.3: + version "5.2.3" + resolved "https://registry.yarnpkg.com/reef-knot/-/reef-knot-5.2.3.tgz#23554c91828454048889d7107aeb859089fb6581" + integrity sha512-L7cWKM+UNZpPGbGzraW6aoZZB3qyqOy7RU4Yic/54hHb63QOhD5f1cNnUi8mVAI2d+s/vrSCLznR1aLuf4RghA== dependencies: - "@reef-knot/connect-wallet-modal" "5.2.0" + "@reef-knot/connect-wallet-modal" "5.2.2" "@reef-knot/core-react" "4.1.1" "@reef-knot/ledger-connector" "4.1.0" "@reef-knot/types" "2.0.1" @@ -10937,6 +10955,20 @@ viem@2.13.3: isows "1.0.4" ws "8.13.0" +viem@^1.1.4: + version "1.21.4" + resolved "https://registry.yarnpkg.com/viem/-/viem-1.21.4.tgz#883760e9222540a5a7e0339809202b45fe6a842d" + integrity sha512-BNVYdSaUjeS2zKQgPs+49e5JKocfo60Ib2yiXOWBT6LuVxY1I/6fFX3waEtpXvL1Xn4qu+BVitVtMh9lyThyhQ== + dependencies: + "@adraffy/ens-normalize" "1.10.0" + "@noble/curves" "1.2.0" + "@noble/hashes" "1.3.2" + "@scure/bip32" "1.3.2" + "@scure/bip39" "1.2.1" + abitype "0.9.8" + isows "1.0.3" + ws "8.13.0" + viem@^2.1.1: version "2.17.9" resolved "https://registry.yarnpkg.com/viem/-/viem-2.17.9.tgz#40ffd00a31621c8efdc4d49a58d5d30dc2d38d83" From addae41bc267de0818e3742e607b9c8bf67fe62e Mon Sep 17 00:00:00 2001 From: Anton Shalimov <a.shalimof@yandex.ru> Date: Wed, 31 Jul 2024 13:47:43 +0300 Subject: [PATCH 17/61] refactor(rewards page): move to stETH balance --- .../description-about-rounding-block.tsx | 13 ++++ .../description-about-rounding-block/index.ts | 1 + .../styles.ts} | 5 +- .../inputDescription/InputDescription.tsx | 7 -- .../components/inputDescription/index.ts | 1 - features/rewards/components/stats/Stats.tsx | 22 ------- features/rewards/features/top-card/styles.tsx | 11 ++-- features/rewards/features/top-card/wallet.tsx | 65 +++++++++++++++---- pages/rewards.tsx | 5 -- 9 files changed, 73 insertions(+), 57 deletions(-) create mode 100644 features/rewards/components/description-about-rounding-block/description-about-rounding-block.tsx create mode 100644 features/rewards/components/description-about-rounding-block/index.ts rename features/rewards/components/{inputDescription/InputDescriptionStyles.ts => description-about-rounding-block/styles.ts} (75%) delete mode 100644 features/rewards/components/inputDescription/InputDescription.tsx delete mode 100644 features/rewards/components/inputDescription/index.ts diff --git a/features/rewards/components/description-about-rounding-block/description-about-rounding-block.tsx b/features/rewards/components/description-about-rounding-block/description-about-rounding-block.tsx new file mode 100644 index 000000000..7a8c53850 --- /dev/null +++ b/features/rewards/components/description-about-rounding-block/description-about-rounding-block.tsx @@ -0,0 +1,13 @@ +import { FC, PropsWithChildren } from 'react'; + +import { DescriptionAboutRoundingBlockStyled } from './styles'; + +export const DescriptionAboutRoundingBlock: FC<PropsWithChildren> = ({ + children, +}) => { + return ( + <DescriptionAboutRoundingBlockStyled> + {children} + </DescriptionAboutRoundingBlockStyled> + ); +}; diff --git a/features/rewards/components/description-about-rounding-block/index.ts b/features/rewards/components/description-about-rounding-block/index.ts new file mode 100644 index 000000000..bca33dde5 --- /dev/null +++ b/features/rewards/components/description-about-rounding-block/index.ts @@ -0,0 +1 @@ +export * from './description-about-rounding-block'; diff --git a/features/rewards/components/inputDescription/InputDescriptionStyles.ts b/features/rewards/components/description-about-rounding-block/styles.ts similarity index 75% rename from features/rewards/components/inputDescription/InputDescriptionStyles.ts rename to features/rewards/components/description-about-rounding-block/styles.ts index 1dca41906..3d42d0bb4 100644 --- a/features/rewards/components/inputDescription/InputDescriptionStyles.ts +++ b/features/rewards/components/description-about-rounding-block/styles.ts @@ -1,9 +1,9 @@ import styled from 'styled-components'; -export const WrapperStyle = styled.div` +export const DescriptionAboutRoundingBlockStyled = styled.div` flex: 1; padding: ${({ theme }) => theme.spaceMap.sm}px; - margin-right: ${({ theme }) => theme.spaceMap.xl}px; + margin-top: ${({ theme }) => theme.spaceMap.md}px; border-radius: ${({ theme }) => theme.spaceMap.sm}px; @@ -12,7 +12,6 @@ export const WrapperStyle = styled.div` text-align: center; ${({ theme }) => theme.mediaQueries.md} { - margin-right: 0; margin-top: ${({ theme }) => theme.spaceMap.xl}px; } `; diff --git a/features/rewards/components/inputDescription/InputDescription.tsx b/features/rewards/components/inputDescription/InputDescription.tsx deleted file mode 100644 index a20fa44dc..000000000 --- a/features/rewards/components/inputDescription/InputDescription.tsx +++ /dev/null @@ -1,7 +0,0 @@ -import { FC, PropsWithChildren } from 'react'; - -import { WrapperStyle } from './InputDescriptionStyles'; - -export const InputDescription: FC<PropsWithChildren> = ({ children }) => { - return <WrapperStyle>{children}</WrapperStyle>; -}; diff --git a/features/rewards/components/inputDescription/index.ts b/features/rewards/components/inputDescription/index.ts deleted file mode 100644 index 264c3cb95..000000000 --- a/features/rewards/components/inputDescription/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './InputDescription'; diff --git a/features/rewards/components/stats/Stats.tsx b/features/rewards/components/stats/Stats.tsx index 47e6c3b74..1a2019a4a 100644 --- a/features/rewards/components/stats/Stats.tsx +++ b/features/rewards/components/stats/Stats.tsx @@ -5,7 +5,6 @@ import { useRewardsHistory } from 'features/rewards/hooks'; import EthSymbol from 'features/rewards/components/EthSymbol'; import NumberFormat from 'features/rewards/components/NumberFormat'; import { useStethEthRate } from 'features/rewards/hooks/use-steth-eth-rate'; -import { useRewardsBalanceData } from 'features/rewards/hooks/use-rewards-balance-data'; import { Item } from './Item'; import { Stat } from './Stat'; @@ -19,30 +18,9 @@ export const Stats: React.FC = () => { initialLoading: pending, } = useRewardsHistory(); const { data: stEthEth } = useStethEthRate(); - const { data: balanceData } = useRewardsBalanceData(); return ( <> - <Item data-testid="stEthBalanceBlock"> - <Title mb="8px">stETH balance - - - - - - <Box display="inline-block" pr="3px"> - {currency.symbol} - </Box> - <NumberFormat - number={balanceData?.stEthCurrencyBalance} - currency - pending={pending} - /> - - stETH rewarded diff --git a/features/rewards/features/top-card/styles.tsx b/features/rewards/features/top-card/styles.tsx index 29d7e119d..42fd5e65e 100644 --- a/features/rewards/features/top-card/styles.tsx +++ b/features/rewards/features/top-card/styles.tsx @@ -13,18 +13,15 @@ export const WalletStyle = styled(WalletCardStyle)` `; export const WalletContentStyle = styled.div` + padding: ${({ theme }) => theme.spaceMap.xxl}px; +`; + +export const WalletContentRowStyle = styled.div` display: flex; flex-wrap: nowrap; flex-direction: row; align-items: center; justify-content: space-between; - - padding: ${({ theme }) => theme.spaceMap.xxl}px; - - ${({ theme }) => theme.mediaQueries.md} { - align-items: end; - flex-direction: column-reverse; - } `; export const WalletContentAddressBadgeStyle = styled(AddressBadge)` diff --git a/features/rewards/features/top-card/wallet.tsx b/features/rewards/features/top-card/wallet.tsx index 53ec384ec..41059a52c 100644 --- a/features/rewards/features/top-card/wallet.tsx +++ b/features/rewards/features/top-card/wallet.tsx @@ -1,31 +1,72 @@ import { FC } from 'react'; -import { ThemeProvider, themeDark } from '@lidofinance/lido-ui'; +import { Box, ThemeProvider, themeDark } from '@lidofinance/lido-ui'; -import { InputDescription } from 'features/rewards/components/inputDescription'; +import EthSymbol from 'features/rewards/components/EthSymbol'; +import NumberFormat from 'features/rewards/components/NumberFormat'; +import { Title } from 'features/rewards/components/stats/Title'; +import { DescriptionAboutRoundingBlock } from 'features/rewards/components/description-about-rounding-block'; import { useRewardsHistory } from 'features/rewards/hooks'; +import { useRewardsBalanceData } from 'features/rewards/hooks/use-rewards-balance-data'; +import { FlexCenter } from 'features/stake/stake-form/wallet/styles'; +import { CardBalance } from 'shared/wallet'; import { WalletStyle, WalletContentStyle, WalletContentAddressBadgeStyle, + WalletContentRowStyle, } from './styles'; -const INPUT_DESC_TEXT = - 'Current balance may differ from last balance in the table due to rounding.'; - export const Wallet: FC = () => { - const { address } = useRewardsHistory(); + const { data: balanceData } = useRewardsBalanceData(); + const { currencyObject: currency, address, loading } = useRewardsHistory(); return ( - {INPUT_DESC_TEXT} - + + + stETH balance + + } + loading={loading} + value={ +
+ + +
+ } + > + + <Box display="inline-block" pr="3px"> + {currency.symbol} + </Box> + <NumberFormat + number={balanceData?.stEthCurrencyBalance} + currency + pending={loading} + /> + +
+ + +
+ + + Current balance may differ from last balance in the table due to + rounding. +
diff --git a/pages/rewards.tsx b/pages/rewards.tsx index 06063e494..609d89a62 100644 --- a/pages/rewards.tsx +++ b/pages/rewards.tsx @@ -6,12 +6,8 @@ import { TopCard, RewardsList } from 'features/rewards/features'; import RewardsHistoryProvider from 'providers/rewardsHistory'; import { Layout } from 'shared/components'; -import { Fallback } from 'shared/wallet'; -import { useDappStatus } from 'shared/hooks/use-dapp-status'; const Rewards: FC = () => { - const { isWalletConnected, isDappActive } = useDappStatus(); - return ( { /> - {isWalletConnected && !isDappActive && } From 703f447f6b4b2ee7f8614f327859e378a061280c Mon Sep 17 00:00:00 2001 From: Anton Shalimov Date: Wed, 31 Jul 2024 14:19:20 +0300 Subject: [PATCH 18/61] feat(rewards): remove AddressInput --- .../components/addressInput/AddressInput.tsx | 38 ------------------- .../rewards/components/addressInput/index.ts | 1 - .../rewards/components/addressInput/types.ts | 7 ---- 3 files changed, 46 deletions(-) delete mode 100644 features/rewards/components/addressInput/AddressInput.tsx delete mode 100644 features/rewards/components/addressInput/index.ts delete mode 100644 features/rewards/components/addressInput/types.ts diff --git a/features/rewards/components/addressInput/AddressInput.tsx b/features/rewards/components/addressInput/AddressInput.tsx deleted file mode 100644 index 88bfd0022..000000000 --- a/features/rewards/components/addressInput/AddressInput.tsx +++ /dev/null @@ -1,38 +0,0 @@ -import { FC } from 'react'; -import { Input, Loader, Identicon } from '@lidofinance/lido-ui'; -import CopyAddressUrl from 'features/rewards/components/CopyAddressUrl'; -import { isValidAnyAddress } from 'features/rewards/utils'; - -import { AddressInputProps } from './types'; - -export const AddressInput: FC = (props) => { - const { - inputValue, - isAddressResolving, - handleInputChange, - address, - addressError, - } = props; - - return ( - handleInputChange(e.target.value)} - placeholder="Ethereum address" - leftDecorator={ - isAddressResolving ? ( - - ) : address ? ( - - ) : null - } - rightDecorator={address ? : null} - spellCheck="false" - error={ - (inputValue.length > 0 && !isValidAnyAddress(inputValue)) || - addressError - } - /> - ); -}; diff --git a/features/rewards/components/addressInput/index.ts b/features/rewards/components/addressInput/index.ts deleted file mode 100644 index 1845571c0..000000000 --- a/features/rewards/components/addressInput/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './AddressInput'; diff --git a/features/rewards/components/addressInput/types.ts b/features/rewards/components/addressInput/types.ts deleted file mode 100644 index 063bc0b23..000000000 --- a/features/rewards/components/addressInput/types.ts +++ /dev/null @@ -1,7 +0,0 @@ -export type AddressInputProps = { - inputValue: string; - isAddressResolving: boolean; - handleInputChange: (value: string) => void; - address: string; - addressError: string; -}; From c0530046c477fdc9d717c855347e55de8d7167da Mon Sep 17 00:00:00 2001 From: Anton Shalimov Date: Wed, 31 Jul 2024 14:34:39 +0300 Subject: [PATCH 19/61] feat(rewards): add connect button instead of rewards table --- .../rewardsListContent/RewardsListsEmpty.tsx | 38 ++++++++++++++++--- .../RewardsListsEmptyStyles.ts | 4 ++ 2 files changed, 37 insertions(+), 5 deletions(-) diff --git a/features/rewards/components/rewardsListContent/RewardsListsEmpty.tsx b/features/rewards/components/rewardsListContent/RewardsListsEmpty.tsx index d83c42966..992928e4a 100644 --- a/features/rewards/components/rewardsListContent/RewardsListsEmpty.tsx +++ b/features/rewards/components/rewardsListContent/RewardsListsEmpty.tsx @@ -1,15 +1,43 @@ -import { FC } from 'react'; +import { FC, useCallback } from 'react'; +import { useConnect } from 'reef-knot/core-react'; +import { wrapWithEventTrack } from '@lidofinance/analytics-matomo'; +import { Button, Divider } from '@lidofinance/lido-ui'; -import { Divider } from '@lidofinance/lido-ui'; - -import { RewardsListEmptyWrapper } from './RewardsListsEmptyStyles'; +import { useUserConfig } from 'config/user-config'; +import { MATOMO_CLICK_EVENTS } from 'consts/matomo-click-events'; +import { + RewardsListEmptyText, + RewardsListEmptyWrapper, +} from './RewardsListsEmptyStyles'; export const RewardsListsEmpty: FC = () => { + const { isWalletConnectionAllowed } = useUserConfig(); + + const { connect } = useConnect(); + + const handleClick = wrapWithEventTrack( + MATOMO_CLICK_EVENTS.connectWallet, + useCallback(() => { + if (!isWalletConnectionAllowed) return; + void connect(); + }, [isWalletConnectionAllowed, connect]), + ); + return ( <> - Connect your wallet to view your staking stats. + + Connect your wallet to view your staking stats. + + ); diff --git a/features/rewards/components/rewardsListContent/RewardsListsEmptyStyles.ts b/features/rewards/components/rewardsListContent/RewardsListsEmptyStyles.ts index 3dd077d9c..d57529b74 100644 --- a/features/rewards/components/rewardsListContent/RewardsListsEmptyStyles.ts +++ b/features/rewards/components/rewardsListContent/RewardsListsEmptyStyles.ts @@ -3,3 +3,7 @@ import styled from 'styled-components'; export const RewardsListEmptyWrapper = styled.div` text-align: center; `; + +export const RewardsListEmptyText = styled.p` + margin-bottom: ${({ theme }) => theme.spaceMap.md}px; +`; From 7b3ca133cf4cd6f48c00e0bba028238a540fb016 Mon Sep 17 00:00:00 2001 From: Anton Shalimov Date: Wed, 31 Jul 2024 14:52:44 +0300 Subject: [PATCH 20/61] fix(rewards): wallet text color --- features/rewards/features/top-card/styles.tsx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/features/rewards/features/top-card/styles.tsx b/features/rewards/features/top-card/styles.tsx index 42fd5e65e..925c68004 100644 --- a/features/rewards/features/top-card/styles.tsx +++ b/features/rewards/features/top-card/styles.tsx @@ -22,6 +22,8 @@ export const WalletContentRowStyle = styled.div` flex-direction: row; align-items: center; justify-content: space-between; + + color: var(--lido-color-text); `; export const WalletContentAddressBadgeStyle = styled(AddressBadge)` From 5f736d873426eb47b59b65e7ed5830378c6560c6 Mon Sep 17 00:00:00 2001 From: Evgeny Taktarov Date: Thu, 1 Aug 2024 16:44:39 +0700 Subject: [PATCH 21/61] Revert "Revert "[fix] remove usage of wallet rpc during tx"" --- features/stake/stake-form/hooks.ts | 2 +- features/stake/stake-form/use-stake.ts | 34 ++-- features/stake/stake-form/utils.ts | 7 +- .../withdrawals/hooks/contract/useClaim.ts | 41 ++--- .../withdrawals/hooks/contract/useRequest.ts | 169 +++++++----------- .../unwrap/hooks/use-unwrap-tx-processing.ts | 21 +-- .../wsteth/wrap/hooks/use-wrap-gas-limit.ts | 14 +- .../wrap/hooks/use-wrap-tx-processing.ts | 58 +++--- shared/hooks/useApprove.ts | 30 ++-- utils/apply-gas-limit-ratio.ts | 7 + utils/estimate-gas.ts | 25 +++ utils/send-tx.ts | 42 +++++ 12 files changed, 219 insertions(+), 231 deletions(-) create mode 100644 utils/apply-gas-limit-ratio.ts create mode 100644 utils/estimate-gas.ts create mode 100644 utils/send-tx.ts diff --git a/features/stake/stake-form/hooks.ts b/features/stake/stake-form/hooks.ts index 3414c044f..96718bc2c 100644 --- a/features/stake/stake-form/hooks.ts +++ b/features/stake/stake-form/hooks.ts @@ -5,7 +5,7 @@ import { useLidoSWR, useSDK, useSTETHContractRPC } from '@lido-sdk/react'; import { config } from 'config'; import { STRATEGY_CONSTANT } from 'consts/swr-strategies'; -import { applyGasLimitRatio } from './utils'; +import { applyGasLimitRatio } from 'utils/apply-gas-limit-ratio'; type UseStethSubmitGasLimit = () => BigNumber; diff --git a/features/stake/stake-form/use-stake.ts b/features/stake/stake-form/use-stake.ts index 997836c81..c2bc8832f 100644 --- a/features/stake/stake-form/use-stake.ts +++ b/features/stake/stake-form/use-stake.ts @@ -8,17 +8,17 @@ import { useSDK, useSTETHContractWeb3 } from '@lido-sdk/react'; import { config } from 'config'; import { useCurrentStaticRpcProvider } from 'shared/hooks/use-current-static-rpc-provider'; import { isContract } from 'utils/isContract'; -import { getFeeData } from 'utils/getFeeData'; import { runWithTransactionLogger } from 'utils'; import { MockLimitReachedError, getAddress, - applyGasLimitRatio, applyCalldataSuffix, } from './utils'; import { useTxModalStagesStake } from './hooks/use-tx-modal-stages-stake'; +import { sendTx } from 'utils/send-tx'; + type StakeArguments = { amount: BigNumber | null; referral: string | null; @@ -33,7 +33,7 @@ export const useStake = ({ onConfirm, onRetry }: StakeOptions) => { const stethContractWeb3 = useSTETHContractWeb3(); const { account, chainId } = useWeb3(); const { staticRpcProvider } = useCurrentStaticRpcProvider(); - const { providerWeb3, providerRpc } = useSDK(); + const { providerWeb3 } = useSDK(); const { txModalStages } = useTxModalStagesStake(); // temporary disable until Ledger is fixed @@ -58,9 +58,9 @@ export const useStake = ({ onConfirm, onRetry }: StakeOptions) => { txModalStages.sign(amount); const [isMultisig, referralAddress] = await Promise.all([ - isContract(account, providerRpc), + isContract(account, staticRpcProvider), referral - ? getAddress(referral, providerRpc) + ? getAddress(referral, staticRpcProvider) : config.STAKE_FALLBACK_REFERRAL_ADDRESS, ]); @@ -74,22 +74,13 @@ export const useStake = ({ onConfirm, onRetry }: StakeOptions) => { if (shouldApplyCalldataSuffix) applyCalldataSuffix(tx); - if (isMultisig) { - return providerWeb3.getSigner().sendUncheckedTransaction(tx); - } else { - const { maxFeePerGas, maxPriorityFeePerGas } = - await getFeeData(staticRpcProvider); - - tx.maxFeePerGas = maxFeePerGas; - tx.maxPriorityFeePerGas = maxPriorityFeePerGas; - - const originalGasLimit = await providerWeb3.estimateGas(tx); - const gasLimit = applyGasLimitRatio(originalGasLimit); - - tx.gasLimit = gasLimit; - - return providerWeb3.getSigner().sendTransaction(tx); - } + return sendTx({ + tx, + isMultisig, + staticProvider: staticRpcProvider, + walletProvider: providerWeb3, + shouldApplyGasLimitRatio: true, + }); }; const tx = await runWithTransactionLogger('Stake signing', callback); @@ -127,7 +118,6 @@ export const useStake = ({ onConfirm, onRetry }: StakeOptions) => { providerWeb3, stethContractWeb3, txModalStages, - providerRpc, onConfirm, staticRpcProvider, shouldApplyCalldataSuffix, diff --git a/features/stake/stake-form/utils.ts b/features/stake/stake-form/utils.ts index ed0cd4ead..7ebb9daf8 100644 --- a/features/stake/stake-form/utils.ts +++ b/features/stake/stake-form/utils.ts @@ -1,15 +1,10 @@ -import type { BigNumber, PopulatedTransaction } from 'ethers'; +import type { PopulatedTransaction } from 'ethers'; import { isAddress } from 'ethers/lib/utils'; import type { BaseProvider } from '@ethersproject/providers'; import { config } from 'config'; import invariant from 'tiny-invariant'; -export const applyGasLimitRatio = (gasLimit: BigNumber): BigNumber => - gasLimit - .mul(config.SUBMIT_EXTRA_GAS_TRANSACTION_RATIO * config.PRECISION) - .div(config.PRECISION); - export const getAddress = async ( input: string, providerRpc: BaseProvider, diff --git a/features/withdrawals/hooks/contract/useClaim.ts b/features/withdrawals/hooks/contract/useClaim.ts index 9cd1bcdf8..04f6402b1 100644 --- a/features/withdrawals/hooks/contract/useClaim.ts +++ b/features/withdrawals/hooks/contract/useClaim.ts @@ -11,6 +11,8 @@ import { isContract } from 'utils/isContract'; import { useWeb3 } from 'reef-knot/web3-react'; import { useSDK } from '@lido-sdk/react'; import { useTxModalStagesClaim } from 'features/withdrawals/claim/transaction-modal-claim/use-tx-modal-stages-claim'; +import { useCurrentStaticRpcProvider } from 'shared/hooks/use-current-static-rpc-provider'; +import { sendTx } from 'utils/send-tx'; type Args = { onRetry?: () => void; @@ -20,6 +22,7 @@ export const useClaim = ({ onRetry }: Args) => { const { account } = useWeb3(); const { providerWeb3 } = useSDK(); const { contractWeb3 } = useWithdrawalsContract(); + const { staticRpcProvider } = useCurrentStaticRpcProvider(); const { optimisticClaimRequests } = useClaimData(); const { txModalStages } = useTxModalStagesClaim(); @@ -43,31 +46,16 @@ export const useClaim = ({ onRetry }: Args) => { const ids = sortedRequests.map((r) => r.id); const hints = sortedRequests.map((r) => r.hint); const callback = async () => { - if (isMultisig) { - const tx = await contractWeb3.populateTransaction.claimWithdrawals( - ids, - hints, - ); - return providerWeb3.getSigner().sendUncheckedTransaction(tx); - } else { - const feeData = await contractWeb3.provider.getFeeData(); - const maxFeePerGas = feeData.maxFeePerGas ?? undefined; - const maxPriorityFeePerGas = - feeData.maxPriorityFeePerGas ?? undefined; - const gasLimit = await contractWeb3.estimateGas.claimWithdrawals( - ids, - hints, - { - maxFeePerGas, - maxPriorityFeePerGas, - }, - ); - return contractWeb3.claimWithdrawals(ids, hints, { - maxFeePerGas, - maxPriorityFeePerGas, - gasLimit, - }); - } + const tx = await contractWeb3.populateTransaction.claimWithdrawals( + ids, + hints, + ); + return sendTx({ + tx, + isMultisig, + staticProvider: staticRpcProvider, + walletProvider: providerWeb3, + }); }; const tx = await runWithTransactionLogger('Claim signing', callback); @@ -100,8 +88,9 @@ export const useClaim = ({ onRetry }: Args) => { contractWeb3, account, providerWeb3, - optimisticClaimRequests, txModalStages, + staticRpcProvider, + optimisticClaimRequests, onRetry, ], ); diff --git a/features/withdrawals/hooks/contract/useRequest.ts b/features/withdrawals/hooks/contract/useRequest.ts index 45896bd3c..7ce7b71f9 100644 --- a/features/withdrawals/hooks/contract/useRequest.ts +++ b/features/withdrawals/hooks/contract/useRequest.ts @@ -1,3 +1,4 @@ +/* eslint-disable sonarjs/no-identical-functions */ import { useCallback } from 'react'; import { BigNumber } from 'ethers'; import invariant from 'tiny-invariant'; @@ -22,11 +23,11 @@ import { useCurrentStaticRpcProvider } from 'shared/hooks/use-current-static-rpc import { useApprove } from 'shared/hooks/useApprove'; import { runWithTransactionLogger } from 'utils'; import { isContract } from 'utils/isContract'; -import { getFeeData } from 'utils/getFeeData'; import { useWithdrawalsContract } from './useWithdrawalsContract'; import { useTxModalStagesRequest } from 'features/withdrawals/request/transaction-modal-request/use-tx-modal-stages-request'; import { useTransactionModal } from 'shared/transaction-modal/transaction-modal'; +import { sendTx } from 'utils/send-tx'; // this encapsulates permit/approval & steth/wsteth flows const useWithdrawalRequestMethods = () => { @@ -44,41 +45,34 @@ const useWithdrawalRequestMethods = () => { }) => { invariant(chainId, 'must have chainId'); invariant(account, 'must have account'); + invariant(providerWeb3, 'must have providerWeb3'); invariant(signature, 'must have signature'); invariant(contractWeb3, 'must have contractWeb3'); - const params = [ - requests, - signature.owner, - { - value: signature.value, - deadline: signature.deadline, - v: signature.v, - r: signature.r, - s: signature.s, - }, - ] as const; - - const { maxFeePerGas, maxPriorityFeePerGas } = - await getFeeData(staticRpcProvider); - const gasLimit = - await contractWeb3.estimateGas.requestWithdrawalsWithPermit(...params, { - maxFeePerGas, - maxPriorityFeePerGas, - }); - - const txOptions = { - maxFeePerGas, - maxPriorityFeePerGas, - gasLimit, - }; + const tx = + await contractWeb3.populateTransaction.requestWithdrawalsWithPermit( + requests, + signature.owner, + { + value: signature.value, + deadline: signature.deadline, + v: signature.v, + r: signature.r, + s: signature.s, + }, + ); const callback = () => - contractWeb3.requestWithdrawalsWithPermit(...params, txOptions); + sendTx({ + tx, + isMultisig: false, + staticProvider: staticRpcProvider, + walletProvider: providerWeb3, + }); return callback; }, - [account, chainId, contractWeb3, staticRpcProvider], + [account, chainId, contractWeb3, providerWeb3, staticRpcProvider], ); const permitWsteth = useCallback( @@ -92,44 +86,33 @@ const useWithdrawalRequestMethods = () => { invariant(chainId, 'must have chainId'); invariant(account, 'must have account'); invariant(signature, 'must have signature'); + invariant(providerWeb3, 'must have providerWeb3'); invariant(contractWeb3, 'must have contractWeb3'); - const params = [ - requests, - signature.owner, - { - value: signature.value, - deadline: signature.deadline, - v: signature.v, - r: signature.r, - s: signature.s, - }, - ] as const; - - const feeData = await getFeeData(staticRpcProvider); - const maxFeePerGas = feeData.maxFeePerGas ?? undefined; - const maxPriorityFeePerGas = feeData.maxPriorityFeePerGas ?? undefined; - const gasLimit = - await contractWeb3.estimateGas.requestWithdrawalsWstETHWithPermit( - ...params, + const tx = + await contractWeb3.populateTransaction.requestWithdrawalsWstETHWithPermit( + requests, + signature.owner, { - maxFeePerGas, - maxPriorityFeePerGas, + value: signature.value, + deadline: signature.deadline, + v: signature.v, + r: signature.r, + s: signature.s, }, ); - const txOptions = { - maxFeePerGas, - maxPriorityFeePerGas, - gasLimit, - }; - const callback = () => - contractWeb3.requestWithdrawalsWstETHWithPermit(...params, txOptions); + sendTx({ + tx, + isMultisig: false, + staticProvider: staticRpcProvider, + walletProvider: providerWeb3, + }); return callback; }, - [account, chainId, contractWeb3, staticRpcProvider], + [account, chainId, contractWeb3, providerWeb3, staticRpcProvider], ); const steth = useCallback( @@ -141,31 +124,18 @@ const useWithdrawalRequestMethods = () => { const isMultisig = await isContract(account, contractWeb3.provider); - const params = [requests, account] as const; - - const callback = async () => { - if (isMultisig) { - const tx = await contractWeb3.populateTransaction.requestWithdrawals( - ...params, - ); - return providerWeb3?.getSigner().sendUncheckedTransaction(tx); - } else { - const { maxFeePerGas, maxPriorityFeePerGas } = - await getFeeData(staticRpcProvider); - const gasLimit = await contractWeb3.estimateGas.requestWithdrawals( - ...params, - { - maxFeePerGas, - maxPriorityFeePerGas, - }, - ); - return contractWeb3.requestWithdrawals(...params, { - maxFeePerGas, - maxPriorityFeePerGas, - gasLimit, - }); - } - }; + const tx = await contractWeb3.populateTransaction.requestWithdrawals( + requests, + account, + ); + + const callback = async () => + sendTx({ + tx, + isMultisig, + staticProvider: staticRpcProvider, + walletProvider: providerWeb3, + }); return callback; }, @@ -180,30 +150,19 @@ const useWithdrawalRequestMethods = () => { invariant(providerWeb3, 'must have providerWeb3'); const isMultisig = await isContract(account, contractWeb3.provider); - const params = [requests, account] as const; - const callback = async () => { - if (isMultisig) { - const tx = - await contractWeb3.populateTransaction.requestWithdrawalsWstETH( - requests, - account, - ); - return providerWeb3?.getSigner().sendUncheckedTransaction(tx); - } else { - const { maxFeePerGas, maxPriorityFeePerGas } = - await getFeeData(staticRpcProvider); - const gasLimit = - await contractWeb3.estimateGas.requestWithdrawalsWstETH(...params, { - maxFeePerGas, - maxPriorityFeePerGas, - }); - return contractWeb3.requestWithdrawalsWstETH(...params, { - maxFeePerGas, - maxPriorityFeePerGas, - gasLimit, - }); - } - }; + const tx = + await contractWeb3.populateTransaction.requestWithdrawalsWstETH( + requests, + account, + ); + + const callback = async () => + sendTx({ + tx, + isMultisig, + staticProvider: staticRpcProvider, + walletProvider: providerWeb3, + }); return callback; }, diff --git a/features/wsteth/unwrap/hooks/use-unwrap-tx-processing.ts b/features/wsteth/unwrap/hooks/use-unwrap-tx-processing.ts index a2ec46b77..eb0742eed 100644 --- a/features/wsteth/unwrap/hooks/use-unwrap-tx-processing.ts +++ b/features/wsteth/unwrap/hooks/use-unwrap-tx-processing.ts @@ -4,9 +4,9 @@ import invariant from 'tiny-invariant'; import { useSDK, useWSTETHContractWeb3 } from '@lido-sdk/react'; import { useCurrentStaticRpcProvider } from 'shared/hooks/use-current-static-rpc-provider'; -import { getFeeData } from 'utils/getFeeData'; import type { UnwrapFormInputType } from '../unwrap-form-context'; +import { sendTx } from 'utils/send-tx'; type UnwrapTxProcessorArgs = Omit & { isMultisig: boolean; @@ -24,17 +24,14 @@ export const useUnwrapTxProcessing = () => { invariant(providerWeb3, 'providerWeb3 must be presented'); invariant(wstethContractWeb3, 'must have wstethContractWeb3'); - if (isMultisig) { - const tx = await wstethContractWeb3.populateTransaction.unwrap(amount); - return providerWeb3.getSigner().sendUncheckedTransaction(tx); - } else { - const { maxFeePerGas, maxPriorityFeePerGas } = - await getFeeData(staticRpcProvider); - return wstethContractWeb3.unwrap(amount, { - maxPriorityFeePerGas: maxPriorityFeePerGas ?? undefined, - maxFeePerGas: maxFeePerGas ?? undefined, - }); - } + const tx = await wstethContractWeb3.populateTransaction.unwrap(amount); + + return sendTx({ + tx, + isMultisig, + staticProvider: staticRpcProvider, + walletProvider: providerWeb3, + }); }, [chainId, providerWeb3, staticRpcProvider, wstethContractWeb3], ); diff --git a/features/wsteth/wrap/hooks/use-wrap-gas-limit.ts b/features/wsteth/wrap/hooks/use-wrap-gas-limit.ts index ac2231866..60d44f792 100644 --- a/features/wsteth/wrap/hooks/use-wrap-gas-limit.ts +++ b/features/wsteth/wrap/hooks/use-wrap-gas-limit.ts @@ -4,7 +4,7 @@ import { useLidoSWR, useWSTETHContractRPC } from '@lido-sdk/react'; import { config } from 'config'; import { WRAP_FROM_ETH_GAS_LIMIT, WRAP_GAS_LIMIT } from 'consts/tx'; import { useCurrentStaticRpcProvider } from 'shared/hooks/use-current-static-rpc-provider'; -import { applyGasLimitRatio } from 'features/stake/stake-form/utils'; +import { applyGasLimitRatio } from 'utils/apply-gas-limit-ratio'; export const useWrapGasLimit = () => { const wsteth = useWSTETHContractRPC(); @@ -18,11 +18,13 @@ export const useWrapGasLimit = () => { const fetchGasLimitETH = async () => { try { - return await staticRpcProvider.estimateGas({ - from: config.ESTIMATE_ACCOUNT, - to: wsteth.address, - value: config.ESTIMATE_AMOUNT, - }); + return applyGasLimitRatio( + await staticRpcProvider.estimateGas({ + from: config.ESTIMATE_ACCOUNT, + to: wsteth.address, + value: config.ESTIMATE_AMOUNT, + }), + ); } catch (error) { console.warn(`${_key}::[eth]`, error); return applyGasLimitRatio(WRAP_FROM_ETH_GAS_LIMIT); diff --git a/features/wsteth/wrap/hooks/use-wrap-tx-processing.ts b/features/wsteth/wrap/hooks/use-wrap-tx-processing.ts index 8a3fe44c6..00d994ebb 100644 --- a/features/wsteth/wrap/hooks/use-wrap-tx-processing.ts +++ b/features/wsteth/wrap/hooks/use-wrap-tx-processing.ts @@ -2,19 +2,18 @@ import { useCallback } from 'react'; import invariant from 'tiny-invariant'; import { useSDK, useWSTETHContractWeb3 } from '@lido-sdk/react'; -import { getTokenAddress, TOKENS } from '@lido-sdk/constants'; +import { TOKENS } from '@lido-sdk/constants'; import { StaticJsonRpcBatchProvider } from '@lidofinance/eth-providers'; import { config } from 'config'; -import { - MockLimitReachedError, - applyGasLimitRatio, -} from 'features/stake/stake-form/utils'; +import { MockLimitReachedError } from 'features/stake/stake-form/utils'; import { useCurrentStaticRpcProvider } from 'shared/hooks/use-current-static-rpc-provider'; import { getFeeData } from 'utils/getFeeData'; import type { WrapFormInputType } from '../wrap-form-context'; +import { sendTx } from 'utils/send-tx'; +import { PopulatedTransaction } from 'ethers'; export const getGasParameters = async ( provider: StaticJsonRpcBatchProvider, @@ -43,15 +42,13 @@ export const useWrapTxProcessing = () => { invariant(wstethContractWeb3, 'wstethContractWeb3 must be presented'); if (token === TOKENS.STETH) { - if (isMultisig) { - const tx = await wstethContractWeb3.populateTransaction.wrap(amount); - return providerWeb3.getSigner().sendUncheckedTransaction(tx); - } else { - return wstethContractWeb3.wrap( - amount, - await getGasParameters(staticRpcProvider), - ); - } + const tx = await wstethContractWeb3.populateTransaction.wrap(amount); + return sendTx({ + tx, + isMultisig, + staticProvider: staticRpcProvider, + walletProvider: providerWeb3, + }); } else { if ( config.enableQaHelpers && @@ -59,27 +56,20 @@ export const useWrapTxProcessing = () => { ) { throw new MockLimitReachedError('Stake limit reached'); } + const from = await providerWeb3.getSigner().getAddress(); + const tx: PopulatedTransaction = { + to: wstethContractWeb3.address, + value: amount, + from, + }; - const wstethTokenAddress = getTokenAddress(chainId, TOKENS.WSTETH); - if (isMultisig) { - return providerWeb3.getSigner().sendUncheckedTransaction({ - to: wstethTokenAddress, - value: amount, - }); - } else { - const originalGasLimit = await wstethContractWeb3.signer.estimateGas({ - to: wstethTokenAddress, - value: amount, - }); - - const gasLimit = applyGasLimitRatio(originalGasLimit); - return wstethContractWeb3.signer.sendTransaction({ - to: wstethTokenAddress, - value: amount, - gasLimit, - ...(await getGasParameters(staticRpcProvider)), - }); - } + return sendTx({ + tx, + isMultisig, + staticProvider: staticRpcProvider, + walletProvider: providerWeb3, + shouldApplyGasLimitRatio: true, + }); } }, [chainId, providerWeb3, staticRpcProvider, wstethContractWeb3], diff --git a/shared/hooks/useApprove.ts b/shared/hooks/useApprove.ts index 5d7b19d9d..f6381832e 100644 --- a/shared/hooks/useApprove.ts +++ b/shared/hooks/useApprove.ts @@ -7,11 +7,11 @@ import { getERC20Contract } from '@lido-sdk/contracts'; import { useAllowance, useSDK } from '@lido-sdk/react'; import { isContract } from 'utils/isContract'; -import { getFeeData } from 'utils/getFeeData'; import { runWithTransactionLogger } from 'utils'; import { useCurrentStaticRpcProvider } from './use-current-static-rpc-provider'; import { STRATEGY_LAZY } from 'consts/swr-strategies'; +import { sendTx } from 'utils/send-tx'; type ApproveOptions = | { @@ -60,24 +60,16 @@ export const useApprove = ( const isMultisig = await isContract(account, providerWeb3); const processApproveTx = async () => { - if (isMultisig) { - const tx = await contractWeb3.populateTransaction.approve( - spender, - amount, - ); - const hash = await providerWeb3 - .getSigner() - .sendUncheckedTransaction(tx); - return hash; - } else { - const { maxFeePerGas, maxPriorityFeePerGas } = - await getFeeData(staticRpcProvider); - const tx = await contractWeb3.approve(spender, amount, { - maxFeePerGas, - maxPriorityFeePerGas, - }); - return tx; - } + const tx = await contractWeb3.populateTransaction.approve( + spender, + amount, + ); + return sendTx({ + tx, + isMultisig, + staticProvider: staticRpcProvider, + walletProvider: providerWeb3, + }); }; const approveTx = await runWithTransactionLogger( diff --git a/utils/apply-gas-limit-ratio.ts b/utils/apply-gas-limit-ratio.ts new file mode 100644 index 000000000..c0d3b9c54 --- /dev/null +++ b/utils/apply-gas-limit-ratio.ts @@ -0,0 +1,7 @@ +import { config } from 'config'; +import type { BigNumber } from 'ethers'; + +export const applyGasLimitRatio = (gasLimit: BigNumber): BigNumber => + gasLimit + .mul(config.SUBMIT_EXTRA_GAS_TRANSACTION_RATIO * config.PRECISION) + .div(config.PRECISION); diff --git a/utils/estimate-gas.ts b/utils/estimate-gas.ts new file mode 100644 index 000000000..51f4dca20 --- /dev/null +++ b/utils/estimate-gas.ts @@ -0,0 +1,25 @@ +import { StaticJsonRpcBatchProvider } from '@lidofinance/eth-providers'; +import { PopulatedTransaction } from 'ethers'; + +export const estimateGas = async ( + tx: PopulatedTransaction, + provider: StaticJsonRpcBatchProvider, +) => { + try { + return await provider.estimateGas(tx); + } catch (error) { + // retry without fees to see if just fails + const result = await provider + .estimateGas({ + ...tx, + maxFeePerGas: undefined, + maxPriorityFeePerGas: undefined, + }) + .catch(() => null); + // rethrow original not enough ether error + if (result) { + throw error; + } + throw new Error('Something went wrong'); + } +}; diff --git a/utils/send-tx.ts b/utils/send-tx.ts new file mode 100644 index 000000000..71c4af2a0 --- /dev/null +++ b/utils/send-tx.ts @@ -0,0 +1,42 @@ +import type { + JsonRpcBatchProvider, + Web3Provider, +} from '@ethersproject/providers'; +import type { PopulatedTransaction } from 'ethers'; + +import { getFeeData } from './getFeeData'; +import { estimateGas } from './estimate-gas'; +import { applyGasLimitRatio } from 'utils/apply-gas-limit-ratio'; + +export type SendTxOptions = { + tx: PopulatedTransaction; + isMultisig: boolean; + walletProvider: Web3Provider; + staticProvider: JsonRpcBatchProvider; + shouldApplyGasLimitRatio?: boolean; +}; + +export const sendTx = async ({ + tx, + isMultisig, + staticProvider, + walletProvider, + shouldApplyGasLimitRatio = false, +}: SendTxOptions) => { + if (isMultisig) + return walletProvider.getSigner().sendUncheckedTransaction(tx); + + const { maxFeePerGas, maxPriorityFeePerGas } = + await getFeeData(staticProvider); + + tx.maxFeePerGas = maxFeePerGas; + tx.maxPriorityFeePerGas = maxPriorityFeePerGas; + + const gasLimit = await estimateGas(tx, staticProvider); + + tx.gasLimit = shouldApplyGasLimitRatio + ? applyGasLimitRatio(gasLimit) + : gasLimit; + + return walletProvider.getSigner().sendTransaction(tx); +}; From aa53e0d80321a221a9ec017353c82299e7cc44b9 Mon Sep 17 00:00:00 2001 From: Evgeny Taktarov Date: Thu, 1 Aug 2024 19:53:42 +0700 Subject: [PATCH 22/61] fix: wait for transactions via static prc --- features/stake/stake-form/use-stake.ts | 12 ++++++---- .../withdrawals/hooks/contract/useClaim.ts | 18 +++++++------- .../withdrawals/hooks/contract/useRequest.ts | 18 +++++++------- .../hooks/use-unwrap-form-processing.ts | 24 +++++++++---------- .../wrap/hooks/use-wrap-form-processing.ts | 17 +++++++------ shared/hooks/useApprove.ts | 12 +++++----- utils/send-tx.ts | 24 +++++++++---------- 7 files changed, 62 insertions(+), 63 deletions(-) diff --git a/features/stake/stake-form/use-stake.ts b/features/stake/stake-form/use-stake.ts index c2bc8832f..f230a4edf 100644 --- a/features/stake/stake-form/use-stake.ts +++ b/features/stake/stake-form/use-stake.ts @@ -83,8 +83,10 @@ export const useStake = ({ onConfirm, onRetry }: StakeOptions) => { }); }; - const tx = await runWithTransactionLogger('Stake signing', callback); - const txHash = typeof tx === 'string' ? tx : tx.hash; + const txHash = await runWithTransactionLogger( + 'Stake signing', + callback, + ); if (isMultisig) { txModalStages.successMultisig(); @@ -93,9 +95,9 @@ export const useStake = ({ onConfirm, onRetry }: StakeOptions) => { txModalStages.pending(amount, txHash); - if (typeof tx === 'object') { - await runWithTransactionLogger('Wrap block confirmation', () => - tx.wait(), + if (!isMultisig) { + await runWithTransactionLogger('Stake block confirmation', () => + staticRpcProvider.waitForTransaction(txHash), ); } diff --git a/features/withdrawals/hooks/contract/useClaim.ts b/features/withdrawals/hooks/contract/useClaim.ts index 04f6402b1..0e55e9bcf 100644 --- a/features/withdrawals/hooks/contract/useClaim.ts +++ b/features/withdrawals/hooks/contract/useClaim.ts @@ -58,8 +58,10 @@ export const useClaim = ({ onRetry }: Args) => { }); }; - const tx = await runWithTransactionLogger('Claim signing', callback); - const txHash = typeof tx === 'string' ? tx : tx.hash; + const txHash = await runWithTransactionLogger( + 'Claim signing', + callback, + ); if (isMultisig) { txModalStages.successMultisig(); @@ -68,13 +70,11 @@ export const useClaim = ({ onRetry }: Args) => { txModalStages.pending(amount, txHash); - if (typeof tx === 'object') { - await runWithTransactionLogger('Claim block confirmation', async () => - tx.wait(), - ); - // we only update if we wait for tx - await optimisticClaimRequests(sortedRequests); - } + await runWithTransactionLogger('Claim block confirmation', async () => + staticRpcProvider.waitForTransaction(txHash), + ); + + await optimisticClaimRequests(sortedRequests); txModalStages.success(amount, txHash); return true; diff --git a/features/withdrawals/hooks/contract/useRequest.ts b/features/withdrawals/hooks/contract/useRequest.ts index 7ce7b71f9..2b8a6c217 100644 --- a/features/withdrawals/hooks/contract/useRequest.ts +++ b/features/withdrawals/hooks/contract/useRequest.ts @@ -201,6 +201,7 @@ export const useWithdrawalRequest = ({ }: useWithdrawalRequestParams) => { const { chainId } = useSDK(); const withdrawalQueueAddress = getWithdrawalQueueAddress(chainId); + const { staticRpcProvider } = useCurrentStaticRpcProvider(); const { connector } = useAccount(); const { account } = useWeb3(); @@ -283,9 +284,8 @@ export const useWithdrawalRequest = ({ txModalStages.signApproval(amount, token); await approve({ - onTxSent: (tx) => { + onTxSent: (txHash) => { if (!isMultisig) { - const txHash = typeof tx === 'string' ? tx : tx.hash; txModalStages.pendingApproval(amount, token, txHash); } }, @@ -303,8 +303,10 @@ export const useWithdrawalRequest = ({ txModalStages.sign(amount, token); const callback = await method({ signature, requests }); - const tx = await runWithTransactionLogger('Request signing', callback); - const txHash = typeof tx === 'string' ? tx : tx.hash; + const txHash = await runWithTransactionLogger( + 'Request signing', + callback, + ); if (isMultisig) { txModalStages.successMultisig(); @@ -313,10 +315,9 @@ export const useWithdrawalRequest = ({ txModalStages.pending(amount, token, txHash); - if (typeof tx === 'object') { - await runWithTransactionLogger( - 'Request block confirmation', - async () => tx.wait(), + if (!isMultisig) { + await runWithTransactionLogger('Stake block confirmation', () => + staticRpcProvider.waitForTransaction(txHash), ); } @@ -340,6 +341,7 @@ export const useWithdrawalRequest = ({ needsApprove, onConfirm, onRetry, + staticRpcProvider, txModalStages, ], ); diff --git a/features/wsteth/unwrap/hooks/use-unwrap-form-processing.ts b/features/wsteth/unwrap/hooks/use-unwrap-form-processing.ts index 9b50127ae..59dc9ef02 100644 --- a/features/wsteth/unwrap/hooks/use-unwrap-form-processing.ts +++ b/features/wsteth/unwrap/hooks/use-unwrap-form-processing.ts @@ -13,6 +13,7 @@ import { useTxModalStagesUnwrap } from './use-tx-modal-stages-unwrap'; import { isContract } from 'utils/isContract'; import { runWithTransactionLogger } from 'utils'; import type { UnwrapFormInputType } from '../unwrap-form-context'; +import { useCurrentStaticRpcProvider } from 'shared/hooks/use-current-static-rpc-provider'; type UseUnwrapFormProcessorArgs = { onConfirm?: () => Promise; @@ -24,6 +25,7 @@ export const useUnwrapFormProcessor = ({ onRetry, }: UseUnwrapFormProcessorArgs) => { const { account } = useWeb3(); + const { staticRpcProvider } = useCurrentStaticRpcProvider(); const { providerWeb3 } = useSDK(); const processWrapTx = useUnwrapTxProcessing(); const stETHContractRPC = useSTETHContractRPC(); @@ -41,12 +43,10 @@ export const useUnwrapFormProcessor = ({ txModalStages.sign(amount, willReceive); - const tx = await runWithTransactionLogger('Unwrap signing', () => + const txHash = await runWithTransactionLogger('Unwrap signing', () => processWrapTx({ amount, isMultisig }), ); - const txHash = typeof tx === 'string' ? tx : tx.hash; - if (isMultisig) { txModalStages.successMultisig(); return true; @@ -54,12 +54,9 @@ export const useUnwrapFormProcessor = ({ txModalStages.pending(amount, willReceive, txHash); - if (typeof tx === 'object') { - await runWithTransactionLogger( - 'Unwrap block confirmation', - async () => tx.wait(), - ); - } + await runWithTransactionLogger('Unwrap block confirmation', async () => + staticRpcProvider.waitForTransaction(txHash), + ); const stethBalance = await stETHContractRPC.balanceOf(account); @@ -74,13 +71,14 @@ export const useUnwrapFormProcessor = ({ }, [ account, - onConfirm, - onRetry, - processWrapTx, providerWeb3, + wstETHContractRPC, txModalStages, stETHContractRPC, - wstETHContractRPC, + onConfirm, + processWrapTx, + staticRpcProvider, + onRetry, ], ); }; diff --git a/features/wsteth/wrap/hooks/use-wrap-form-processing.ts b/features/wsteth/wrap/hooks/use-wrap-form-processing.ts index 77cde9c3b..0b3789ba9 100644 --- a/features/wsteth/wrap/hooks/use-wrap-form-processing.ts +++ b/features/wsteth/wrap/hooks/use-wrap-form-processing.ts @@ -13,6 +13,7 @@ import type { WrapFormApprovalData, WrapFormInputType, } from '../wrap-form-context'; +import { useCurrentStaticRpcProvider } from 'shared/hooks/use-current-static-rpc-provider'; type UseWrapFormProcessorArgs = { approvalData: WrapFormApprovalData; @@ -31,6 +32,7 @@ export const useWrapFormProcessor = ({ const { isApprovalNeededBeforeWrap, processApproveTx } = approvalData; const { txModalStages } = useTxModalWrap(); const wstETHContractRPC = useWSTETHContractRPC(); + const { staticRpcProvider } = useCurrentStaticRpcProvider(); return useCallback( async ({ amount, token }: WrapFormInputType) => { @@ -45,8 +47,7 @@ export const useWrapFormProcessor = ({ txModalStages.signApproval(amount, token); await processApproveTx({ - onTxSent: (tx) => { - const txHash = typeof tx === 'string' ? tx : tx.hash; + onTxSent: (txHash) => { if (!isMultisig) { txModalStages.pendingApproval(amount, token, txHash); } @@ -60,10 +61,9 @@ export const useWrapFormProcessor = ({ txModalStages.sign(amount, token, willReceive); - const tx = await runWithTransactionLogger('Wrap signing', () => + const txHash = await runWithTransactionLogger('Wrap signing', () => processWrapTx({ amount, token, isMultisig }), ); - const txHash = typeof tx === 'string' ? tx : tx.hash; if (isMultisig) { txModalStages.successMultisig(); @@ -72,11 +72,9 @@ export const useWrapFormProcessor = ({ txModalStages.pending(amount, token, willReceive, txHash); - if (typeof tx === 'object') { - await runWithTransactionLogger('Wrap block confirmation', async () => - tx.wait(), - ); - } + await runWithTransactionLogger('Wrap block confirmation', () => + staticRpcProvider.waitForTransaction(txHash), + ); const wstethBalance = await wstETHContractRPC.balanceOf(account); @@ -98,6 +96,7 @@ export const useWrapFormProcessor = ({ onConfirm, processApproveTx, processWrapTx, + staticRpcProvider, onRetry, ], ); diff --git a/shared/hooks/useApprove.ts b/shared/hooks/useApprove.ts index f6381832e..50e7f92b3 100644 --- a/shared/hooks/useApprove.ts +++ b/shared/hooks/useApprove.ts @@ -1,7 +1,7 @@ import invariant from 'tiny-invariant'; import { useCallback } from 'react'; -import { ContractReceipt, ContractTransaction } from '@ethersproject/contracts'; +import type { ContractReceipt } from '@ethersproject/contracts'; import { BigNumber } from '@ethersproject/bignumber'; import { getERC20Contract } from '@lido-sdk/contracts'; import { useAllowance, useSDK } from '@lido-sdk/react'; @@ -16,7 +16,7 @@ import { sendTx } from 'utils/send-tx'; type ApproveOptions = | { onTxStart?: () => void | Promise; - onTxSent?: (tx: string | ContractTransaction) => void | Promise; + onTxSent?: (tx: string) => void | Promise; onTxAwaited?: (tx: ContractReceipt) => void | Promise; } | undefined; @@ -72,16 +72,16 @@ export const useApprove = ( }); }; - const approveTx = await runWithTransactionLogger( + const approveTxHash = await runWithTransactionLogger( 'Approve signing', processApproveTx, ); - await onTxSent?.(approveTx); + await onTxSent?.(approveTxHash); - if (typeof approveTx === 'object') { + if (!isMultisig) { const receipt = await runWithTransactionLogger( 'Approve block confirmation', - () => approveTx.wait(), + () => staticRpcProvider.waitForTransaction(approveTxHash), ); await onTxAwaited?.(receipt); } diff --git a/utils/send-tx.ts b/utils/send-tx.ts index 71c4af2a0..a7c003a70 100644 --- a/utils/send-tx.ts +++ b/utils/send-tx.ts @@ -23,20 +23,18 @@ export const sendTx = async ({ walletProvider, shouldApplyGasLimitRatio = false, }: SendTxOptions) => { - if (isMultisig) - return walletProvider.getSigner().sendUncheckedTransaction(tx); + if (!isMultisig) { + const { maxFeePerGas, maxPriorityFeePerGas } = + await getFeeData(staticProvider); - const { maxFeePerGas, maxPriorityFeePerGas } = - await getFeeData(staticProvider); + tx.maxFeePerGas = maxFeePerGas; + tx.maxPriorityFeePerGas = maxPriorityFeePerGas; - tx.maxFeePerGas = maxFeePerGas; - tx.maxPriorityFeePerGas = maxPriorityFeePerGas; + const gasLimit = await estimateGas(tx, staticProvider); - const gasLimit = await estimateGas(tx, staticProvider); - - tx.gasLimit = shouldApplyGasLimitRatio - ? applyGasLimitRatio(gasLimit) - : gasLimit; - - return walletProvider.getSigner().sendTransaction(tx); + tx.gasLimit = shouldApplyGasLimitRatio + ? applyGasLimitRatio(gasLimit) + : gasLimit; + } + return walletProvider.getSigner().sendUncheckedTransaction(tx); }; From 04bb4b0c6aa87a2e20efce4176ef67f4905c6c43 Mon Sep 17 00:00:00 2001 From: Evgeny Taktarov Date: Fri, 2 Aug 2024 14:24:09 +0700 Subject: [PATCH 23/61] fix: update wagmi to use latest wc connector --- features/stake/stake-form/use-stake.ts | 12 ++- package.json | 2 +- yarn.lock | 124 ++++++++++++------------- 3 files changed, 72 insertions(+), 66 deletions(-) diff --git a/features/stake/stake-form/use-stake.ts b/features/stake/stake-form/use-stake.ts index f230a4edf..092272289 100644 --- a/features/stake/stake-form/use-stake.ts +++ b/features/stake/stake-form/use-stake.ts @@ -3,7 +3,11 @@ import { useCallback } from 'react'; import { useWeb3 } from 'reef-knot/web3-react'; import invariant from 'tiny-invariant'; -import { useSDK, useSTETHContractWeb3 } from '@lido-sdk/react'; +import { + useSDK, + useSTETHContractRPC, + useSTETHContractWeb3, +} from '@lido-sdk/react'; import { config } from 'config'; import { useCurrentStaticRpcProvider } from 'shared/hooks/use-current-static-rpc-provider'; @@ -31,6 +35,7 @@ type StakeOptions = { export const useStake = ({ onConfirm, onRetry }: StakeOptions) => { const stethContractWeb3 = useSTETHContractWeb3(); + const stethContract = useSTETHContractRPC(); const { account, chainId } = useWeb3(); const { staticRpcProvider } = useCurrentStaticRpcProvider(); const { providerWeb3 } = useSDK(); @@ -101,7 +106,7 @@ export const useStake = ({ onConfirm, onRetry }: StakeOptions) => { ); } - const stethBalance = await stethContractWeb3.balanceOf(account); + const stethBalance = await stethContract.balanceOf(account); await onConfirm?.(); @@ -120,8 +125,9 @@ export const useStake = ({ onConfirm, onRetry }: StakeOptions) => { providerWeb3, stethContractWeb3, txModalStages, - onConfirm, staticRpcProvider, + stethContract, + onConfirm, shouldApplyCalldataSuffix, onRetry, ], diff --git a/package.json b/package.json index ad92ad829..9ef5e7344 100644 --- a/package.json +++ b/package.json @@ -79,7 +79,7 @@ "tiny-invariant": "^1.1.0", "uuid": "^8.3.2", "viem": "2.13.3", - "wagmi": "2.11.2" + "wagmi": "2.12.2" }, "devDependencies": { "@commitlint/cli": "^17.4.4", diff --git a/yarn.lock b/yarn.lock index e40811c91..ee0549249 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2350,10 +2350,10 @@ resolved "https://registry.yarnpkg.com/@metamask/safe-event-emitter/-/safe-event-emitter-3.1.1.tgz#e89b840a7af8097a8ed4953d8dc8470d1302d3ef" integrity sha512-ihb3B0T/wJm1eUuArYP4lCTSEoZsClHhuWyfo/kMX3m/odpqNcPfsz5O2A3NT7dXCAgWPGDQGPqygCpgeniKMw== -"@metamask/sdk-communication-layer@0.26.4": - version "0.26.4" - resolved "https://registry.yarnpkg.com/@metamask/sdk-communication-layer/-/sdk-communication-layer-0.26.4.tgz#dda8e33a327f29962095b82c598799b852e40d81" - integrity sha512-+X4GEc5mV1gWK4moSswVlKsUh+RsA48qPlkxBLTUxQODSnyBe0TRMxE6mH+bSrfponnTzvBkGUXyEjvDwDjDHw== +"@metamask/sdk-communication-layer@0.27.0": + version "0.27.0" + resolved "https://registry.yarnpkg.com/@metamask/sdk-communication-layer/-/sdk-communication-layer-0.27.0.tgz#8d618fadd39f11627d5b3ef1bc72867439e33ff4" + integrity sha512-G9LCaQzIqp5WmUmvHN6UUdjWrBh67MbRobmbbs5fcc2+9XFhj3vBgtyleUYjun91jSlPHoZeo+f/Pj4/WoPIJg== dependencies: bufferutil "^4.0.8" date-fns "^2.29.3" @@ -2368,14 +2368,14 @@ dependencies: qr-code-styling "^1.6.0-rc.1" -"@metamask/sdk@0.26.5": - version "0.26.5" - resolved "https://registry.yarnpkg.com/@metamask/sdk/-/sdk-0.26.5.tgz#8adf2957918d0ec06be499d995da15d2171c058e" - integrity sha512-HS/MPQCCYRS+m3dDdGLcAagwYHiPv9iUshDMBjINUywCtfUN4P2BH8xdvPOgtnzRIuRSMXqMWBbZnTvEvBeQvA== +"@metamask/sdk@0.27.0": + version "0.27.0" + resolved "https://registry.yarnpkg.com/@metamask/sdk/-/sdk-0.27.0.tgz#38617985b8305a0f5d482cdd7af8ddec87968bb7" + integrity sha512-6sMjr/0qR700X1svPGEQ4rBdtccidBLeTC27fYQc7r9ROgSixB1DUUAyu/LoySVqt3Hu/Zm7NnAHXuT228ht7A== dependencies: "@metamask/onboarding" "^1.0.1" "@metamask/providers" "16.1.0" - "@metamask/sdk-communication-layer" "0.26.4" + "@metamask/sdk-communication-layer" "0.27.0" "@metamask/sdk-install-modal-web" "0.26.5" "@types/dom-screen-wake-lock" "^1.0.0" bowser "^2.9.0" @@ -3803,23 +3803,23 @@ resolved "https://registry.yarnpkg.com/@ungap/structured-clone/-/structured-clone-1.2.0.tgz#756641adb587851b5ccb3e095daf27ae581c8406" integrity sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ== -"@wagmi/connectors@5.0.26": - version "5.0.26" - resolved "https://registry.yarnpkg.com/@wagmi/connectors/-/connectors-5.0.26.tgz#74982f6b871c63e414049951b943ce2e76d5ae22" - integrity sha512-aGc3oDQPQwVqJr7S/7IU7rF0bA61OYXGPLzj30Y3MSmmEWXtAEgKpqkhIwiEdYQAMnlR3ukbqROq8qmUm/iYQg== +"@wagmi/connectors@5.1.2": + version "5.1.2" + resolved "https://registry.yarnpkg.com/@wagmi/connectors/-/connectors-5.1.2.tgz#f94a030b277c7c2cf00cf67606c4c907b24fcb58" + integrity sha512-UX5LqDdGXrTdHBpL9wrJbcjK7/rtpOjx6YSIkO26TdPp6UyxQvEmY2XY6hdgBwHVx9xPaiVNIrWoexa5pRJUNA== dependencies: "@coinbase/wallet-sdk" "4.0.4" - "@metamask/sdk" "0.26.5" + "@metamask/sdk" "0.27.0" "@safe-global/safe-apps-provider" "0.18.3" "@safe-global/safe-apps-sdk" "9.1.0" - "@walletconnect/ethereum-provider" "2.13.0" + "@walletconnect/ethereum-provider" "2.14.0" "@walletconnect/modal" "2.6.2" cbw-sdk "npm:@coinbase/wallet-sdk@3.9.3" -"@wagmi/core@2.12.2": - version "2.12.2" - resolved "https://registry.yarnpkg.com/@wagmi/core/-/core-2.12.2.tgz#009a475a14f44999082f2e4881853e49bc655fdf" - integrity sha512-V/KmuTOBHVdg5NG5EIzLyWuXJ3f8a8YwpXM7ywjuEnGkljxh+WROKKd+I/Qc5RHK59nEhFOYWQKXuyz1szmO9A== +"@wagmi/core@2.13.1": + version "2.13.1" + resolved "https://registry.yarnpkg.com/@wagmi/core/-/core-2.13.1.tgz#d9cf910775eca0e1aeb6fe9ad787264ee32632f3" + integrity sha512-6ZdgI6dYfpa+IZPU0DZ3XQEQVzs003tKCERzSUNkxmt5cwSMg0XB1kvF5vU9MuPP96K6IcGkqSwAtgCmM5uy2w== dependencies: eventemitter3 "5.0.1" mipd "0.0.7" @@ -3834,10 +3834,10 @@ mipd "0.0.5" zustand "4.4.1" -"@walletconnect/core@2.13.0": - version "2.13.0" - resolved "https://registry.yarnpkg.com/@walletconnect/core/-/core-2.13.0.tgz#6b79b039930643e8ee85a0f512b143a35fdb8b52" - integrity sha512-blDuZxQenjeXcVJvHxPznTNl6c/2DO4VNrFnus+qHmO6OtT5lZRowdMtlCaCNb1q0OxzgrmBDcTOCbFcCpio/g== +"@walletconnect/core@2.14.0": + version "2.14.0" + resolved "https://registry.yarnpkg.com/@walletconnect/core/-/core-2.14.0.tgz#e8afb01455968b02aaf26c74f3bfcc9b82678a39" + integrity sha512-E/dgBM9q3judXnTfZQ5ILvDpeSdDpabBLsXtYXa3Nyc26cfNplfLJ2nXm9FgtTdhM1nZ7yx4+zDPiXawBRZl2g== dependencies: "@walletconnect/heartbeat" "1.2.2" "@walletconnect/jsonrpc-provider" "1.0.14" @@ -3850,8 +3850,8 @@ "@walletconnect/relay-auth" "1.0.4" "@walletconnect/safe-json" "1.0.2" "@walletconnect/time" "1.0.2" - "@walletconnect/types" "2.13.0" - "@walletconnect/utils" "2.13.0" + "@walletconnect/types" "2.14.0" + "@walletconnect/utils" "2.14.0" events "3.3.0" isomorphic-unfetch "3.1.0" lodash.isequal "4.5.0" @@ -3864,20 +3864,20 @@ dependencies: tslib "1.14.1" -"@walletconnect/ethereum-provider@2.13.0": - version "2.13.0" - resolved "https://registry.yarnpkg.com/@walletconnect/ethereum-provider/-/ethereum-provider-2.13.0.tgz#5148851983e0d55fa1c18737b2db22802c82434c" - integrity sha512-dnpW8mmLpWl1AZUYGYZpaAfGw1HFkL0WSlhk5xekx3IJJKn4pLacX2QeIOo0iNkzNQxZfux1AK4Grl1DvtzZEA== +"@walletconnect/ethereum-provider@2.14.0": + version "2.14.0" + resolved "https://registry.yarnpkg.com/@walletconnect/ethereum-provider/-/ethereum-provider-2.14.0.tgz#0ed4ba9b383c889b56e0af87181756d900fc504a" + integrity sha512-Cc2/DCn85VciA10BrsNWFM//3VC1D8yjwrjfUKjGndLPDz0YIdAxTgYZViIlMjE0lzQC/DMvPYEAnGfW0O1Bwg== dependencies: "@walletconnect/jsonrpc-http-connection" "1.0.8" "@walletconnect/jsonrpc-provider" "1.0.14" "@walletconnect/jsonrpc-types" "1.0.4" "@walletconnect/jsonrpc-utils" "1.0.8" "@walletconnect/modal" "2.6.2" - "@walletconnect/sign-client" "2.13.0" - "@walletconnect/types" "2.13.0" - "@walletconnect/universal-provider" "2.13.0" - "@walletconnect/utils" "2.13.0" + "@walletconnect/sign-client" "2.14.0" + "@walletconnect/types" "2.14.0" + "@walletconnect/universal-provider" "2.14.0" + "@walletconnect/utils" "2.14.0" events "3.3.0" "@walletconnect/events@1.0.1", "@walletconnect/events@^1.0.1": @@ -4019,19 +4019,19 @@ dependencies: tslib "1.14.1" -"@walletconnect/sign-client@2.13.0": - version "2.13.0" - resolved "https://registry.yarnpkg.com/@walletconnect/sign-client/-/sign-client-2.13.0.tgz#f59993f082aec1ca5498b9519027e764c1e6d28b" - integrity sha512-En7KSvNUlQFx20IsYGsFgkNJ2lpvDvRsSFOT5PTdGskwCkUfOpB33SQJ6nCrN19gyoKPNvWg80Cy6MJI0TjNYA== +"@walletconnect/sign-client@2.14.0": + version "2.14.0" + resolved "https://registry.yarnpkg.com/@walletconnect/sign-client/-/sign-client-2.14.0.tgz#36533ef0976a869d815624217527482c90937fc8" + integrity sha512-UrB3S3eLjPYfBLCN3WJ5u7+WcZ8kFMe/QIDqLf76Jk6TaLwkSUy563LvnSw4KW/kA+/cY1KBSdUDfX1tzYJJXg== dependencies: - "@walletconnect/core" "2.13.0" + "@walletconnect/core" "2.14.0" "@walletconnect/events" "1.0.1" "@walletconnect/heartbeat" "1.2.2" "@walletconnect/jsonrpc-utils" "1.0.8" "@walletconnect/logger" "2.1.2" "@walletconnect/time" "1.0.2" - "@walletconnect/types" "2.13.0" - "@walletconnect/utils" "2.13.0" + "@walletconnect/types" "2.14.0" + "@walletconnect/utils" "2.14.0" events "3.3.0" "@walletconnect/time@1.0.2", "@walletconnect/time@^1.0.2": @@ -4041,10 +4041,10 @@ dependencies: tslib "1.14.1" -"@walletconnect/types@2.13.0": - version "2.13.0" - resolved "https://registry.yarnpkg.com/@walletconnect/types/-/types-2.13.0.tgz#cdac083651f5897084fe9ed62779f11810335ac6" - integrity sha512-MWaVT0FkZwzYbD3tvk8F+2qpPlz1LUSWHuqbINUtMXnSzJtXN49Y99fR7FuBhNFtDalfuWsEK17GrNA+KnAsPQ== +"@walletconnect/types@2.14.0": + version "2.14.0" + resolved "https://registry.yarnpkg.com/@walletconnect/types/-/types-2.14.0.tgz#af3d4799b8ac5d166251af12bc024276f82f9b91" + integrity sha512-vevMi4jZLJ55vLuFOicQFmBBbLyb+S0sZS4IsaBdZkQflfGIq34HkN13c/KPl4Ye0aoR4/cUcUSitmGIzEQM5g== dependencies: "@walletconnect/events" "1.0.1" "@walletconnect/heartbeat" "1.2.2" @@ -4053,25 +4053,25 @@ "@walletconnect/logger" "2.1.2" events "3.3.0" -"@walletconnect/universal-provider@2.13.0": - version "2.13.0" - resolved "https://registry.yarnpkg.com/@walletconnect/universal-provider/-/universal-provider-2.13.0.tgz#f2b597001245e4d4a06d96dd1bce8d3a8a4dcbbf" - integrity sha512-B5QvO8pnk5Bqn4aIt0OukGEQn2Auk9VbHfhQb9cGwgmSCd1GlprX/Qblu4gyT5+TjHMb1Gz5UssUaZWTWbDhBg== +"@walletconnect/universal-provider@2.14.0": + version "2.14.0" + resolved "https://registry.yarnpkg.com/@walletconnect/universal-provider/-/universal-provider-2.14.0.tgz#39d029be80374894b5f4249b76282dd9211d8b9f" + integrity sha512-Mr8uoTmD6H0+Hh+3gxBu4l3T2uP/nNPR02sVtwEujNum++F727mMk+ifPRIpkVo21V/bvXFEy8sHTs5hqyq5iA== dependencies: "@walletconnect/jsonrpc-http-connection" "1.0.8" "@walletconnect/jsonrpc-provider" "1.0.14" "@walletconnect/jsonrpc-types" "1.0.4" "@walletconnect/jsonrpc-utils" "1.0.8" "@walletconnect/logger" "2.1.2" - "@walletconnect/sign-client" "2.13.0" - "@walletconnect/types" "2.13.0" - "@walletconnect/utils" "2.13.0" + "@walletconnect/sign-client" "2.14.0" + "@walletconnect/types" "2.14.0" + "@walletconnect/utils" "2.14.0" events "3.3.0" -"@walletconnect/utils@2.13.0": - version "2.13.0" - resolved "https://registry.yarnpkg.com/@walletconnect/utils/-/utils-2.13.0.tgz#1fc1fbff0d26db0830e65d1ba8cfe1a13a0616ad" - integrity sha512-q1eDCsRHj5iLe7fF8RroGoPZpdo2CYMZzQSrw1iqL+2+GOeqapxxuJ1vaJkmDUkwgklfB22ufqG6KQnz78sD4w== +"@walletconnect/utils@2.14.0": + version "2.14.0" + resolved "https://registry.yarnpkg.com/@walletconnect/utils/-/utils-2.14.0.tgz#48493ffe1e902815fda3cbd5cc5409288a066d35" + integrity sha512-vRVomYQEtEAyCK2c5bzzEvtgxaGGITF8mWuIL+WYSAMyEJLY97mirP2urDucNwcUczwxUgI+no9RiNFbUHreQQ== dependencies: "@stablelib/chacha20poly1305" "1.0.1" "@stablelib/hkdf" "1.0.1" @@ -4081,7 +4081,7 @@ "@walletconnect/relay-api" "1.0.10" "@walletconnect/safe-json" "1.0.2" "@walletconnect/time" "1.0.2" - "@walletconnect/types" "2.13.0" + "@walletconnect/types" "2.14.0" "@walletconnect/window-getters" "1.0.1" "@walletconnect/window-metadata" "1.0.1" detect-browser "5.3.0" @@ -10983,13 +10983,13 @@ viem@^2.1.1: isows "1.0.4" ws "8.17.1" -wagmi@2.11.2: - version "2.11.2" - resolved "https://registry.yarnpkg.com/wagmi/-/wagmi-2.11.2.tgz#8d508c2f7ed5f5470754a21cd4deebfa338ac5ac" - integrity sha512-yHbeI2HNo7pPGToo4ib3lKSQDfprp+flV/V8T66nxbTne0fHcNtbCiny1xe9kAE44VNFdnABrUk8d83CMC7+QA== +wagmi@2.12.2: + version "2.12.2" + resolved "https://registry.yarnpkg.com/wagmi/-/wagmi-2.12.2.tgz#1d3b1dea0783c05245aed72a29bce756eb4f0bd8" + integrity sha512-gIZdAgmHJjENdOdkD/Zpu85NR16k/uMB3H/yGBz1q9bDAE8oguuBxRUEhuMt6jAC95RB96+7hMVfL9kBtHnu+g== dependencies: - "@wagmi/connectors" "5.0.26" - "@wagmi/core" "2.12.2" + "@wagmi/connectors" "5.1.2" + "@wagmi/core" "2.13.1" use-sync-external-store "1.2.0" walker@^1.0.8: From f592e9b0d74436ba34dcf4d273052a428097664d Mon Sep 17 00:00:00 2001 From: Evgeny Taktarov Date: Fri, 2 Aug 2024 19:36:04 +0700 Subject: [PATCH 24/61] fix: united polling interval to transports --- config/get-config.ts | 6 +++--- config/groups/{estimate.ts => web3.ts} | 3 +++ providers/sdk-legacy.tsx | 14 ++++++-------- providers/web3.tsx | 17 ++++++++++++++--- shared/hooks/useApprove.ts | 4 +++- 5 files changed, 29 insertions(+), 15 deletions(-) rename config/groups/{estimate.ts => web3.ts} (70%) diff --git a/config/get-config.ts b/config/get-config.ts index 31cc81fa2..42375e98a 100644 --- a/config/get-config.ts +++ b/config/get-config.ts @@ -1,17 +1,17 @@ import { getPreConfig, PreConfigType } from './get-preconfig'; import * as cache from './groups/cache'; -import * as estimate from './groups/estimate'; import * as ipfs from './groups/ipfs'; import * as locale from './groups/locale'; import * as stake from './groups/stake'; +import * as web3 from './groups/web3'; import * as withdrawalQueueEstimate from './groups/withdrawal-queue-estimate'; export type ConfigType = { isClientSide: boolean; isServerSide: boolean; } & typeof cache & - typeof estimate & typeof ipfs & + typeof web3 & typeof locale & typeof stake & typeof withdrawalQueueEstimate & @@ -23,7 +23,7 @@ export const getConfig = (): ConfigType => { isServerSide: typeof window === 'undefined', ...cache, - ...estimate, + ...web3, ...ipfs, ...locale, ...stake, diff --git a/config/groups/estimate.ts b/config/groups/web3.ts similarity index 70% rename from config/groups/estimate.ts rename to config/groups/web3.ts index f3beb9e70..06f27f001 100644 --- a/config/groups/estimate.ts +++ b/config/groups/web3.ts @@ -1,5 +1,8 @@ import { parseEther } from '@ethersproject/units'; +// interval in ms for RPC event polling for token balance and tx updates +export const PROVIDER_POLLING_INTERVAL = 12_000; + // account for gas estimation // will always have >=0.001 ether, >=0.001 stETH, >=0.001 wstETH // on Mainnet, Holesky diff --git a/providers/sdk-legacy.tsx b/providers/sdk-legacy.tsx index 9c6203118..f01e86d86 100644 --- a/providers/sdk-legacy.tsx +++ b/providers/sdk-legacy.tsx @@ -9,17 +9,15 @@ import { mainnet } from 'wagmi/chains'; import { getStaticRpcBatchProvider } from '@lido-sdk/providers'; import { useReefKnotContext } from 'reef-knot/core-react'; -const POLLING_INTERVAL = 12_000; - type SDKLegacyProviderProps = PropsWithChildren<{ defaultChainId: number; - pollingInterval?: number; + pollingInterval: number; }>; export const SDKLegacyProvider = ({ children, defaultChainId, - pollingInterval = POLLING_INTERVAL, + pollingInterval, }: SDKLegacyProviderProps) => { const { chainId: web3ChainId = defaultChainId, account, active } = useWeb3(); const { supportedChains } = useSupportedChains(); @@ -81,8 +79,8 @@ export const SDKLegacyProvider = ({ }, [defaultChainId, supportedChainIds, web3ChainId]); const providerRpc = useMemo( - () => getStaticRpcBatchProvider(chainId, rpc[chainId], 0, POLLING_INTERVAL), - [rpc, chainId], + () => getStaticRpcBatchProvider(chainId, rpc[chainId], 0, pollingInterval), + [rpc, chainId, pollingInterval], ); const providerMainnetRpc = useMemo( @@ -91,9 +89,9 @@ export const SDKLegacyProvider = ({ mainnet.id, rpc[mainnet.id], 0, - POLLING_INTERVAL, + pollingInterval, ), - [rpc], + [rpc, pollingInterval], ); return ( diff --git a/providers/web3.tsx b/providers/web3.tsx index ea098ee6c..c13000bae 100644 --- a/providers/web3.tsx +++ b/providers/web3.tsx @@ -9,6 +9,7 @@ import { } from 'reef-knot/core-react'; import { WalletsListEthereum } from 'reef-knot/wallets'; +import { config } from 'config'; import { useUserConfig } from 'config/user-config'; import { useGetRpcUrlByChainId } from 'config/rpc'; import { CHAINS } from 'consts/chains'; @@ -67,11 +68,18 @@ const Web3Provider: FC = ({ children }) => { }); }, [backendRPC, defaultChain, walletconnectProjectId]); - const config = useMemo(() => { + const wagmiConfig = useMemo(() => { return createConfig({ chains: supportedChains, ssr: true, + batch: { + // eth_call's will be batched via multicall contract every 100ms + multicall: { + wait: 100, + }, + }, multiInjectedProviderDiscovery: false, + pollingInterval: config.PROVIDER_POLLING_INTERVAL, transports: supportedChains.reduce( (res, curr) => ({ ...res, @@ -84,7 +92,7 @@ const Web3Provider: FC = ({ children }) => { return ( // default wagmi autoConnect, MUST be false in our case, because we use custom autoConnect from Reef Knot - + = ({ children }) => { walletDataList={walletsDataList} > {isWalletConnectionAllowed && } - + {children} diff --git a/shared/hooks/useApprove.ts b/shared/hooks/useApprove.ts index 50e7f92b3..a4ad56bd8 100644 --- a/shared/hooks/useApprove.ts +++ b/shared/hooks/useApprove.ts @@ -22,7 +22,7 @@ type ApproveOptions = | undefined; export type UseApproveResponse = { - approve: (options?: ApproveOptions) => Promise; + approve: (options?: ApproveOptions) => Promise; needsApprove: boolean; initialLoading: boolean; allowance: BigNumber | undefined; @@ -87,6 +87,8 @@ export const useApprove = ( } await updateAllowance(); + + return approveTxHash; }, [ chainId, From c484514e5cd5f3371db5166922577b65179aae4c Mon Sep 17 00:00:00 2001 From: Evgeny Taktarov Date: Fri, 2 Aug 2024 19:50:49 +0700 Subject: [PATCH 25/61] chore: add qa helper --- features/withdrawals/hooks/contract/useRequest.ts | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/features/withdrawals/hooks/contract/useRequest.ts b/features/withdrawals/hooks/contract/useRequest.ts index 2b8a6c217..16a4cfba2 100644 --- a/features/withdrawals/hooks/contract/useRequest.ts +++ b/features/withdrawals/hooks/contract/useRequest.ts @@ -28,6 +28,7 @@ import { useWithdrawalsContract } from './useWithdrawalsContract'; import { useTxModalStagesRequest } from 'features/withdrawals/request/transaction-modal-request/use-tx-modal-stages-request'; import { useTransactionModal } from 'shared/transaction-modal/transaction-modal'; import { sendTx } from 'utils/send-tx'; +import { overrideWithQAMockBoolean } from 'utils/qa'; // this encapsulates permit/approval & steth/wsteth flows const useWithdrawalRequestMethods = () => { @@ -236,8 +237,13 @@ export const useWithdrawalRequest = ({ spender: withdrawalQueueAddress, }); + const isWalletConnect = overrideWithQAMockBoolean( + connector?.id === 'walletConnect', + 'mock-qa-helpers-force-approval-withdrawal-wallet-connect', + ); + const isApprovalFlow = Boolean( - connector?.id === 'walletConnect' || + isWalletConnect || isMultisig || (allowance && allowance.gt(Zero) && !needsApprove), ); From d034f3f7bff41e79ce00507ebad3acdae3125be8 Mon Sep 17 00:00:00 2001 From: Anton Shalimov Date: Fri, 2 Aug 2024 16:34:43 +0300 Subject: [PATCH 26/61] refactor: wallet block --- .../description-about-rounding-block.tsx | 13 ------------- .../description-about-rounding-block/index.ts | 1 - .../description-about-rounding-block/styles.ts | 17 ----------------- features/rewards/features/top-card/wallet.tsx | 17 +++++------------ 4 files changed, 5 insertions(+), 43 deletions(-) delete mode 100644 features/rewards/components/description-about-rounding-block/description-about-rounding-block.tsx delete mode 100644 features/rewards/components/description-about-rounding-block/index.ts delete mode 100644 features/rewards/components/description-about-rounding-block/styles.ts diff --git a/features/rewards/components/description-about-rounding-block/description-about-rounding-block.tsx b/features/rewards/components/description-about-rounding-block/description-about-rounding-block.tsx deleted file mode 100644 index 7a8c53850..000000000 --- a/features/rewards/components/description-about-rounding-block/description-about-rounding-block.tsx +++ /dev/null @@ -1,13 +0,0 @@ -import { FC, PropsWithChildren } from 'react'; - -import { DescriptionAboutRoundingBlockStyled } from './styles'; - -export const DescriptionAboutRoundingBlock: FC = ({ - children, -}) => { - return ( - - {children} - - ); -}; diff --git a/features/rewards/components/description-about-rounding-block/index.ts b/features/rewards/components/description-about-rounding-block/index.ts deleted file mode 100644 index bca33dde5..000000000 --- a/features/rewards/components/description-about-rounding-block/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './description-about-rounding-block'; diff --git a/features/rewards/components/description-about-rounding-block/styles.ts b/features/rewards/components/description-about-rounding-block/styles.ts deleted file mode 100644 index 3d42d0bb4..000000000 --- a/features/rewards/components/description-about-rounding-block/styles.ts +++ /dev/null @@ -1,17 +0,0 @@ -import styled from 'styled-components'; - -export const DescriptionAboutRoundingBlockStyled = styled.div` - flex: 1; - padding: ${({ theme }) => theme.spaceMap.sm}px; - margin-top: ${({ theme }) => theme.spaceMap.md}px; - - border-radius: ${({ theme }) => theme.spaceMap.sm}px; - - background-color: rgb(255, 172, 47, 0.1); - color: #ffac2f; - text-align: center; - - ${({ theme }) => theme.mediaQueries.md} { - margin-top: ${({ theme }) => theme.spaceMap.xl}px; - } -`; diff --git a/features/rewards/features/top-card/wallet.tsx b/features/rewards/features/top-card/wallet.tsx index 41059a52c..d7ccca0e0 100644 --- a/features/rewards/features/top-card/wallet.tsx +++ b/features/rewards/features/top-card/wallet.tsx @@ -1,10 +1,8 @@ import { FC } from 'react'; import { Box, ThemeProvider, themeDark } from '@lidofinance/lido-ui'; -import EthSymbol from 'features/rewards/components/EthSymbol'; import NumberFormat from 'features/rewards/components/NumberFormat'; import { Title } from 'features/rewards/components/stats/Title'; -import { DescriptionAboutRoundingBlock } from 'features/rewards/components/description-about-rounding-block'; import { useRewardsHistory } from 'features/rewards/hooks'; import { useRewardsBalanceData } from 'features/rewards/hooks/use-rewards-balance-data'; import { FlexCenter } from 'features/stake/stake-form/wallet/styles'; @@ -36,18 +34,18 @@ export const Wallet: FC = () => { loading={loading} value={
- + + stETH +
} > - <Box display="inline-block" pr="3px"> - {currency.symbol} - </Box> + <Box display="inline-block">{currency.symbol}</Box> <NumberFormat number={balanceData?.stEthCurrencyBalance} currency @@ -59,14 +57,9 @@ export const Wallet: FC = () => { <WalletContentAddressBadgeStyle address={address as `0x${string}`} symbolsMobile={6} - symbolsDesktop={12} + symbolsDesktop={6} /> </WalletContentRowStyle> - - <DescriptionAboutRoundingBlock> - Current balance may differ from last balance in the table due to - rounding. - </DescriptionAboutRoundingBlock> </WalletContentStyle> </ThemeProvider> </WalletStyle> From 34e390693a501ffe882ebf5bdf623ccda13e99e1 Mon Sep 17 00:00:00 2001 From: Anton Shalimov <a.shalimof@yandex.ru> Date: Fri, 2 Aug 2024 16:37:28 +0300 Subject: [PATCH 27/61] refactor: stats block --- features/rewards/components/stats/Stat.tsx | 4 ++-- features/rewards/components/stats/Stats.tsx | 25 ++++++++++----------- features/rewards/components/stats/Title.tsx | 2 +- 3 files changed, 15 insertions(+), 16 deletions(-) diff --git a/features/rewards/components/stats/Stat.tsx b/features/rewards/components/stats/Stat.tsx index f7785f6d9..f290a1376 100644 --- a/features/rewards/components/stats/Stat.tsx +++ b/features/rewards/components/stats/Stat.tsx @@ -7,11 +7,11 @@ export const Stat = ({ children, ...rest }: BoxProps) => ( <Box fontStyle="normal" fontWeight={[null, null, 600]} - fontSize={['14px', '14px', '20px']} + fontSize={['12px', '12px', '16px']} lineHeight="20px" color="text" height="20px" - mb="6px" + mb="2px" display={'flex'} {...rest} > diff --git a/features/rewards/components/stats/Stats.tsx b/features/rewards/components/stats/Stats.tsx index 1a2019a4a..7127a4c38 100644 --- a/features/rewards/components/stats/Stats.tsx +++ b/features/rewards/components/stats/Stats.tsx @@ -2,7 +2,6 @@ import { Box, Link } from '@lidofinance/lido-ui'; import { config } from 'config'; import { useRewardsHistory } from 'features/rewards/hooks'; -import EthSymbol from 'features/rewards/components/EthSymbol'; import NumberFormat from 'features/rewards/components/NumberFormat'; import { useStethEthRate } from 'features/rewards/hooks/use-steth-eth-rate'; @@ -22,15 +21,15 @@ export const Stats: React.FC = () => { return ( <> <Item data-testid="stEthRewardedBlock"> - <Title mb="8px">stETH rewarded - - + stETH earned + + + stETH + - <Box display="inline-block" pr="3px"> - {currency.symbol} - </Box> + <Box display="inline-block">{currency.symbol}</Box> <NumberFormat number={data?.totals.currencyRewards} currency @@ -40,7 +39,7 @@ export const Stats: React.FC = () => { </Item> <Item data-testid="averageAprBlock"> <Title mb="8px">Average APR - + {parseFloat(data?.averageApr || '0') ? ( ) : ( @@ -49,15 +48,13 @@ export const Stats: React.FC = () => { <Link href={`${config.rootOrigin}/ethereum#apr`}> - <Box data-testid="moreInfo" style={{ textDecoration: 'underline' }}> - More info - </Box> + <Box data-testid="moreInfo">More info</Box> </Link>
stETH price - + {currency.symbol} @@ -68,12 +65,14 @@ export const Stats: React.FC = () => { /> - <EthSymbol /> <NumberFormat number={stEthEth?.toString()} StEthEth pending={pending} /> + <Box display="inline-block" pl={'3px'}> + ETH + </Box> diff --git a/features/rewards/components/stats/Title.tsx b/features/rewards/components/stats/Title.tsx index 554af581b..8e1269c24 100644 --- a/features/rewards/components/stats/Title.tsx +++ b/features/rewards/components/stats/Title.tsx @@ -8,7 +8,7 @@ type TitleProps = BoxProps & { // TODO: refactoring to style files export const Title = ({ children, hideMobile, ...rest }: TitleProps) => ( Date: Mon, 5 Aug 2024 10:42:29 +0300 Subject: [PATCH 28/61] refactor(rewards): hide left filters --- .../components/rewardsListHeader/RewardsListHeader.tsx | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/features/rewards/components/rewardsListHeader/RewardsListHeader.tsx b/features/rewards/components/rewardsListHeader/RewardsListHeader.tsx index 9781d558e..f41fe5b5d 100644 --- a/features/rewards/components/rewardsListHeader/RewardsListHeader.tsx +++ b/features/rewards/components/rewardsListHeader/RewardsListHeader.tsx @@ -11,8 +11,12 @@ export const RewardsListHeader: FC = () => { return ( Reward history - - {!error && data && data?.events.length > 0 && } + {!error && data && data?.events.length > 0 && ( + <> + + + + )} ); }; From c2d645bd1c2dc0788bda9103aa8ee8b4c4e73d56 Mon Sep 17 00:00:00 2001 From: Anton Shalimov Date: Mon, 5 Aug 2024 11:17:24 +0300 Subject: [PATCH 29/61] refactor(rewards): filters layout --- features/rewards/components/CurrencySelector.tsx | 4 ++++ features/rewards/components/export/Exportstyled.ts | 5 +++++ features/rewards/components/rewardsListHeader/styles.ts | 4 ++-- 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/features/rewards/components/CurrencySelector.tsx b/features/rewards/components/CurrencySelector.tsx index 0de84f3ed..16f9cf297 100644 --- a/features/rewards/components/CurrencySelector.tsx +++ b/features/rewards/components/CurrencySelector.tsx @@ -11,6 +11,10 @@ const StyledSelect = styled(Select)` height: 32px; width: 72px; + ${({ theme }) => theme.mediaQueries.lg} { + width: 100%; + } + border-radius: 6px; & > span { diff --git a/features/rewards/components/export/Exportstyled.ts b/features/rewards/components/export/Exportstyled.ts index 42bcaa6be..930675c72 100644 --- a/features/rewards/components/export/Exportstyled.ts +++ b/features/rewards/components/export/Exportstyled.ts @@ -7,4 +7,9 @@ export const ButtonStyle = styled(Button)` min-width: unset; padding: 0 15px; font-size: 12px; + color: var(--lido-color-text); + + &::before { + border-color: var(--lido-color-border); + } `; diff --git a/features/rewards/components/rewardsListHeader/styles.ts b/features/rewards/components/rewardsListHeader/styles.ts index 98190d54b..ca4af30c3 100644 --- a/features/rewards/components/rewardsListHeader/styles.ts +++ b/features/rewards/components/rewardsListHeader/styles.ts @@ -4,7 +4,7 @@ export const RewardsListHeaderStyle = styled.div` display: flex; flex-wrap: wrap; align-items: center; - gap: 20px 32px; + gap: 20px 28px; height: 32px; align-items: center; @@ -39,7 +39,7 @@ export const LeftOptionsWrapper = styled.div` } ${({ theme }) => theme.mediaQueries.md} { - flex-direction: column; + flex-direction: row; } `; From 5256147d0e0a89bac29575e16280e41b4700a90d Mon Sep 17 00:00:00 2001 From: Anton Shalimov Date: Mon, 5 Aug 2024 11:17:49 +0300 Subject: [PATCH 30/61] refactor(rewards): connect button --- features/rewards/components/errorBlocks/ErrorBlockNoSteth.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/features/rewards/components/errorBlocks/ErrorBlockNoSteth.tsx b/features/rewards/components/errorBlocks/ErrorBlockNoSteth.tsx index 65ee3b46f..6c5c2bb64 100644 --- a/features/rewards/components/errorBlocks/ErrorBlockNoSteth.tsx +++ b/features/rewards/components/errorBlocks/ErrorBlockNoSteth.tsx @@ -26,7 +26,7 @@ export const ErrorBlockNoSteth = ({ hasSteth }: ErrorBlockNoStethProps) => { {!hasSteth && ( - + )} From 6fd46fa5fc936e1d61ba969bd60042108626e34c Mon Sep 17 00:00:00 2001 From: Anton Shalimov Date: Mon, 5 Aug 2024 11:31:25 +0300 Subject: [PATCH 31/61] refactor(rewards): inline loader --- shared/wallet/card/card.tsx | 6 +++--- shared/wallet/card/styles.tsx | 6 +++++- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/shared/wallet/card/card.tsx b/shared/wallet/card/card.tsx index cc8c4cd3e..68a3b3566 100644 --- a/shared/wallet/card/card.tsx +++ b/shared/wallet/card/card.tsx @@ -1,4 +1,3 @@ -import { InlineLoader } from '@lidofinance/lido-ui'; import { Component } from 'types'; import { useWalletModal } from '../wallet-modal/use-wallet-modal'; import { AddressBadge } from '../components/address-badge/address-badge'; @@ -11,6 +10,7 @@ import { WalletCardExtraStyle, WalletCardAccountStyle, WalletCardContentStyle, + InlineLoaderStyled, } from './styles'; import { WalletCardBalanceComponent, @@ -44,11 +44,11 @@ export const CardBalance: WalletCardBalanceComponent = (props) => { {title} - {loading ? : value} + {loading ? : value} {hasExtra && ( - {loading ? : extra} + {loading ? : extra} )} {hasChildren && ( diff --git a/shared/wallet/card/styles.tsx b/shared/wallet/card/styles.tsx index aa6940c92..81bf97020 100644 --- a/shared/wallet/card/styles.tsx +++ b/shared/wallet/card/styles.tsx @@ -1,5 +1,9 @@ import styled from 'styled-components'; -import { Block } from '@lidofinance/lido-ui'; +import { Block, InlineLoader } from '@lidofinance/lido-ui'; + +export const InlineLoaderStyled = styled(InlineLoader)` + max-width: 120px; +`; export const WalletCardStyle = styled((props) => )` margin-bottom: ${({ theme }) => -theme.borderRadiusesMap.xl}px; From 2e80a5a32583c772e884927c76d5c6618e31c7b9 Mon Sep 17 00:00:00 2001 From: Anton Shalimov Date: Mon, 5 Aug 2024 11:44:47 +0300 Subject: [PATCH 32/61] refactor(rewards): inline loader --- features/rewards/components/NumberFormat.tsx | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/features/rewards/components/NumberFormat.tsx b/features/rewards/components/NumberFormat.tsx index c3c8cd6d8..116bb3e02 100644 --- a/features/rewards/components/NumberFormat.tsx +++ b/features/rewards/components/NumberFormat.tsx @@ -48,7 +48,11 @@ type Props = Partial & { const NumberFormat = (props: Props) => { if (props.pending) - return ; + return ( + + ); return props.number ? ( Date: Mon, 5 Aug 2024 11:52:21 +0300 Subject: [PATCH 33/61] fix(rewards): hide filter after disconnect --- .../components/rewardsListHeader/RewardsListHeader.tsx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/features/rewards/components/rewardsListHeader/RewardsListHeader.tsx b/features/rewards/components/rewardsListHeader/RewardsListHeader.tsx index f41fe5b5d..d156454c4 100644 --- a/features/rewards/components/rewardsListHeader/RewardsListHeader.tsx +++ b/features/rewards/components/rewardsListHeader/RewardsListHeader.tsx @@ -1,5 +1,6 @@ import { FC } from 'react'; import { useRewardsHistory } from 'features/rewards/hooks'; +import { useDappStatus } from 'shared/hooks/use-dapp-status'; import { LeftOptions } from './LeftOptions'; import { RightOptions } from './RightOptions'; @@ -7,11 +8,12 @@ import { RewardsListHeaderStyle } from './styles'; import { TitleStyle } from './styles'; export const RewardsListHeader: FC = () => { + const { isDappActive } = useDappStatus(); const { error, data } = useRewardsHistory(); return ( Reward history - {!error && data && data?.events.length > 0 && ( + {isDappActive && !error && data && data?.events.length > 0 && ( <> From b57369309a181ddb8e1e2378e71de9baeca37576 Mon Sep 17 00:00:00 2001 From: Anton Shalimov Date: Mon, 5 Aug 2024 12:13:48 +0300 Subject: [PATCH 34/61] fix(rewards): remove 'Only Show Rewards' checkbox, add 'Include transfers' checkbox --- features/rewards/components/NumberFormat.tsx | 2 +- .../rewardsListHeader/LeftOptions.tsx | 28 +++++++++---------- .../rewardsListHeader/RightOptions.tsx | 4 +-- features/rewards/hooks/useRewardsDataLoad.ts | 6 ++-- providers/rewardsHistory.tsx | 16 +++++------ 5 files changed, 28 insertions(+), 28 deletions(-) diff --git a/features/rewards/components/NumberFormat.tsx b/features/rewards/components/NumberFormat.tsx index 116bb3e02..1c69066fd 100644 --- a/features/rewards/components/NumberFormat.tsx +++ b/features/rewards/components/NumberFormat.tsx @@ -50,7 +50,7 @@ const NumberFormat = (props: Props) => { if (props.pending) return ( ); diff --git a/features/rewards/components/rewardsListHeader/LeftOptions.tsx b/features/rewards/components/rewardsListHeader/LeftOptions.tsx index 5383d2c75..fef130268 100644 --- a/features/rewards/components/rewardsListHeader/LeftOptions.tsx +++ b/features/rewards/components/rewardsListHeader/LeftOptions.tsx @@ -1,19 +1,30 @@ import { FC } from 'react'; import { Tooltip, Checkbox } from '@lidofinance/lido-ui'; -import { LeftOptionsWrapper } from './styles'; import { useRewardsHistory } from 'features/rewards/hooks/useRewardsHistory'; +import { LeftOptionsWrapper } from './styles'; export const LeftOptions: FC = () => { const { isUseArchiveExchangeRate, - isOnlyRewards, + isIncludeTransfers, setIsUseArchiveExchangeRate, - setIsOnlyRewards, + setIsIncludeTransfers, } = useRewardsHistory(); return ( + + setIsIncludeTransfers(!isIncludeTransfers)} + data-testid="includeTransfersCheckbox" + label="Include transfers" + /> + - - setIsOnlyRewards(!isOnlyRewards)} - data-testid="onlyRewardsCheckbox" - label="Only Show Rewards" - /> - ); }; diff --git a/features/rewards/components/rewardsListHeader/RightOptions.tsx b/features/rewards/components/rewardsListHeader/RightOptions.tsx index 0b5252024..5b5632b6d 100644 --- a/features/rewards/components/rewardsListHeader/RightOptions.tsx +++ b/features/rewards/components/rewardsListHeader/RightOptions.tsx @@ -11,7 +11,7 @@ export const RightOptions: FC = () => { currencyObject, setCurrency, isUseArchiveExchangeRate, - isOnlyRewards, + isIncludeTransfers, } = useRewardsHistory(); return ( @@ -20,7 +20,7 @@ export const RightOptions: FC = () => { currency={currencyObject} address={address} archiveRate={isUseArchiveExchangeRate} - onlyRewards={isOnlyRewards} + onlyRewards={!isIncludeTransfers} /> ); diff --git a/features/rewards/hooks/useRewardsDataLoad.ts b/features/rewards/hooks/useRewardsDataLoad.ts index 064219e8a..5696098cf 100644 --- a/features/rewards/hooks/useRewardsDataLoad.ts +++ b/features/rewards/hooks/useRewardsDataLoad.ts @@ -7,7 +7,7 @@ import { useLaggyDataWrapper } from './use-laggy-data-wrapper'; type UseRewardsDataLoad = (props: { address: string; currency: string; - isOnlyRewards: boolean; + isIncludeTransfers: boolean; isUseArchiveExchangeRate: boolean; skip: number; limit: number; @@ -23,7 +23,7 @@ export const useRewardsDataLoad: UseRewardsDataLoad = (props) => { const { address, currency, - isOnlyRewards, + isIncludeTransfers, isUseArchiveExchangeRate, skip, limit, @@ -32,7 +32,7 @@ export const useRewardsDataLoad: UseRewardsDataLoad = (props) => { const requestOptions = { address, currency, - onlyRewards: isOnlyRewards, + onlyRewards: !isIncludeTransfers, archiveRate: isUseArchiveExchangeRate, skip, limit, diff --git a/providers/rewardsHistory.tsx b/providers/rewardsHistory.tsx index 05dbb6ced..fe25eea3f 100644 --- a/providers/rewardsHistory.tsx +++ b/providers/rewardsHistory.tsx @@ -34,11 +34,11 @@ export type RewardsHistoryValue = { address: string; addressError: string; inputValue: string; - isOnlyRewards: boolean; + isIncludeTransfers: boolean; isUseArchiveExchangeRate: boolean; isLagging: boolean; setInputValue: (value: string) => void; - setIsOnlyRewards: (value: boolean) => void; + setIsIncludeTransfers: (value: boolean) => void; setIsUseArchiveExchangeRate: (value: boolean) => void; setPage: (page: number) => void; setCurrency: (value: string) => void; @@ -56,7 +56,7 @@ const RewardsHistoryProvider: FC = (props) => { if (currencyValue) setCurrency(currencyValue); }, []); - const [isOnlyRewards, setIsOnlyRewards] = useState(false); + const [isIncludeTransfers, setIsIncludeTransfers] = useState(false); const [isUseArchiveExchangeRate, setIsUseArchiveExchangeRate] = useState(true); const [page, setPage] = useState(0); @@ -75,7 +75,7 @@ const RewardsHistoryProvider: FC = (props) => { const { data, error, loading, initialLoading, isLagging } = useRewardsDataLoad({ address, - isOnlyRewards, + isIncludeTransfers, isUseArchiveExchangeRate, currency, skip, @@ -84,7 +84,7 @@ const RewardsHistoryProvider: FC = (props) => { useEffect(() => { setPage(0); - }, [isUseArchiveExchangeRate, isOnlyRewards]); + }, [isUseArchiveExchangeRate, isIncludeTransfers]); const currencyObject = getCurrency(currency); @@ -99,8 +99,8 @@ const RewardsHistoryProvider: FC = (props) => { limit, page, setPage, - isOnlyRewards, - setIsOnlyRewards, + isIncludeTransfers, + setIsIncludeTransfers, setIsUseArchiveExchangeRate, isUseArchiveExchangeRate, setCurrency, @@ -121,7 +121,7 @@ const RewardsHistoryProvider: FC = (props) => { inputValue, isAddressResolving, isLagging, - isOnlyRewards, + isIncludeTransfers, isUseArchiveExchangeRate, limit, loading, From 5dce3fc9f16a9e85b96d6caefc86c4059eb3a9c8 Mon Sep 17 00:00:00 2001 From: Anton Shalimov Date: Mon, 5 Aug 2024 12:40:58 +0300 Subject: [PATCH 35/61] fix(rewards): remove InputWrapper component --- .../rewards/components/inputWrapper/InputWrapper.tsx | 11 ----------- .../components/inputWrapper/InputWrapperStyles.ts | 7 ------- features/rewards/components/inputWrapper/index.ts | 1 - 3 files changed, 19 deletions(-) delete mode 100644 features/rewards/components/inputWrapper/InputWrapper.tsx delete mode 100644 features/rewards/components/inputWrapper/InputWrapperStyles.ts delete mode 100644 features/rewards/components/inputWrapper/index.ts diff --git a/features/rewards/components/inputWrapper/InputWrapper.tsx b/features/rewards/components/inputWrapper/InputWrapper.tsx deleted file mode 100644 index 4de38fd82..000000000 --- a/features/rewards/components/inputWrapper/InputWrapper.tsx +++ /dev/null @@ -1,11 +0,0 @@ -import { FC, PropsWithChildren } from 'react'; -import { BlockProps } from '@lidofinance/lido-ui'; - -import { InputWrapperStyle } from './InputWrapperStyles'; - -export const InputWrapper: FC> = ({ - children, - ...rest -}) => { - return {children}; -}; diff --git a/features/rewards/components/inputWrapper/InputWrapperStyles.ts b/features/rewards/components/inputWrapper/InputWrapperStyles.ts deleted file mode 100644 index 268743da1..000000000 --- a/features/rewards/components/inputWrapper/InputWrapperStyles.ts +++ /dev/null @@ -1,7 +0,0 @@ -import styled from 'styled-components'; -import { Block } from '@lidofinance/lido-ui'; - -export const InputWrapperStyle = styled(Block)` - background: transparent; - padding-bottom: 24px; -`; diff --git a/features/rewards/components/inputWrapper/index.ts b/features/rewards/components/inputWrapper/index.ts deleted file mode 100644 index ff6f77010..000000000 --- a/features/rewards/components/inputWrapper/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './InputWrapper'; From 8648ee486f349c82fd5b8a3d9d7a9ae3a16d8676 Mon Sep 17 00:00:00 2001 From: Anton Shalimov Date: Mon, 5 Aug 2024 13:00:05 +0300 Subject: [PATCH 36/61] refactor(rewards): paddings --- features/rewards/components/stats/Stats.tsx | 4 +++- features/rewards/features/top-card/wallet.tsx | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/features/rewards/components/stats/Stats.tsx b/features/rewards/components/stats/Stats.tsx index 7127a4c38..b28e1d894 100644 --- a/features/rewards/components/stats/Stats.tsx +++ b/features/rewards/components/stats/Stats.tsx @@ -29,7 +29,9 @@ export const Stats: React.FC = () => { - <Box display="inline-block">{currency.symbol}</Box> + <Box display="inline-block" pr={'3px'}> + {currency.symbol} + </Box> <NumberFormat number={data?.totals.currencyRewards} currency diff --git a/features/rewards/features/top-card/wallet.tsx b/features/rewards/features/top-card/wallet.tsx index d7ccca0e0..3f16d3946 100644 --- a/features/rewards/features/top-card/wallet.tsx +++ b/features/rewards/features/top-card/wallet.tsx @@ -45,7 +45,9 @@ export const Wallet: FC = () => { } > <Title data-testid="stEthBalanceIn$" hideMobile> - <Box display="inline-block">{currency.symbol}</Box> + <Box display="inline-block" pr={'3px'}> + {currency.symbol} + </Box> <NumberFormat number={balanceData?.stEthCurrencyBalance} currency From d93d073777bb72a3fbff5491759ec3de04809d5a Mon Sep 17 00:00:00 2001 From: Anton Shalimov <a.shalimof@yandex.ru> Date: Mon, 5 Aug 2024 13:07:10 +0300 Subject: [PATCH 37/61] refactor(rewards): stake now wrapper width --- features/rewards/components/errorBlocks/ErrorBlockNoSteth.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/features/rewards/components/errorBlocks/ErrorBlockNoSteth.tsx b/features/rewards/components/errorBlocks/ErrorBlockNoSteth.tsx index 6c5c2bb64..f2d09ec0f 100644 --- a/features/rewards/components/errorBlocks/ErrorBlockNoSteth.tsx +++ b/features/rewards/components/errorBlocks/ErrorBlockNoSteth.tsx @@ -25,7 +25,7 @@ export const ErrorBlockNoSteth = ({ hasSteth }: ErrorBlockNoStethProps) => { </Box> <LocalLink href={HOME_PATH}> {!hasSteth && ( - <Box width="150px"> + <Box> <Button size={'xs'}>Stake now</Button> </Box> )} From feea85f734c6f6ef41201e2eba24ded0bcabbffc Mon Sep 17 00:00:00 2001 From: Anton Shalimov <a.shalimof@yandex.ru> Date: Mon, 5 Aug 2024 13:33:46 +0300 Subject: [PATCH 38/61] fix: tests --- test/consts.ts | 110 ------------------------------------------------- 1 file changed, 110 deletions(-) diff --git a/test/consts.ts b/test/consts.ts index 295fc7eaa..3b8f03ef7 100644 --- a/test/consts.ts +++ b/test/consts.ts @@ -13,8 +13,6 @@ export interface PostRequest { schema: object; } -const FLOAT_REGEX = /^\d+(\.\d+)?$/; - const LIDO_STATS_SCHEMA = { type: 'object', properties: { @@ -164,46 +162,6 @@ const LIDO_STATS_SCHEMA = { }; export const GET_REQUESTS: GetRequest[] = [ - { - uri: '/api/oneinch-rate', - schema: { - type: 'object', - properties: { - rate: { type: 'number', min: 0 }, - toReceive: { type: 'string' }, - }, - required: ['rate', 'toReceive'], - additionalProperties: false, - }, - }, - { - uri: `/api/short-lido-stats?chainId=${CONFIG.STAND_CONFIG.chainId}`, - schema: { - type: 'object', - properties: { - uniqueAnytimeHolders: { type: 'string' }, - uniqueHolders: { type: 'string' }, - totalStaked: { type: 'string' }, - marketCap: { type: 'number' }, - }, - required: [ - 'totalStaked', - 'marketCap', - 'uniqueAnytimeHolders', - 'uniqueHolders', - ], - additionalProperties: false, - }, - }, - { - uri: '/api/eth-apr', - isDeprecated: true, - schema: { type: 'string', pattern: FLOAT_REGEX }, - }, - { - uri: '/api/totalsupply', - schema: { type: 'string', pattern: FLOAT_REGEX }, - }, { uri: '/api/lidostats', isDeprecated: true, @@ -214,74 +172,6 @@ export const GET_REQUESTS: GetRequest[] = [ isDeprecated: true, schema: LIDO_STATS_SCHEMA, }, - { - uri: '/api/eth-price', - schema: { - type: 'object', - properties: { - price: { - type: 'number', - min: 0, - }, - }, - required: ['price'], - additionalProperties: false, - }, - }, - { - uri: '/api/rewards?address=0x87c0e047F4e4D3e289A56a36570D4CB957A37Ef1¤cy=usd&onlyRewards=false&archiveRate=true&skip=0&limit=10', - skipTestnet: true, // api/rewards don't work on testnet - schema: { - type: 'object', - properties: { - averageApr: { type: 'string' }, - ethToStEthRatio: { type: 'number' }, - events: { - type: 'array', - items: [ - { - type: 'object', - additionalProperties: true, - }, - ], - }, - stETHCurrencyPrice: { - type: 'object', - properties: { - eth: { type: 'number' }, - usd: { type: 'number' }, - }, - required: ['eth', 'usd'], - additionalProperties: false, - }, - totalItems: { type: 'number' }, - totals: { - type: 'object', - properties: { - currencyRewards: { type: 'string' }, - ethRewards: { type: 'string' }, - }, - }, - required: [ - 'averageApr', - 'ethToStEthRatio', - 'events', - 'stETHCurrencyPrice', - 'totalItems', - 'totals', - ], - additionalProperties: false, - }, - }, - }, - { - uri: '/api/sma-steth-apr', - isDeprecated: true, - schema: { - type: 'string', - pattern: FLOAT_REGEX, - }, - }, ]; export const POST_REQUESTS: PostRequest[] = [ From 48e4c81d947a36067c573129f91c3df99304a87f Mon Sep 17 00:00:00 2001 From: Anton Shalimov <a.shalimof@yandex.ru> Date: Mon, 5 Aug 2024 19:05:14 +0300 Subject: [PATCH 39/61] fix: tests after remove some api methods --- test/consts.ts | 110 ------------------------------------------------- 1 file changed, 110 deletions(-) diff --git a/test/consts.ts b/test/consts.ts index 295fc7eaa..3b8f03ef7 100644 --- a/test/consts.ts +++ b/test/consts.ts @@ -13,8 +13,6 @@ export interface PostRequest { schema: object; } -const FLOAT_REGEX = /^\d+(\.\d+)?$/; - const LIDO_STATS_SCHEMA = { type: 'object', properties: { @@ -164,46 +162,6 @@ const LIDO_STATS_SCHEMA = { }; export const GET_REQUESTS: GetRequest[] = [ - { - uri: '/api/oneinch-rate', - schema: { - type: 'object', - properties: { - rate: { type: 'number', min: 0 }, - toReceive: { type: 'string' }, - }, - required: ['rate', 'toReceive'], - additionalProperties: false, - }, - }, - { - uri: `/api/short-lido-stats?chainId=${CONFIG.STAND_CONFIG.chainId}`, - schema: { - type: 'object', - properties: { - uniqueAnytimeHolders: { type: 'string' }, - uniqueHolders: { type: 'string' }, - totalStaked: { type: 'string' }, - marketCap: { type: 'number' }, - }, - required: [ - 'totalStaked', - 'marketCap', - 'uniqueAnytimeHolders', - 'uniqueHolders', - ], - additionalProperties: false, - }, - }, - { - uri: '/api/eth-apr', - isDeprecated: true, - schema: { type: 'string', pattern: FLOAT_REGEX }, - }, - { - uri: '/api/totalsupply', - schema: { type: 'string', pattern: FLOAT_REGEX }, - }, { uri: '/api/lidostats', isDeprecated: true, @@ -214,74 +172,6 @@ export const GET_REQUESTS: GetRequest[] = [ isDeprecated: true, schema: LIDO_STATS_SCHEMA, }, - { - uri: '/api/eth-price', - schema: { - type: 'object', - properties: { - price: { - type: 'number', - min: 0, - }, - }, - required: ['price'], - additionalProperties: false, - }, - }, - { - uri: '/api/rewards?address=0x87c0e047F4e4D3e289A56a36570D4CB957A37Ef1¤cy=usd&onlyRewards=false&archiveRate=true&skip=0&limit=10', - skipTestnet: true, // api/rewards don't work on testnet - schema: { - type: 'object', - properties: { - averageApr: { type: 'string' }, - ethToStEthRatio: { type: 'number' }, - events: { - type: 'array', - items: [ - { - type: 'object', - additionalProperties: true, - }, - ], - }, - stETHCurrencyPrice: { - type: 'object', - properties: { - eth: { type: 'number' }, - usd: { type: 'number' }, - }, - required: ['eth', 'usd'], - additionalProperties: false, - }, - totalItems: { type: 'number' }, - totals: { - type: 'object', - properties: { - currencyRewards: { type: 'string' }, - ethRewards: { type: 'string' }, - }, - }, - required: [ - 'averageApr', - 'ethToStEthRatio', - 'events', - 'stETHCurrencyPrice', - 'totalItems', - 'totals', - ], - additionalProperties: false, - }, - }, - }, - { - uri: '/api/sma-steth-apr', - isDeprecated: true, - schema: { - type: 'string', - pattern: FLOAT_REGEX, - }, - }, ]; export const POST_REQUESTS: PostRequest[] = [ From 65964b8a07df21141f485f0a99670fda4eea1578 Mon Sep 17 00:00:00 2001 From: Anton Shalimov <a.shalimof@yandex.ru> Date: Mon, 5 Aug 2024 19:33:04 +0300 Subject: [PATCH 40/61] fix(test): add 200 status code to expected --- test/consts.ts | 110 +++++++++++++++++++++++++++++++++++++++++++++ test/smoke.spec.ts | 2 +- 2 files changed, 111 insertions(+), 1 deletion(-) diff --git a/test/consts.ts b/test/consts.ts index 3b8f03ef7..295fc7eaa 100644 --- a/test/consts.ts +++ b/test/consts.ts @@ -13,6 +13,8 @@ export interface PostRequest { schema: object; } +const FLOAT_REGEX = /^\d+(\.\d+)?$/; + const LIDO_STATS_SCHEMA = { type: 'object', properties: { @@ -162,6 +164,46 @@ const LIDO_STATS_SCHEMA = { }; export const GET_REQUESTS: GetRequest[] = [ + { + uri: '/api/oneinch-rate', + schema: { + type: 'object', + properties: { + rate: { type: 'number', min: 0 }, + toReceive: { type: 'string' }, + }, + required: ['rate', 'toReceive'], + additionalProperties: false, + }, + }, + { + uri: `/api/short-lido-stats?chainId=${CONFIG.STAND_CONFIG.chainId}`, + schema: { + type: 'object', + properties: { + uniqueAnytimeHolders: { type: 'string' }, + uniqueHolders: { type: 'string' }, + totalStaked: { type: 'string' }, + marketCap: { type: 'number' }, + }, + required: [ + 'totalStaked', + 'marketCap', + 'uniqueAnytimeHolders', + 'uniqueHolders', + ], + additionalProperties: false, + }, + }, + { + uri: '/api/eth-apr', + isDeprecated: true, + schema: { type: 'string', pattern: FLOAT_REGEX }, + }, + { + uri: '/api/totalsupply', + schema: { type: 'string', pattern: FLOAT_REGEX }, + }, { uri: '/api/lidostats', isDeprecated: true, @@ -172,6 +214,74 @@ export const GET_REQUESTS: GetRequest[] = [ isDeprecated: true, schema: LIDO_STATS_SCHEMA, }, + { + uri: '/api/eth-price', + schema: { + type: 'object', + properties: { + price: { + type: 'number', + min: 0, + }, + }, + required: ['price'], + additionalProperties: false, + }, + }, + { + uri: '/api/rewards?address=0x87c0e047F4e4D3e289A56a36570D4CB957A37Ef1¤cy=usd&onlyRewards=false&archiveRate=true&skip=0&limit=10', + skipTestnet: true, // api/rewards don't work on testnet + schema: { + type: 'object', + properties: { + averageApr: { type: 'string' }, + ethToStEthRatio: { type: 'number' }, + events: { + type: 'array', + items: [ + { + type: 'object', + additionalProperties: true, + }, + ], + }, + stETHCurrencyPrice: { + type: 'object', + properties: { + eth: { type: 'number' }, + usd: { type: 'number' }, + }, + required: ['eth', 'usd'], + additionalProperties: false, + }, + totalItems: { type: 'number' }, + totals: { + type: 'object', + properties: { + currencyRewards: { type: 'string' }, + ethRewards: { type: 'string' }, + }, + }, + required: [ + 'averageApr', + 'ethToStEthRatio', + 'events', + 'stETHCurrencyPrice', + 'totalItems', + 'totals', + ], + additionalProperties: false, + }, + }, + }, + { + uri: '/api/sma-steth-apr', + isDeprecated: true, + schema: { + type: 'string', + pattern: FLOAT_REGEX, + }, + }, ]; export const POST_REQUESTS: PostRequest[] = [ diff --git a/test/smoke.spec.ts b/test/smoke.spec.ts index 3f2d2a83c..9a65dff84 100644 --- a/test/smoke.spec.ts +++ b/test/smoke.spec.ts @@ -19,7 +19,7 @@ test.describe('Smoke GET', () => { const resp = await request.get(element.uri); if (element.isDeprecated) { - expect([299, 410]).toContain(resp.status()); + expect([200, 299, 410]).toContain(resp.status()); if (resp.status() === 299) { expect(resp.headers()).toHaveProperty('warning'); expect(resp.headers()).toHaveProperty('deprecation'); From 665cb5928189788fed64b06bbc86d523205bf996 Mon Sep 17 00:00:00 2001 From: Evgeny Taktarov <je.mouth@gmail.com> Date: Tue, 6 Aug 2024 12:42:06 +0700 Subject: [PATCH 41/61] fix: use static provider for isMultisig --- features/withdrawals/hooks/useNftDataByTxHash.ts | 12 +++++------- .../wsteth/wrap/hooks/use-wrap-form-processing.ts | 6 +----- shared/hooks/useApprove.ts | 2 +- 3 files changed, 7 insertions(+), 13 deletions(-) diff --git a/features/withdrawals/hooks/useNftDataByTxHash.ts b/features/withdrawals/hooks/useNftDataByTxHash.ts index 3f675ee89..098f719c9 100644 --- a/features/withdrawals/hooks/useNftDataByTxHash.ts +++ b/features/withdrawals/hooks/useNftDataByTxHash.ts @@ -1,9 +1,9 @@ -import { useSDK } from '@lido-sdk/react'; import { useLidoSWR } from '@lido-sdk/react'; import { useWithdrawalsContract } from './contract/useWithdrawalsContract'; import { standardFetcher } from 'utils/standardFetcher'; import type { TransactionReceipt } from '@ethersproject/abstract-provider'; +import { useCurrentStaticRpcProvider } from 'shared/hooks/use-current-static-rpc-provider'; const EVENT_NAME = 'WithdrawalRequested'; @@ -15,17 +15,15 @@ type NFTApiData = { export const useNftDataByTxHash = (txHash: string | null) => { const { contractRpc, account } = useWithdrawalsContract(); - const { providerWeb3 } = useSDK(); + const { staticRpcProvider } = useCurrentStaticRpcProvider(); const swrNftApiData = useLidoSWR( - account && txHash && providerWeb3 - ? ['swr:nft-data-by-tx-hash', txHash, account] - : null, + account && txHash ? ['swr:nft-data-by-tx-hash', txHash, account] : null, async () => { - if (!txHash || !account || !providerWeb3) return null; + if (!txHash || !account) return null; const txReciept: TransactionReceipt = - await providerWeb3.getTransactionReceipt(txHash); + await staticRpcProvider.getTransactionReceipt(txHash); const eventTopic = contractRpc.interface.getEventTopic(EVENT_NAME); const eventLogs = txReciept.logs.filter( diff --git a/features/wsteth/wrap/hooks/use-wrap-form-processing.ts b/features/wsteth/wrap/hooks/use-wrap-form-processing.ts index 0b3789ba9..3c5daa786 100644 --- a/features/wsteth/wrap/hooks/use-wrap-form-processing.ts +++ b/features/wsteth/wrap/hooks/use-wrap-form-processing.ts @@ -1,7 +1,6 @@ import invariant from 'tiny-invariant'; import { useCallback } from 'react'; -import { useSDK } from '@lido-sdk/react'; import { useWeb3 } from 'reef-knot/web3-react'; import { useWrapTxProcessing } from './use-wrap-tx-processing'; import { useTxModalWrap } from './use-tx-modal-stages-wrap'; @@ -27,7 +26,6 @@ export const useWrapFormProcessor = ({ onRetry, }: UseWrapFormProcessorArgs) => { const { account } = useWeb3(); - const { providerWeb3 } = useSDK(); const processWrapTx = useWrapTxProcessing(); const { isApprovalNeededBeforeWrap, processApproveTx } = approvalData; const { txModalStages } = useTxModalWrap(); @@ -39,8 +37,7 @@ export const useWrapFormProcessor = ({ try { invariant(amount, 'amount should be presented'); invariant(account, 'address should be presented'); - invariant(providerWeb3, 'provider should be presented'); - const isMultisig = await isContract(account, providerWeb3); + const isMultisig = await isContract(account, staticRpcProvider); const willReceive = await wstETHContractRPC.getWstETHByStETH(amount); if (isApprovalNeededBeforeWrap) { @@ -89,7 +86,6 @@ export const useWrapFormProcessor = ({ }, [ account, - providerWeb3, wstETHContractRPC, isApprovalNeededBeforeWrap, txModalStages, diff --git a/shared/hooks/useApprove.ts b/shared/hooks/useApprove.ts index a4ad56bd8..4c962f330 100644 --- a/shared/hooks/useApprove.ts +++ b/shared/hooks/useApprove.ts @@ -57,7 +57,7 @@ export const useApprove = ( invariant(account, 'account is required'); await onTxStart?.(); const contractWeb3 = getERC20Contract(token, providerWeb3.getSigner()); - const isMultisig = await isContract(account, providerWeb3); + const isMultisig = await isContract(account, staticRpcProvider); const processApproveTx = async () => { const tx = await contractWeb3.populateTransaction.approve( From 9c51aa24a372105c3ae1f7ac2f592fceca259b9e Mon Sep 17 00:00:00 2001 From: Evgeny Taktarov <je.mouth@gmail.com> Date: Tue, 6 Aug 2024 14:17:21 +0700 Subject: [PATCH 42/61] fix: rpc urls --- pages/api/rpc.ts | 2 +- test/consts.ts | 158 ----------------------------------------------- 2 files changed, 1 insertion(+), 159 deletions(-) diff --git a/pages/api/rpc.ts b/pages/api/rpc.ts index a8f0455fd..01eaa99d1 100644 --- a/pages/api/rpc.ts +++ b/pages/api/rpc.ts @@ -47,8 +47,8 @@ const rpc = rpcFactory({ defaultChain: `${config.defaultChain}`, providers: { [CHAINS.Mainnet]: secretConfig.rpcUrls_1, - [CHAINS.Goerli]: secretConfig.rpcUrls_5, [CHAINS.Holesky]: secretConfig.rpcUrls_17000, + [CHAINS.Sepolia]: secretConfig.rpcUrls_11155111, }, }); diff --git a/test/consts.ts b/test/consts.ts index b070b3953..8dae119cd 100644 --- a/test/consts.ts +++ b/test/consts.ts @@ -15,154 +15,6 @@ export interface PostRequest { const FLOAT_REGEX = /^\d+(\.\d+)?$/; -const LIDO_STATS_SCHEMA = { - type: 'object', - properties: { - data: { - type: 'object', - properties: { - address: { - type: 'string', - }, - decimals: { - type: 'string', - }, - name: { - type: 'string', - }, - symbol: { - type: 'string', - }, - totalSupply: { - type: 'string', - }, - transfersCount: { - type: 'integer', - }, - txsCount: { - type: 'integer', - }, - lastUpdated: { - type: 'integer', - }, - issuancesCount: { - type: 'integer', - }, - holdersCount: { - type: 'integer', - }, - website: { - type: 'string', - }, - image: { - type: 'string', - }, - ethTransfersCount: { - type: 'integer', - }, - price: { - type: 'object', - properties: { - rate: { - type: 'number', - }, - diff: { - type: 'number', - }, - diff7d: { - type: 'number', - }, - ts: { - type: 'integer', - }, - marketCapUsd: { - type: 'number', - }, - availableSupply: { - type: 'number', - }, - volume24h: { - type: 'number', - }, - volDiff1: { - type: 'number', - }, - volDiff7: { - type: 'number', - }, - volDiff30: { - type: 'number', - }, - diff30d: { - type: 'number', - }, - bid: { - type: 'number', - }, - tsAdded: { - type: 'number', - }, - currency: { - type: 'string', - }, - }, - required: [ - 'rate', - 'diff', - 'diff7d', - 'ts', - 'marketCapUsd', - 'availableSupply', - 'volume24h', - 'volDiff1', - 'volDiff7', - 'volDiff30', - 'diff30d', - 'bid', - 'currency', - ], - additionalProperties: false, - }, - publicTags: { - type: 'array', - items: [ - { - type: 'string', - }, - ], - }, - owner: { - type: 'string', - }, - countOps: { - type: 'integer', - }, - }, - required: [ - 'address', - 'decimals', - 'name', - 'symbol', - 'totalSupply', - 'transfersCount', - 'txsCount', - 'lastUpdated', - 'issuancesCount', - 'holdersCount', - 'website', - 'image', - 'price', - 'publicTags', - 'owner', - 'countOps', - ], - additionalProperties: false, - }, - }, - required: ['data'], - additionalProperties: false, -}; - export const GET_REQUESTS: GetRequest[] = [ { uri: '/api/oneinch-rate?token=ETH', @@ -208,16 +60,6 @@ export const GET_REQUESTS: GetRequest[] = [ isDeprecated: true, schema: { type: 'string', pattern: FLOAT_REGEX }, }, - { - uri: '/api/lidostats', - isDeprecated: true, - schema: LIDO_STATS_SCHEMA, - }, - { - uri: '/api/ldo-stats', - isDeprecated: true, - schema: LIDO_STATS_SCHEMA, - }, { uri: '/api/eth-price', isDeprecated: true, From b0fb6296173e0a97278204ae9ceadedefbdf1ef2 Mon Sep 17 00:00:00 2001 From: Anton Shalimov <a.shalimof@yandex.ru> Date: Tue, 6 Aug 2024 11:51:58 +0300 Subject: [PATCH 43/61] feat(rewards): reset stats after disconnect --- features/rewards/components/stats/Stats.tsx | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/features/rewards/components/stats/Stats.tsx b/features/rewards/components/stats/Stats.tsx index b28e1d894..34c9a6b24 100644 --- a/features/rewards/components/stats/Stats.tsx +++ b/features/rewards/components/stats/Stats.tsx @@ -4,6 +4,7 @@ import { config } from 'config'; import { useRewardsHistory } from 'features/rewards/hooks'; import NumberFormat from 'features/rewards/components/NumberFormat'; import { useStethEthRate } from 'features/rewards/hooks/use-steth-eth-rate'; +import { useDappStatus } from 'shared/hooks/use-dapp-status'; import { Item } from './Item'; import { Stat } from './Stat'; @@ -17,13 +18,17 @@ export const Stats: React.FC = () => { initialLoading: pending, } = useRewardsHistory(); const { data: stEthEth } = useStethEthRate(); + const { isDappActive } = useDappStatus(); return ( <> <Item data-testid="stEthRewardedBlock"> <Title mb="8px">stETH earned - + stETH @@ -33,7 +38,7 @@ export const Stats: React.FC = () => { {currency.symbol} @@ -43,7 +48,11 @@ export const Stats: React.FC = () => { Average APR {parseFloat(data?.averageApr || '0') ? ( - + ) : ( '-' )} @@ -61,14 +70,16 @@ export const Stats: React.FC = () => { {currency.symbol} <NumberFormat - number={stEthEth?.toString()} + number={isDappActive ? stEthEth?.toString() : undefined} StEthEth pending={pending} /> From 368dc6c2cf87e9938507f9aa1d7ab732419f8878 Mon Sep 17 00:00:00 2001 From: Anton Shalimov <a.shalimof@yandex.ru> Date: Tue, 6 Aug 2024 12:00:11 +0300 Subject: [PATCH 44/61] revert: tests --- test/consts.ts | 110 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 110 insertions(+) diff --git a/test/consts.ts b/test/consts.ts index 3b8f03ef7..295fc7eaa 100644 --- a/test/consts.ts +++ b/test/consts.ts @@ -13,6 +13,8 @@ export interface PostRequest { schema: object; } +const FLOAT_REGEX = /^\d+(\.\d+)?$/; + const LIDO_STATS_SCHEMA = { type: 'object', properties: { @@ -162,6 +164,46 @@ const LIDO_STATS_SCHEMA = { }; export const GET_REQUESTS: GetRequest[] = [ + { + uri: '/api/oneinch-rate', + schema: { + type: 'object', + properties: { + rate: { type: 'number', min: 0 }, + toReceive: { type: 'string' }, + }, + required: ['rate', 'toReceive'], + additionalProperties: false, + }, + }, + { + uri: `/api/short-lido-stats?chainId=${CONFIG.STAND_CONFIG.chainId}`, + schema: { + type: 'object', + properties: { + uniqueAnytimeHolders: { type: 'string' }, + uniqueHolders: { type: 'string' }, + totalStaked: { type: 'string' }, + marketCap: { type: 'number' }, + }, + required: [ + 'totalStaked', + 'marketCap', + 'uniqueAnytimeHolders', + 'uniqueHolders', + ], + additionalProperties: false, + }, + }, + { + uri: '/api/eth-apr', + isDeprecated: true, + schema: { type: 'string', pattern: FLOAT_REGEX }, + }, + { + uri: '/api/totalsupply', + schema: { type: 'string', pattern: FLOAT_REGEX }, + }, { uri: '/api/lidostats', isDeprecated: true, @@ -172,6 +214,74 @@ export const GET_REQUESTS: GetRequest[] = [ isDeprecated: true, schema: LIDO_STATS_SCHEMA, }, + { + uri: '/api/eth-price', + schema: { + type: 'object', + properties: { + price: { + type: 'number', + min: 0, + }, + }, + required: ['price'], + additionalProperties: false, + }, + }, + { + uri: '/api/rewards?address=0x87c0e047F4e4D3e289A56a36570D4CB957A37Ef1¤cy=usd&onlyRewards=false&archiveRate=true&skip=0&limit=10', + skipTestnet: true, // api/rewards don't work on testnet + schema: { + type: 'object', + properties: { + averageApr: { type: 'string' }, + ethToStEthRatio: { type: 'number' }, + events: { + type: 'array', + items: [ + { + type: 'object', + additionalProperties: true, + }, + ], + }, + stETHCurrencyPrice: { + type: 'object', + properties: { + eth: { type: 'number' }, + usd: { type: 'number' }, + }, + required: ['eth', 'usd'], + additionalProperties: false, + }, + totalItems: { type: 'number' }, + totals: { + type: 'object', + properties: { + currencyRewards: { type: 'string' }, + ethRewards: { type: 'string' }, + }, + }, + required: [ + 'averageApr', + 'ethToStEthRatio', + 'events', + 'stETHCurrencyPrice', + 'totalItems', + 'totals', + ], + additionalProperties: false, + }, + }, + }, + { + uri: '/api/sma-steth-apr', + isDeprecated: true, + schema: { + type: 'string', + pattern: FLOAT_REGEX, + }, + }, ]; export const POST_REQUESTS: PostRequest[] = [ From 9c3484d85d33d685882b3e0e6cc16ae3be45a007 Mon Sep 17 00:00:00 2001 From: Anton Shalimov <a.shalimof@yandex.ru> Date: Tue, 6 Aug 2024 12:22:33 +0300 Subject: [PATCH 45/61] feat: add `mock-qa-rewards-address` for rewards table --- features/rewards/hooks/useGetCurrentAddress.ts | 7 ++++++- utils/qa.ts | 10 ++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/features/rewards/hooks/useGetCurrentAddress.ts b/features/rewards/hooks/useGetCurrentAddress.ts index 9f46299be..3a0e672c1 100644 --- a/features/rewards/hooks/useGetCurrentAddress.ts +++ b/features/rewards/hooks/useGetCurrentAddress.ts @@ -6,6 +6,7 @@ import { useSDK } from '@lido-sdk/react'; import { resolveEns, isValidEns, isValidAddress } from 'features/rewards/utils'; import { useCurrentStaticRpcProvider } from 'shared/hooks/use-current-static-rpc-provider'; +import { overrideWithQAMockString } from 'utils/qa'; type UseGetCurrentAddress = () => { address: string; @@ -86,7 +87,11 @@ export const useGetCurrentAddress: UseGetCurrentAddress = () => { return; } // From a connected wallet - if (account) setInputValue(account); + if (account) { + setInputValue( + overrideWithQAMockString(account, 'mock-qa-rewards-address'), + ); + } } }, [account, query.address, isReady, setInputValue]); diff --git a/utils/qa.ts b/utils/qa.ts index e5e56bda3..f7b46c421 100644 --- a/utils/qa.ts +++ b/utils/qa.ts @@ -20,6 +20,16 @@ export const overrideWithQAMockNumber = (value: number, key: string) => { return value; }; +export const overrideWithQAMockString = (value: string, key: string) => { + if (config.enableQaHelpers && typeof window !== 'undefined') { + const mock = localStorage.getItem(key); + if (mock) { + return mock; + } + } + return value; +}; + export const overrideWithQAMockArray = <TArrayElement>( value: TArrayElement[], key: string, From 0f515cb2131ea51af78f9d1989ca9f3831a15e6c Mon Sep 17 00:00:00 2001 From: Anton Shalimov <a.shalimof@yandex.ru> Date: Tue, 6 Aug 2024 12:39:47 +0300 Subject: [PATCH 46/61] refactor(useStethEthRate): return const rate for chain != {mainnet, sepolia, holesky} --- features/rewards/hooks/use-steth-eth-rate.ts | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/features/rewards/hooks/use-steth-eth-rate.ts b/features/rewards/hooks/use-steth-eth-rate.ts index 414e0f3be..6d774aab4 100644 --- a/features/rewards/hooks/use-steth-eth-rate.ts +++ b/features/rewards/hooks/use-steth-eth-rate.ts @@ -1,9 +1,10 @@ +import { constants } from 'ethers'; import { useLidoSWR, useSDK } from '@lido-sdk/react'; +import { CHAINS } from 'consts/chains'; import { STRATEGY_LAZY } from 'consts/swr-strategies'; -import { useMainnetStaticRpcProvider } from 'shared/hooks/use-mainnet-static-rpc-provider'; import { stEthEthRequest } from 'features/rewards/fetchers/requesters'; -import { constants } from 'ethers'; +import { useMainnetStaticRpcProvider } from 'shared/hooks/use-mainnet-static-rpc-provider'; export const useStethEthRate = () => { const { chainId } = useSDK(); @@ -12,12 +13,16 @@ export const useStethEthRate = () => { const swrResult = useLidoSWR( `steth-eth-${chainId}`, async () => { - if (chainId !== 1) { - return constants.WeiPerEther; - } else { + if ( + [CHAINS.Mainnet, CHAINS.Sepolia, CHAINS.Holesky].indexOf( + chainId as CHAINS, + ) > -1 + ) { const stEthEth = await stEthEthRequest(mainnetStaticRpcProvider); return stEthEth; } + + return constants.WeiPerEther; }, STRATEGY_LAZY, ); From d501173497676d7d0688643df413ba638ce0b31a Mon Sep 17 00:00:00 2001 From: Anton Shalimov <a.shalimof@yandex.ru> Date: Tue, 6 Aug 2024 13:06:57 +0300 Subject: [PATCH 47/61] fix: using useStethEthRate --- features/rewards/components/stats/Stats.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/features/rewards/components/stats/Stats.tsx b/features/rewards/components/stats/Stats.tsx index 34c9a6b24..3896eb03a 100644 --- a/features/rewards/components/stats/Stats.tsx +++ b/features/rewards/components/stats/Stats.tsx @@ -17,7 +17,7 @@ export const Stats: React.FC = () => { data, initialLoading: pending, } = useRewardsHistory(); - const { data: stEthEth } = useStethEthRate(); + const stEthEth = useStethEthRate(); const { isDappActive } = useDappStatus(); return ( From 49aee983fdacd7ff64f3deb27df3077984b3d829 Mon Sep 17 00:00:00 2001 From: Anton Shalimov <a.shalimof@yandex.ru> Date: Tue, 6 Aug 2024 15:44:38 +0300 Subject: [PATCH 48/61] fix(rewards): wording --- features/rewards/components/stats/Stats.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/features/rewards/components/stats/Stats.tsx b/features/rewards/components/stats/Stats.tsx index 3896eb03a..3307ce9d6 100644 --- a/features/rewards/components/stats/Stats.tsx +++ b/features/rewards/components/stats/Stats.tsx @@ -23,7 +23,7 @@ export const Stats: React.FC = () => { return ( <> <Item data-testid="stEthRewardedBlock"> - <Title mb="8px">stETH earned + stETH rewarded Date: Wed, 7 Aug 2024 08:55:56 +0300 Subject: [PATCH 49/61] fix(rewards): open wallet by click on AddressBadge --- features/rewards/features/top-card/styles.tsx | 1 + features/rewards/features/top-card/wallet.tsx | 3 +++ 2 files changed, 4 insertions(+) diff --git a/features/rewards/features/top-card/styles.tsx b/features/rewards/features/top-card/styles.tsx index 925c68004..7ba12c78e 100644 --- a/features/rewards/features/top-card/styles.tsx +++ b/features/rewards/features/top-card/styles.tsx @@ -28,6 +28,7 @@ export const WalletContentRowStyle = styled.div` export const WalletContentAddressBadgeStyle = styled(AddressBadge)` background: #00000033; + cursor: pointer; `; export const ConnectWalletStyle = styled(WalletCardStyle)` diff --git a/features/rewards/features/top-card/wallet.tsx b/features/rewards/features/top-card/wallet.tsx index 3f16d3946..d2bf33360 100644 --- a/features/rewards/features/top-card/wallet.tsx +++ b/features/rewards/features/top-card/wallet.tsx @@ -7,6 +7,7 @@ import { useRewardsHistory } from 'features/rewards/hooks'; import { useRewardsBalanceData } from 'features/rewards/hooks/use-rewards-balance-data'; import { FlexCenter } from 'features/stake/stake-form/wallet/styles'; import { CardBalance } from 'shared/wallet'; +import { useWalletModal } from 'shared/wallet/wallet-modal/use-wallet-modal'; import { WalletStyle, @@ -18,6 +19,7 @@ import { export const Wallet: FC = () => { const { data: balanceData } = useRewardsBalanceData(); const { currencyObject: currency, address, loading } = useRewardsHistory(); + const { openModal } = useWalletModal(); return ( @@ -60,6 +62,7 @@ export const Wallet: FC = () => { address={address as `0x${string}`} symbolsMobile={6} symbolsDesktop={6} + onClick={() => openModal({})} /> From b8de7f2e38ebd8d9aeac9c05550198ca54f10a40 Mon Sep 17 00:00:00 2001 From: Anton Shalimov Date: Wed, 7 Aug 2024 09:00:44 +0300 Subject: [PATCH 50/61] fix(layout): remove Y micro scroll --- shared/components/layout/main/styles.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/shared/components/layout/main/styles.tsx b/shared/components/layout/main/styles.tsx index 75189f9fa..fad7cad81 100644 --- a/shared/components/layout/main/styles.tsx +++ b/shared/components/layout/main/styles.tsx @@ -3,6 +3,6 @@ import styled from 'styled-components'; export const MainStyle = styled(Container)` position: relative; - margin-top: ${({ theme }) => theme.spaceMap.sm}px; - margin-bottom: ${({ theme }) => theme.spaceMap.sm}px; + padding-top: ${({ theme }) => theme.spaceMap.sm}px; + padding-bottom: ${({ theme }) => theme.spaceMap.sm}px; `; From 1714f3e8c0e58d0eee7dae60dbfdc224dbc54b26 Mon Sep 17 00:00:00 2001 From: Anton Shalimov Date: Wed, 7 Aug 2024 09:08:43 +0300 Subject: [PATCH 51/61] fix(rewards): text --- .../rewards/components/rewardsListContent/RewardsListsEmpty.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/features/rewards/components/rewardsListContent/RewardsListsEmpty.tsx b/features/rewards/components/rewardsListContent/RewardsListsEmpty.tsx index 992928e4a..d249d5b80 100644 --- a/features/rewards/components/rewardsListContent/RewardsListsEmpty.tsx +++ b/features/rewards/components/rewardsListContent/RewardsListsEmpty.tsx @@ -28,7 +28,7 @@ export const RewardsListsEmpty: FC = () => { - Connect your wallet to view your staking stats. + Connect your wallet to view your staking stats