From 7f477e3598f5ae7a2c6ffa57879ba9f1fd53380b Mon Sep 17 00:00:00 2001 From: Jan Langheimer Date: Wed, 22 Jun 2022 09:10:04 +0100 Subject: [PATCH 01/36] install react-query --- package.json | 1 + src/index.tsx | 23 +++++---- src/queries/useApiPoolsV3.ts | 10 ++++ src/queries/useApiTokensV3.ts | 10 ++++ yarn.lock | 89 +++++++++++++++++++++++++++++++---- 5 files changed, 116 insertions(+), 17 deletions(-) create mode 100644 src/queries/useApiPoolsV3.ts create mode 100644 src/queries/useApiTokensV3.ts diff --git a/package.json b/package.json index 1801466ad..72530153c 100644 --- a/package.json +++ b/package.json @@ -45,6 +45,7 @@ "react-dom": "^17.0.2", "react-intl": "^5.17.6", "react-popper": "^2.2.5", + "react-query": "^3.39.1", "react-router-dom": "6", "react-scripts": "4.0.3", "react-table": "^7.7.0", diff --git a/src/index.tsx b/src/index.tsx index d49453ff3..be5327aad 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -8,17 +8,22 @@ import { I18nProvider } from 'i18n/i18nProvider'; import { getLibrary } from 'services/web3/wallet/utils'; import { Web3ReactProvider } from '@web3-react/core'; import 'styles/index.css'; +import { QueryClient, QueryClientProvider } from 'react-query'; + +const queryClient = new QueryClient(); ReactDOM.render( - - - - - - - - - , + + + + + + + + + + + , document.getElementById('root') ); diff --git a/src/queries/useApiPoolsV3.ts b/src/queries/useApiPoolsV3.ts new file mode 100644 index 000000000..98bed12b5 --- /dev/null +++ b/src/queries/useApiPoolsV3.ts @@ -0,0 +1,10 @@ +import { useQuery } from 'react-query'; +import { BancorApi } from 'services/api/bancorApi/bancorApi'; +import { APIPoolV3 } from 'services/api/bancorApi/bancorApi.types'; + +export const useApiPoolsV3 = () => { + return useQuery( + ['v3', 'api', 'pools'], + BancorApi.v3.getPools + ); +}; diff --git a/src/queries/useApiTokensV3.ts b/src/queries/useApiTokensV3.ts new file mode 100644 index 000000000..a12cea45b --- /dev/null +++ b/src/queries/useApiTokensV3.ts @@ -0,0 +1,10 @@ +import { useQuery } from 'react-query'; +import { BancorApi } from 'services/api/bancorApi/bancorApi'; +import { APITokenV3 } from 'services/api/bancorApi/bancorApi.types'; + +export const useApiTokensV3 = () => { + return useQuery( + ['v3', 'api', 'tokens'], + BancorApi.v3.getTokens + ); +}; diff --git a/yarn.lock b/yarn.lock index 1a29dc2a9..1ccb377c4 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1185,6 +1185,13 @@ dependencies: regenerator-runtime "^0.13.4" +"@babel/runtime@^7.6.2": + version "7.18.3" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.18.3.tgz#c7b654b57f6f63cf7f8b418ac9ca04408c4579f4" + integrity sha512-38Y8f7YUhce/K7RMwTp7m0uCumpv9hZkitCbBClqQIow1qSbCvGkcegKOXpEWCQLfWmevgRiWokZ1GkpfhbZug== + dependencies: + regenerator-runtime "^0.13.4" + "@babel/template@^7.10.4", "@babel/template@^7.12.7", "@babel/template@^7.16.7", "@babel/template@^7.3.3": version "7.16.7" resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.16.7.tgz#8d126c8701fde4d66b264b3eba3d96f07666d155" @@ -5767,6 +5774,11 @@ bfj@^7.0.2: hoopy "^0.1.4" tryer "^1.0.1" +big-integer@^1.6.16: + version "1.6.51" + resolved "https://registry.yarnpkg.com/big-integer/-/big-integer-1.6.51.tgz#0df92a5d9880560d3ff2d5fd20245c889d130686" + integrity sha512-GPEid2Y9QU1Exl1rpO9B2IPJGHPSupF5GnVIP0blYvNOMer2bTvSWs1jGOUg04hTmu67nmLsQ9TBo1puaotBHg== + big.js@^5.2.2: version "5.2.2" resolved "https://registry.yarnpkg.com/big.js/-/big.js-5.2.2.tgz#65f0af382f578bcdc742bd9c281e9cb2d7768328" @@ -5924,6 +5936,20 @@ braces@^3.0.1, braces@~3.0.2: dependencies: fill-range "^7.0.1" +broadcast-channel@^3.4.1: + version "3.7.0" + resolved "https://registry.yarnpkg.com/broadcast-channel/-/broadcast-channel-3.7.0.tgz#2dfa5c7b4289547ac3f6705f9c00af8723889937" + integrity sha512-cIAKJXAxGJceNZGTZSBzMxzyOn72cVgPnKx4dc6LRjQgbaJUQqhy5rzL3zbMxkMWsGKkv2hSFkPRMEXfoMZ2Mg== + dependencies: + "@babel/runtime" "^7.7.2" + detect-node "^2.1.0" + js-sha3 "0.8.0" + microseconds "0.2.0" + nano-time "1.0.0" + oblivious-set "1.0.0" + rimraf "3.0.2" + unload "2.2.0" + brorand@^1.0.1, brorand@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/brorand/-/brorand-1.1.0.tgz#12c25efe40a45e3c323eb8675a0a0ce57b22371f" @@ -7624,7 +7650,7 @@ detect-node@2.0.3: resolved "https://registry.yarnpkg.com/detect-node/-/detect-node-2.0.3.tgz#a2033c09cc8e158d37748fbde7507832bd6ce127" integrity sha1-ogM8CcyOFY03dI+951B4Mr1s4Sc= -detect-node@^2.0.4: +detect-node@^2.0.4, detect-node@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/detect-node/-/detect-node-2.1.0.tgz#c9c70775a49c3d03bc2c06d9a73be550f978f8b1" integrity sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g== @@ -12463,6 +12489,14 @@ markdown-to-jsx@^7.1.3: resolved "https://registry.yarnpkg.com/markdown-to-jsx/-/markdown-to-jsx-7.1.6.tgz#421487df2a66fe4231d94db653a34da033691e62" integrity sha512-1wrIGZYwIG2gR3yfRmbr4FlQmhaAKoKTpRo4wur4fp9p0njU1Hi7vR8fj0AUKKIcPduiJmPprzmCB5B/GvlC7g== +match-sorter@^6.0.2: + version "6.3.1" + resolved "https://registry.yarnpkg.com/match-sorter/-/match-sorter-6.3.1.tgz#98cc37fda756093424ddf3cbc62bfe9c75b92bda" + integrity sha512-mxybbo3pPNuA+ZuCUhm5bwNkXrJTbsk5VWbR5wiwz/GC6LIiegBGn2w3O08UG/jdbYLinw51fSQ5xNU1U3MgBw== + dependencies: + "@babel/runtime" "^7.12.5" + remove-accents "0.4.2" + md5.js@^1.3.4: version "1.3.5" resolved "https://registry.yarnpkg.com/md5.js/-/md5.js-1.3.5.tgz#b5d07b8e3216e3e27cd728d72f70d1e6a342005f" @@ -12644,6 +12678,11 @@ micromatch@^4.0.2, micromatch@^4.0.4: braces "^3.0.1" picomatch "^2.2.3" +microseconds@0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/microseconds/-/microseconds-0.2.0.tgz#233b25f50c62a65d861f978a4a4f8ec18797dc39" + integrity sha512-n7DHHMjR1avBbSpsTBj6fmMGh2AGrifVV4e+WYc3Q9lO+xnSZ3NyhcBND3vzzatt05LFhoKFRxrIyklmLlUtyA== + miller-rabin@^4.0.0: version "4.0.1" resolved "https://registry.yarnpkg.com/miller-rabin/-/miller-rabin-4.0.1.tgz#f080351c865b0dc562a8462966daa53543c78a4d" @@ -12862,6 +12901,13 @@ nan@^2.12.1, nan@^2.14.0, nan@^2.14.2, nan@^2.2.1: resolved "https://registry.yarnpkg.com/nan/-/nan-2.15.0.tgz#3f34a473ff18e15c1b5626b62903b5ad6e665fee" integrity sha512-8ZtvEnA2c5aYCZYd1cvgdnU6cqwixRoYg70xPLWUws5ORTa/lnw+u4amixRS/Ac5U5mQVgp9pnlSUnbNWFaWZQ== +nano-time@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/nano-time/-/nano-time-1.0.0.tgz#b0554f69ad89e22d0907f7a12b0993a5d96137ef" + integrity sha512-flnngywOoQ0lLQOTRNexn2gGSNuM9bKj9RZAWSzhQ+UJYaAFG9bac4DW9VHjUAzrOaIcajHybCTHe/bkvozQqA== + dependencies: + big-integer "^1.6.16" + nanoid@^3.1.30: version "3.2.0" resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.2.0.tgz#62667522da6673971cca916a6d3eff3f415ff80c" @@ -13269,6 +13315,11 @@ objectorarray@^1.0.5: resolved "https://registry.yarnpkg.com/objectorarray/-/objectorarray-1.0.5.tgz#2c05248bbefabd8f43ad13b41085951aac5e68a5" integrity sha512-eJJDYkhJFFbBBAxeh8xW+weHlkI28n2ZdQV/J/DNfWfSKlGEf2xcfAbZTv3riEXHAhL9SVOTs2pRmXiSTf78xg== +oblivious-set@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/oblivious-set/-/oblivious-set-1.0.0.tgz#c8316f2c2fb6ff7b11b6158db3234c49f733c566" + integrity sha512-z+pI07qxo4c2CulUHCDf9lcqDlMSo72N/4rLUpRXf6fu+q8vjt8y0xS+Tlf8NTJDdTXHbdeO1n3MlbctwEoXZw== + oboe@2.1.4: version "2.1.4" resolved "https://registry.yarnpkg.com/oboe/-/oboe-2.1.4.tgz#20c88cdb0c15371bb04119257d4fdd34b0aa49f6" @@ -15168,6 +15219,15 @@ react-popper@^2.2.4, react-popper@^2.2.5: react-fast-compare "^3.0.1" warning "^4.0.2" +react-query@^3.39.1: + version "3.39.1" + resolved "https://registry.yarnpkg.com/react-query/-/react-query-3.39.1.tgz#3876c0fdac7a3b5a84e195534e5fa8fbdd628847" + integrity sha512-qYKT1bavdDiQZbngWZyPotlBVzcBjDYEJg5RQLBa++5Ix5jjfbEYJmHSZRZD+USVHUSvl/ey9Hu+QfF1QAK80A== + dependencies: + "@babel/runtime" "^7.5.5" + broadcast-channel "^3.4.1" + match-sorter "^6.0.2" + react-redux@^7.2.6: version "7.2.6" resolved "https://registry.yarnpkg.com/react-redux/-/react-redux-7.2.6.tgz#49633a24fe552b5f9caf58feb8a138936ddfe9aa" @@ -15584,6 +15644,11 @@ remark-squeeze-paragraphs@4.0.0: dependencies: mdast-squeeze-paragraphs "^4.0.0" +remove-accents@0.4.2: + version "0.4.2" + resolved "https://registry.yarnpkg.com/remove-accents/-/remove-accents-0.4.2.tgz#0a43d3aaae1e80db919e07ae254b285d9e1c7bb5" + integrity sha512-7pXIJqJOq5tFgG1A2Zxti3Ht8jJF337m4sowbuHsW30ZnkQFnDzy9qBNhgzX8ZLW4+UBcXiiR7SwR6pokHsxiA== + remove-trailing-separator@^1.0.1: version "1.1.0" resolved "https://registry.yarnpkg.com/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz#c24bce2a283adad5bc3f58e0d48249b92379d8ef" @@ -15794,6 +15859,13 @@ rgba-regex@^1.0.0: resolved "https://registry.yarnpkg.com/rgba-regex/-/rgba-regex-1.0.0.tgz#43374e2e2ca0968b0ef1523460b7d730ff22eeb3" integrity sha1-QzdOLiyglosO8VI0YLfXMP8i7rM= +rimraf@3.0.2, rimraf@^3.0.0, rimraf@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" + integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA== + dependencies: + glob "^7.1.3" + rimraf@^2.2.8, rimraf@^2.5.4, rimraf@^2.6.3: version "2.7.1" resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.7.1.tgz#35797f13a7fdadc566142c29d4f07ccad483e3ec" @@ -15801,13 +15873,6 @@ rimraf@^2.2.8, rimraf@^2.5.4, rimraf@^2.6.3: dependencies: glob "^7.1.3" -rimraf@^3.0.0, rimraf@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" - integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA== - dependencies: - glob "^7.1.3" - rimraf@~2.6.2: version "2.6.3" resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.3.tgz#b2d104fe0d8fb27cf9e0a1cda8262dd3833c6cab" @@ -17744,6 +17809,14 @@ universalify@^2.0.0: resolved "https://registry.yarnpkg.com/universalify/-/universalify-2.0.0.tgz#75a4984efedc4b08975c5aeb73f530d02df25717" integrity sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ== +unload@2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/unload/-/unload-2.2.0.tgz#ccc88fdcad345faa06a92039ec0f80b488880ef7" + integrity sha512-B60uB5TNBLtN6/LsgAf3udH9saB5p7gqJwcFfbOEZ8BcBHnGwCf6G/TGiEqkRAxX7zAFIUtzdrXQSdL3Q/wqNA== + dependencies: + "@babel/runtime" "^7.6.2" + detect-node "^2.0.4" + unpipe@1.0.0, unpipe@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" From 38076e8763d4eb44a769a8f7e041cedd5ad6635c Mon Sep 17 00:00:00 2001 From: Jan Langheimer Date: Wed, 22 Jun 2022 10:18:01 +0100 Subject: [PATCH 02/36] refactor statistics to use react-query --- src/elements/earn/pools/Statistics.tsx | 69 ++++++------ .../earn/pools/poolsTable/PoolsTable.tsx | 4 +- src/index.tsx | 3 +- src/queries/useApiDataV2.ts | 7 ++ src/queries/useStatistics.ts | 104 ++++++++++++++++++ src/services/observables/statistics.ts | 98 ----------------- src/services/observables/triggers.ts | 6 - src/store/bancor/bancor.ts | 9 +- src/store/bancor/pool.ts | 8 +- 9 files changed, 156 insertions(+), 152 deletions(-) create mode 100644 src/queries/useApiDataV2.ts create mode 100644 src/queries/useStatistics.ts delete mode 100644 src/services/observables/statistics.ts diff --git a/src/elements/earn/pools/Statistics.tsx b/src/elements/earn/pools/Statistics.tsx index 4f097ee16..c39af2c0c 100644 --- a/src/elements/earn/pools/Statistics.tsx +++ b/src/elements/earn/pools/Statistics.tsx @@ -1,46 +1,53 @@ -import { useAppSelector } from 'store'; import './Statistics.css'; +import { useStatistics } from 'queries/useStatistics'; export const Statistics = () => { - const stats = useAppSelector((state) => state.bancor.statistics); - const first = stats[0]; + const { data: stats, isError, isLoading, isIdle } = useStatistics(); - return ( -
- {!stats.length ? ( - [...Array(4)].map((_, i) => ( + if (isLoading || isIdle) { + return ( + <> + {[...Array(4)].map((_, i) => (
- )) - ) : ( + ))} + + ); + } + + if (!stats || isError) { + return
Error loading stats
; + } + console.log('muh', stats); + const first = stats[0]; + + return ( + <> +
-
-
-
{first.label}
-
- {first.value} -
-
+
{first.label}
+
+ {first.value}
-
-
- {stats.slice(1).map((item, i) => ( -
-
-
-
{item.label}
-
- {item.value} -
-
+
+
+
+
+ {stats.slice(1).map((item, i) => ( +
+
+
+
{item.label}
+
+ {item.value}
- ))} +
-
- )} -
+ ))} + + ); }; diff --git a/src/elements/earn/pools/poolsTable/PoolsTable.tsx b/src/elements/earn/pools/poolsTable/PoolsTable.tsx index 1b0c29e04..d6f309969 100644 --- a/src/elements/earn/pools/poolsTable/PoolsTable.tsx +++ b/src/elements/earn/pools/poolsTable/PoolsTable.tsx @@ -210,7 +210,9 @@ export const PoolsTable = ({
- +
+ +
diff --git a/src/index.tsx b/src/index.tsx index be5327aad..96d41daa1 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -9,9 +9,9 @@ import { getLibrary } from 'services/web3/wallet/utils'; import { Web3ReactProvider } from '@web3-react/core'; import 'styles/index.css'; import { QueryClient, QueryClientProvider } from 'react-query'; +import { ReactQueryDevtools } from 'react-query/devtools'; const queryClient = new QueryClient(); - ReactDOM.render( @@ -23,6 +23,7 @@ ReactDOM.render( + , document.getElementById('root') ); diff --git a/src/queries/useApiDataV2.ts b/src/queries/useApiDataV2.ts new file mode 100644 index 000000000..5b54b20a1 --- /dev/null +++ b/src/queries/useApiDataV2.ts @@ -0,0 +1,7 @@ +import { useQuery } from 'react-query'; +import { BancorApi } from 'services/api/bancorApi/bancorApi'; +import { WelcomeData } from 'services/api/bancorApi/bancorApi.types'; + +export const useApiDataV2 = () => { + return useQuery(['v2', 'api'], BancorApi.v2.getWelcome); +}; diff --git a/src/queries/useStatistics.ts b/src/queries/useStatistics.ts new file mode 100644 index 000000000..8491fb3e8 --- /dev/null +++ b/src/queries/useStatistics.ts @@ -0,0 +1,104 @@ +import { useQuery } from 'react-query'; +import { BancorApi } from 'services/api/bancorApi/bancorApi'; +import BigNumber from 'bignumber.js'; +import { bntToken } from 'services/web3/config'; +import { toBigNumber } from 'utils/helperFunctions'; +import numbro from 'numbro'; +import { useApiDataV2 } from 'queries/useApiDataV2'; +import { WelcomeData } from 'services/api/bancorApi/bancorApi.types'; + +export interface Statistic { + label: string; + value: string; + change24h?: number; +} + +const averageFormat = { + average: true, + mantissa: 2, + optionalMantissa: true, + spaceSeparated: true, + lowPrecision: false, +}; + +const fetchStatistics = async ( + apiDataV2: WelcomeData +): Promise => { + const stats = await BancorApi.v3.getStatistics(); + + const bnt24hChange = new BigNumber(stats.bntRate) + .div(stats.bntRate24hAgo) + .times(100) + .minus(100) + .toNumber(); + + const bntSupply = apiDataV2.bnt_supply; + + const totalBntStakedV2: number = apiDataV2.pools.reduce((acc, item) => { + const bntReserve = item.reserves.find( + (reserve) => reserve.address === bntToken + ); + if (!bntReserve) return acc; + return Number(bntReserve.balance) + acc; + }, 0); + + const stakedBntPercentV2 = new BigNumber(totalBntStakedV2) + .div(toBigNumber(bntSupply).toExponential(18)) + .times(100); + + const stakedBntPercentV3 = new BigNumber(stats.stakedBalanceBNT.bnt) + .div(toBigNumber(bntSupply).toExponential(18)) + .times(100); + + const totalBNTStaked = new BigNumber(stakedBntPercentV2).plus( + stakedBntPercentV3 + ); + + const totalLiquidity = new BigNumber(stats.tradingLiquidityBNT.usd) + .plus(stats.tradingLiquidityTKN.usd) + .plus(apiDataV2.total_liquidity.usd); + + const totalVolume = new BigNumber(apiDataV2.total_volume_24h.usd).plus( + stats.totalVolume24h.usd + ); + const totalFees = new BigNumber(apiDataV2.total_fees_24h.usd).plus( + stats.totalFees24h.usd + ); + + return [ + { + label: 'Total Liquidity', + value: '$' + numbro(totalLiquidity).format(averageFormat), + change24h: 0, + }, + { + label: 'Volume', + value: '$' + numbro(totalVolume).format(averageFormat), + change24h: 0, + }, + { + label: 'Fees (24h)', + value: '$' + numbro(totalFees).format(averageFormat), + change24h: 0, + }, + { + label: 'BNT Price', + value: '$' + numbro(stats.bntRate).format({ mantissa: 2 }), + change24h: bnt24hChange, + }, + { + label: 'BNT Staked', + value: numbro(totalBNTStaked).format({ mantissa: 2 }) + '%', + }, + ]; +}; + +export const useStatistics = () => { + const { data: apiDataV2 } = useApiDataV2(); + + return useQuery( + ['v3', 'statistics'], + () => fetchStatistics(apiDataV2!), + { enabled: !!apiDataV2 } + ); +}; diff --git a/src/services/observables/statistics.ts b/src/services/observables/statistics.ts deleted file mode 100644 index 21aa38948..000000000 --- a/src/services/observables/statistics.ts +++ /dev/null @@ -1,98 +0,0 @@ -import { combineLatest } from 'rxjs'; -import { shareReplay } from 'rxjs/operators'; -import BigNumber from 'bignumber.js'; -import numbro from 'numbro'; -import { apiData$ } from 'services/observables/apiData'; -import { bntToken } from 'services/web3/config'; -import { oneMinute$ } from 'services/observables/timers'; -import { BancorApi } from 'services/api/bancorApi/bancorApi'; -import { switchMapIgnoreThrow } from 'services/observables/customOperators'; -import { toBigNumber } from 'utils/helperFunctions'; - -export interface Statistic { - label: string; - value: string; - change24h?: number; -} - -const averageFormat = { - average: true, - mantissa: 2, - optionalMantissa: true, - spaceSeparated: true, - lowPrecision: false, -}; - -export const statisticsV3$ = combineLatest([apiData$, oneMinute$]).pipe( - switchMapIgnoreThrow(async ([apiDataV2]) => { - const stats = await BancorApi.v3.getStatistics(); - - const bnt24hChange = new BigNumber(stats.bntRate) - .div(stats.bntRate24hAgo) - .times(100) - .minus(100) - .toNumber(); - - const bntSupply = apiDataV2.bnt_supply; - - const totalBntStakedV2: number = apiDataV2.pools.reduce((acc, item) => { - const bntReserve = item.reserves.find( - (reserve) => reserve.address === bntToken - ); - if (!bntReserve) return acc; - return Number(bntReserve.balance) + acc; - }, 0); - - const stakedBntPercentV2 = new BigNumber(totalBntStakedV2) - .div(toBigNumber(bntSupply).toExponential(18)) - .times(100); - - const stakedBntPercentV3 = new BigNumber(stats.stakedBalanceBNT.bnt) - .div(toBigNumber(bntSupply).toExponential(18)) - .times(100); - - const totalBNTStaked = new BigNumber(stakedBntPercentV2).plus( - stakedBntPercentV3 - ); - - const totalLiquidity = new BigNumber(stats.tradingLiquidityBNT.usd) - .plus(stats.tradingLiquidityTKN.usd) - .plus(apiDataV2.total_liquidity.usd); - - const totalVolume = new BigNumber(apiDataV2.total_volume_24h.usd).plus( - stats.totalVolume24h.usd - ); - const totalFees = new BigNumber(apiDataV2.total_fees_24h.usd).plus( - stats.totalFees24h.usd - ); - - const statistics: Statistic[] = [ - { - label: 'Total Liquidity', - value: '$' + numbro(totalLiquidity).format(averageFormat), - change24h: 0, - }, - { - label: 'Volume', - value: '$' + numbro(totalVolume).format(averageFormat), - change24h: 0, - }, - { - label: 'Fees (24h)', - value: '$' + numbro(totalFees).format(averageFormat), - change24h: 0, - }, - { - label: 'BNT Price', - value: '$' + numbro(stats.bntRate).format({ mantissa: 2 }), - change24h: bnt24hChange, - }, - { - label: 'BNT Staked', - value: numbro(totalBNTStaked).format({ mantissa: 2 }) + '%', - }, - ]; - return statistics; - }), - shareReplay(1) -); diff --git a/src/services/observables/triggers.ts b/src/services/observables/triggers.ts index 939987362..702395d91 100644 --- a/src/services/observables/triggers.ts +++ b/src/services/observables/triggers.ts @@ -8,14 +8,12 @@ import { setAllTokenListTokens, setAllTokensV2, setKeeperDaoTokens, - setStatisticsV3, setTokenLists, setTokensV2, setTokensV3, } from 'store/bancor/bancor'; import { getTokenListLS, setTokenListLS } from 'utils/localStorage'; import { loadingLockedBnt$, loadingPositions$, loadingRewards$ } from './user'; -import { statisticsV3$ } from 'services/observables/statistics'; import { setv2Pools, setv3Pools } from 'store/bancor/pool'; import { setLoadingLockedBnt, @@ -97,10 +95,6 @@ export const subscribeToObservables = (dispatch: any) => { dispatch(setv2Pools(pools)); }); - statisticsV3$.subscribe((stats) => { - dispatch(setStatisticsV3(stats)); - }); - protectedPositions$.subscribe((protectedPositions) => { dispatch(setProtectedPositions(protectedPositions)); }); diff --git a/src/store/bancor/bancor.ts b/src/store/bancor/bancor.ts index 828367deb..0bc9b3bde 100644 --- a/src/store/bancor/bancor.ts +++ b/src/store/bancor/bancor.ts @@ -1,4 +1,4 @@ -import { createSelector, createSlice, PayloadAction } from '@reduxjs/toolkit'; +import { createSelector, createSlice } from '@reduxjs/toolkit'; import { KeeprDaoToken } from 'services/api/keeperDao'; import { Token, TokenList, TokenMinimal } from 'services/observables/tokens'; import { RootState } from 'store'; @@ -6,7 +6,6 @@ import { orderBy, uniqBy } from 'lodash'; import { getAllTokensMap } from 'store/bancor/token'; import { utils } from 'ethers'; -import { Statistic } from 'services/observables/statistics'; import { NotificationType } from 'store/notification/notification'; interface BancorState { @@ -17,7 +16,6 @@ interface BancorState { allTokenListTokens: TokenMinimal[]; allTokens: Token[]; isLoadingTokens: boolean; - statistics: Statistic[]; } export const initialState: BancorState = { @@ -28,7 +26,6 @@ export const initialState: BancorState = { keeperDaoTokens: [], allTokenListTokens: [], isLoadingTokens: true, - statistics: [], }; const bancorSlice = createSlice({ @@ -54,9 +51,6 @@ const bancorSlice = createSlice({ setKeeperDaoTokens: (state, action) => { state.keeperDaoTokens = action.payload; }, - setStatisticsV3: (state, action: PayloadAction) => { - state.statistics = action.payload; - }, }, }); @@ -65,7 +59,6 @@ export const { setTokensV3, setTokenLists, setAllTokensV2, - setStatisticsV3, setAllTokenListTokens, setKeeperDaoTokens, } = bancorSlice.actions; diff --git a/src/store/bancor/pool.ts b/src/store/bancor/pool.ts index 2238fbdd6..2cb874502 100644 --- a/src/store/bancor/pool.ts +++ b/src/store/bancor/pool.ts @@ -1,6 +1,5 @@ import { createSelector, createSlice } from '@reduxjs/toolkit'; import { Token } from 'services/observables/tokens'; -import { Statistic } from 'services/observables/statistics'; import { RootState } from 'store'; import { isEqual, orderBy } from 'lodash'; import { createSelectorCreator, defaultMemoize } from 'reselect'; @@ -11,14 +10,12 @@ interface PoolState { v2Pools: Pool[]; v3Pools: PoolV3[]; isLoadingV3Pools: boolean; - statistics: Statistic[]; } const initialState: PoolState = { v2Pools: [], v3Pools: [], isLoadingV3Pools: true, - statistics: [], }; const poolSlice = createSlice({ @@ -32,9 +29,6 @@ const poolSlice = createSlice({ state.v3Pools = action.payload; state.isLoadingV3Pools = false; }, - setStats: (state, action) => { - state.statistics = action.payload; - }, }, }); @@ -171,6 +165,6 @@ export const getPoolByIdWithoutV3 = (id: string) => return { status: 'ready', pool } as SelectedPool; }); -export const { setv2Pools, setv3Pools, setStats } = poolSlice.actions; +export const { setv2Pools, setv3Pools } = poolSlice.actions; export const pool = poolSlice.reducer; From f7118742304d813e86714941388e4deedd9ac049 Mon Sep 17 00:00:00 2001 From: Jan Langheimer Date: Thu, 23 Jun 2022 11:18:51 +0100 Subject: [PATCH 03/36] react-query tmp commit --- .../ErrorBoundary/ErrorBoundary.tsx | 35 +++++++++++++++++++ src/elements/earn/pools/Statistics.tsx | 8 ++--- .../earn/pools/poolsTable/PoolsTable.tsx | 5 ++- src/index.tsx | 16 +++++++-- src/queries/useApiDataV2.ts | 2 +- src/queries/useBalances.ts | 10 ++++++ 6 files changed, 66 insertions(+), 10 deletions(-) create mode 100644 src/components/ErrorBoundary/ErrorBoundary.tsx create mode 100644 src/queries/useBalances.ts diff --git a/src/components/ErrorBoundary/ErrorBoundary.tsx b/src/components/ErrorBoundary/ErrorBoundary.tsx new file mode 100644 index 000000000..a4647cdef --- /dev/null +++ b/src/components/ErrorBoundary/ErrorBoundary.tsx @@ -0,0 +1,35 @@ +import React, { Component, ErrorInfo, ReactNode } from 'react'; + +interface Props { + errorMsg?: string; + children?: ReactNode; +} + +interface State { + hasError: boolean; +} + +class ErrorBoundary extends Component { + public state: State = { + hasError: false, + }; + + public static getDerivedStateFromError(_: Error): State { + // Update state so the next render will show the fallback UI. + return { hasError: true }; + } + + public componentDidCatch(error: Error, errorInfo: ErrorInfo) { + console.error('Uncaught error:', error, errorInfo); + } + + public render() { + if (this.state.hasError) { + return

{this.props.errorMsg || 'Sorry.. there was an error'}

; + } + + return this.props.children; + } +} + +export default ErrorBoundary; diff --git a/src/elements/earn/pools/Statistics.tsx b/src/elements/earn/pools/Statistics.tsx index c39af2c0c..d47f2ec6a 100644 --- a/src/elements/earn/pools/Statistics.tsx +++ b/src/elements/earn/pools/Statistics.tsx @@ -2,9 +2,9 @@ import './Statistics.css'; import { useStatistics } from 'queries/useStatistics'; export const Statistics = () => { - const { data: stats, isError, isLoading, isIdle } = useStatistics(); + const { data: stats } = useStatistics(); - if (isLoading || isIdle) { + if (!stats) { return ( <> {[...Array(4)].map((_, i) => ( @@ -17,10 +17,6 @@ export const Statistics = () => { ); } - if (!stats || isError) { - return
Error loading stats
; - } - console.log('muh', stats); const first = stats[0]; return ( diff --git a/src/elements/earn/pools/poolsTable/PoolsTable.tsx b/src/elements/earn/pools/poolsTable/PoolsTable.tsx index d6f309969..16f808c22 100644 --- a/src/elements/earn/pools/poolsTable/PoolsTable.tsx +++ b/src/elements/earn/pools/poolsTable/PoolsTable.tsx @@ -17,6 +17,7 @@ import { sortNumbersByKey } from 'utils/pureFunctions'; import { Navigate } from 'components/navigate/Navigate'; import { PopoverV3 } from 'components/popover/PopoverV3'; import { Image } from 'components/image/Image'; +import ErrorBoundary from 'components/ErrorBoundary/ErrorBoundary'; export const PoolsTable = ({ rewards, @@ -211,7 +212,9 @@ export const PoolsTable = ({
- + + +
diff --git a/src/index.tsx b/src/index.tsx index 96d41daa1..28ebc95b6 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -10,15 +10,27 @@ import { Web3ReactProvider } from '@web3-react/core'; import 'styles/index.css'; import { QueryClient, QueryClientProvider } from 'react-query'; import { ReactQueryDevtools } from 'react-query/devtools'; +import ErrorBoundary from 'components/ErrorBoundary/ErrorBoundary'; + +const queryClient = new QueryClient({ + defaultOptions: { + queries: { + refetchInterval: 60000, + staleTime: 30000, + useErrorBoundary: true, + }, + }, +}); -const queryClient = new QueryClient(); ReactDOM.render( - + + + diff --git a/src/queries/useApiDataV2.ts b/src/queries/useApiDataV2.ts index 5b54b20a1..2605f3560 100644 --- a/src/queries/useApiDataV2.ts +++ b/src/queries/useApiDataV2.ts @@ -3,5 +3,5 @@ import { BancorApi } from 'services/api/bancorApi/bancorApi'; import { WelcomeData } from 'services/api/bancorApi/bancorApi.types'; export const useApiDataV2 = () => { - return useQuery(['v2', 'api'], BancorApi.v2.getWelcome); + return useQuery(['v2', 'api'], BancorApi.v2.getWelcome); }; diff --git a/src/queries/useBalances.ts b/src/queries/useBalances.ts new file mode 100644 index 000000000..fc2ed46e6 --- /dev/null +++ b/src/queries/useBalances.ts @@ -0,0 +1,10 @@ +import { useQuery } from 'react-query'; +import { fetchTokenBalanceMulticall } from 'services/web3/token/token'; + +export const useBalances = (tokenIds: string[], user?: string) => { + return useQuery>( + ['v3', 'token', 'balances'], + () => fetchTokenBalanceMulticall(tokenIds, user!), + { enabled: !!user } + ); +}; From 5620a4d7141355ef2b5a8f723faa204e12e8ff0a Mon Sep 17 00:00:00 2001 From: Jan Langheimer Date: Mon, 4 Jul 2022 11:28:20 +0200 Subject: [PATCH 04/36] react-query tmp commit --- src/queries/useBalances.ts | 12 ++++++++---- src/queries/useTokens.ts | 16 ++++++++++++++++ 2 files changed, 24 insertions(+), 4 deletions(-) create mode 100644 src/queries/useTokens.ts diff --git a/src/queries/useBalances.ts b/src/queries/useBalances.ts index fc2ed46e6..552f47d74 100644 --- a/src/queries/useBalances.ts +++ b/src/queries/useBalances.ts @@ -1,10 +1,14 @@ import { useQuery } from 'react-query'; import { fetchTokenBalanceMulticall } from 'services/web3/token/token'; +import { useApiPoolsV3 } from 'queries/useApiPoolsV3'; + +export const useTokenBalances = (user?: string) => { + const { data: pools } = useApiPoolsV3(); + const ids = pools ? pools.map((p) => p.poolDltId) : []; -export const useBalances = (tokenIds: string[], user?: string) => { return useQuery>( - ['v3', 'token', 'balances'], - () => fetchTokenBalanceMulticall(tokenIds, user!), - { enabled: !!user } + ['v3', 'token', 'balances', user], + () => fetchTokenBalanceMulticall(ids, user!), + { enabled: !!user && !!pools } ); }; diff --git a/src/queries/useTokens.ts b/src/queries/useTokens.ts new file mode 100644 index 000000000..a964325eb --- /dev/null +++ b/src/queries/useTokens.ts @@ -0,0 +1,16 @@ +import { useQuery } from 'react-query'; +import { fetchTokenBalanceMulticall } from 'services/web3/token/token'; +import { useApiPoolsV3 } from 'queries/useApiPoolsV3'; +import { useWeb3React } from '@web3-react/core'; + +export const useTokens = () => { + const { account } = useWeb3React(); + const { data: pools } = useApiPoolsV3(); + const ids = pools ? pools.map((p) => p.poolDltId) : []; + + return useQuery>( + ['v3', 'tokens'], + () => fetchTokenBalanceMulticall(ids, account!), + { enabled: !!account && !!pools } + ); +}; From 5ab79b33e18ca1166fe3134cf0135dec637d60ed Mon Sep 17 00:00:00 2001 From: Jan Langheimer Date: Mon, 4 Jul 2022 12:59:19 +0200 Subject: [PATCH 05/36] fix merge conflicts --- .../earn/pools/poolsTable/PoolsTable.tsx | 5 +--- src/index.tsx | 5 +--- yarn.lock | 29 +++++++------------ 3 files changed, 13 insertions(+), 26 deletions(-) diff --git a/src/elements/earn/pools/poolsTable/PoolsTable.tsx b/src/elements/earn/pools/poolsTable/PoolsTable.tsx index 16f808c22..d6f309969 100644 --- a/src/elements/earn/pools/poolsTable/PoolsTable.tsx +++ b/src/elements/earn/pools/poolsTable/PoolsTable.tsx @@ -17,7 +17,6 @@ import { sortNumbersByKey } from 'utils/pureFunctions'; import { Navigate } from 'components/navigate/Navigate'; import { PopoverV3 } from 'components/popover/PopoverV3'; import { Image } from 'components/image/Image'; -import ErrorBoundary from 'components/ErrorBoundary/ErrorBoundary'; export const PoolsTable = ({ rewards, @@ -212,9 +211,7 @@ export const PoolsTable = ({
- - - +
diff --git a/src/index.tsx b/src/index.tsx index 28ebc95b6..2563ccef8 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -10,7 +10,6 @@ import { Web3ReactProvider } from '@web3-react/core'; import 'styles/index.css'; import { QueryClient, QueryClientProvider } from 'react-query'; import { ReactQueryDevtools } from 'react-query/devtools'; -import ErrorBoundary from 'components/ErrorBoundary/ErrorBoundary'; const queryClient = new QueryClient({ defaultOptions: { @@ -28,9 +27,7 @@ ReactDOM.render( - - - + diff --git a/yarn.lock b/yarn.lock index 93ab2b430..6e46125bd 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1131,7 +1131,7 @@ dependencies: regenerator-runtime "^0.12.0" -"@babel/runtime@^7.0.0", "@babel/runtime@^7.10.2", "@babel/runtime@^7.11.2", "@babel/runtime@^7.12.5", "@babel/runtime@^7.15.4", "@babel/runtime@^7.16.3", "@babel/runtime@^7.17.8", "@babel/runtime@^7.18.3", "@babel/runtime@^7.3.1", "@babel/runtime@^7.5.0", "@babel/runtime@^7.5.5", "@babel/runtime@^7.7.6", "@babel/runtime@^7.8.4", "@babel/runtime@^7.9.2": +"@babel/runtime@^7.0.0", "@babel/runtime@^7.10.2", "@babel/runtime@^7.11.2", "@babel/runtime@^7.12.5", "@babel/runtime@^7.15.4", "@babel/runtime@^7.16.3", "@babel/runtime@^7.17.8", "@babel/runtime@^7.18.3", "@babel/runtime@^7.3.1", "@babel/runtime@^7.5.0", "@babel/runtime@^7.5.5", "@babel/runtime@^7.6.2", "@babel/runtime@^7.7.2", "@babel/runtime@^7.7.6", "@babel/runtime@^7.8.4", "@babel/runtime@^7.9.2": version "7.18.6" resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.18.6.tgz#6a1ef59f838debd670421f8c7f2cbb8da9751580" integrity sha512-t9wi7/AW6XtKahAe20Yw0/mMljKq0B1r2fPdvaAdV/KPDZewFXdaaa6K7lxmZBZ8FBNpCiAT6iHPmd6QO9bKfQ== @@ -5553,7 +5553,7 @@ bfj@^7.0.2: hoopy "^0.1.4" tryer "^1.0.1" -big-integer@^1.6.16: +big-integer@^1.6.16, big-integer@^1.6.7: version "1.6.51" resolved "https://registry.yarnpkg.com/big-integer/-/big-integer-1.6.51.tgz#0df92a5d9880560d3ff2d5fd20245c889d130686" integrity sha512-GPEid2Y9QU1Exl1rpO9B2IPJGHPSupF5GnVIP0blYvNOMer2bTvSWs1jGOUg04hTmu67nmLsQ9TBo1puaotBHg== @@ -7238,11 +7238,6 @@ detect-newline@^3.0.0: resolved "https://registry.yarnpkg.com/detect-newline/-/detect-newline-3.1.0.tgz#576f5dfc63ae1a192ff192d8ad3af6308991b651" integrity sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA== -detect-node@2.0.3: - version "2.0.3" - resolved "https://registry.yarnpkg.com/detect-node/-/detect-node-2.0.3.tgz#a2033c09cc8e158d37748fbde7507832bd6ce127" - integrity sha1-ogM8CcyOFY03dI+951B4Mr1s4Sc= - detect-node@^2.0.4, detect-node@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/detect-node/-/detect-node-2.1.0.tgz#c9c70775a49c3d03bc2c06d9a73be550f978f8b1" @@ -11668,6 +11663,14 @@ markdown-escapes@^1.0.0: resolved "https://registry.yarnpkg.com/markdown-escapes/-/markdown-escapes-1.0.4.tgz#c95415ef451499d7602b91095f3c8e8975f78535" integrity sha512-8z4efJYk43E0upd0NbVXwgSTQs6cT3T06etieCMEg7dRbzCbxUCK/GHlX8mhHRDcp+OLlHkPKsvqQTCvsRl2cg== +match-sorter@^6.0.2: + version "6.3.1" + resolved "https://registry.yarnpkg.com/match-sorter/-/match-sorter-6.3.1.tgz#98cc37fda756093424ddf3cbc62bfe9c75b92bda" + integrity sha512-mxybbo3pPNuA+ZuCUhm5bwNkXrJTbsk5VWbR5wiwz/GC6LIiegBGn2w3O08UG/jdbYLinw51fSQ5xNU1U3MgBw== + dependencies: + "@babel/runtime" "^7.12.5" + remove-accents "0.4.2" + md5.js@^1.3.4: version "1.3.5" resolved "https://registry.yarnpkg.com/md5.js/-/md5.js-1.3.5.tgz#b5d07b8e3216e3e27cd728d72f70d1e6a342005f" @@ -14732,16 +14735,6 @@ rfdc@^1.3.0: resolved "https://registry.yarnpkg.com/rfdc/-/rfdc-1.3.0.tgz#d0b7c441ab2720d05dc4cf26e01c89631d9da08b" integrity sha512-V2hovdzFbOi77/WajaSMXk2OLm+xNIeQdMMuB7icj7bk6zi2F8GGAxigcnDFpJHbNyNcgyJDiP+8nOrY5cZGrA== -rgb-regex@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/rgb-regex/-/rgb-regex-1.0.1.tgz#c0e0d6882df0e23be254a475e8edd41915feaeb1" - integrity sha1-wODWiC3w4jviVKR16O3UGRX+rrE= - -rgba-regex@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/rgba-regex/-/rgba-regex-1.0.0.tgz#43374e2e2ca0968b0ef1523460b7d730ff22eeb3" - integrity sha1-QzdOLiyglosO8VI0YLfXMP8i7rM= - rimraf@3.0.2, rimraf@^3.0.0, rimraf@^3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" @@ -14749,7 +14742,7 @@ rimraf@3.0.2, rimraf@^3.0.0, rimraf@^3.0.2: dependencies: glob "^7.1.3" -rimraf@^2.2.8, rimraf@^2.5.4, rimraf@^2.6.3: +rimraf@^2.5.4, rimraf@^2.6.3: version "2.7.1" resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.7.1.tgz#35797f13a7fdadc566142c29d4f07ccad483e3ec" integrity sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w== From 2ae3e549bf61d8c27ff1559b2cae19196968575c Mon Sep 17 00:00:00 2001 From: Jan Langheimer Date: Tue, 5 Jul 2022 11:47:29 +0200 Subject: [PATCH 06/36] core functionality proof of concept --- package.json | 7 +- src/App.tsx | 37 +- .../earn/pools/poolsTable/PoolsTable.tsx | 110 +++--- src/elements/layoutHeader/LayoutHeader.tsx | 4 +- src/index.tsx | 13 + src/queries/useApiDataV2.ts | 5 +- src/queries/useApiPoolsV3.ts | 9 +- src/queries/useApiTokensV3.ts | 18 +- src/queries/useBalances.ts | 30 +- src/queries/usePoolsV3.ts | 109 ++++++ src/queries/useStatistics.ts | 2 +- src/queries/useV3ChainData.ts | 351 ++++++++++++++++++ src/services/api/bancorApi/bancorApi.types.ts | 8 + src/services/api/bancorApi/bancorApiV3.ts | 34 +- src/services/notifications/notifications.ts | 5 +- src/services/web3/multicall/multicall.ts | 19 +- src/services/web3/token/token.ts | 3 + src/services/web3/v3/contractsApi.ts | 8 + yarn.lock | 31 +- 19 files changed, 685 insertions(+), 118 deletions(-) create mode 100644 src/queries/usePoolsV3.ts create mode 100644 src/queries/useV3ChainData.ts diff --git a/package.json b/package.json index 8faba2598..01a7ef9b3 100644 --- a/package.json +++ b/package.json @@ -40,9 +40,10 @@ "react-chartjs-2": "^4.0.1", "react-device-detect": "^2.1.2", "react-dom": "^17.0.2", + "react-error-boundary": "^3.1.4", "react-intl": "^5.17.6", "react-popper": "^2.2.5", - "react-query": "^3.39.1", + "react-query": "^4.0.0-beta.23", "react-router-dom": "6", "react-scripts": "5.0.1", "react-table": "^7.7.0", @@ -57,10 +58,10 @@ "@storybook/addon-actions": "6.5.9", "@storybook/addon-essentials": "6.5.9", "@storybook/addon-links": "6.5.9", - "@storybook/node-logger": "6.5.9", - "@storybook/preset-create-react-app": "4.1.2", "@storybook/builder-webpack5": "6.5.9", "@storybook/manager-webpack5": "6.5.9", + "@storybook/node-logger": "6.5.9", + "@storybook/preset-create-react-app": "4.1.2", "@storybook/react": "6.5.9", "@typechain/ethers-v5": "^8.0.2", "@types/json-bigint": "^1.0.0", diff --git a/src/App.tsx b/src/App.tsx index 80ca9b1b2..aa059a63c 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -30,6 +30,16 @@ import { useWeb3React } from '@web3-react/core'; import { useAutoConnect } from 'services/web3/wallet/hooks'; import { setUser } from 'services/observables/user'; import { BancorRouter } from 'router/BancorRouter'; +import { ErrorBoundary, FallbackProps } from 'react-error-boundary'; + +function ErrorFallback({ error }: FallbackProps) { + return ( +
+

Something went wrong:

+
{error.message}
+
+ ); +} const handleModeChange = (_: MediaQueryListEvent) => { const darkMode = store.getState().user.darkMode; @@ -91,17 +101,20 @@ export const App = () => { }, [account, dispatch]); return ( - - - {unsupportedNetwork ? ( - - ) : ( -
- -
- )} - - -
+ // @ts-ignore + + + + {unsupportedNetwork ? ( + + ) : ( +
+ +
+ )} + + +
+
); }; diff --git a/src/elements/earn/pools/poolsTable/PoolsTable.tsx b/src/elements/earn/pools/poolsTable/PoolsTable.tsx index d6f309969..365ff40e1 100644 --- a/src/elements/earn/pools/poolsTable/PoolsTable.tsx +++ b/src/elements/earn/pools/poolsTable/PoolsTable.tsx @@ -2,11 +2,9 @@ import { Token } from 'services/observables/tokens'; import { useCallback, useMemo, useState } from 'react'; import { SortingRule } from 'react-table'; import { DataTable, TableColumn } from 'components/table/DataTable'; -import { useAppSelector } from 'store'; import { SearchInput } from 'components/searchInput/SearchInput'; import { ReactComponent as IconGift } from 'assets/icons/gift.svg'; import { PoolsTableSort } from './PoolsTableFilter'; -import { PoolV3 } from 'services/observables/pools'; // import { DepositV3Modal } from 'elements/earn/pools/poolsTable/v3/DepositV3Modal'; import { DepositDisabledModal } from 'elements/earn/pools/poolsTable/v3/DepositDisabledModal'; import { prettifyNumber, toBigNumber } from 'utils/helperFunctions'; @@ -17,6 +15,8 @@ import { sortNumbersByKey } from 'utils/pureFunctions'; import { Navigate } from 'components/navigate/Navigate'; import { PopoverV3 } from 'components/popover/PopoverV3'; import { Image } from 'components/image/Image'; +import { usePoolsV3 } from 'queries/usePoolsV3'; +import { PoolV3Chain } from 'queries/useV3ChainData'; export const PoolsTable = ({ rewards, @@ -37,66 +37,73 @@ export const PoolsTable = ({ lowEarnRate: boolean; setLowEarnRate: Function; }) => { - const pools = useAppSelector((state) => state.pool.v3Pools); + const { data: pools, isLoading } = usePoolsV3(); const [search, setSearch] = useState(''); - const data = useMemo(() => { - return pools.filter( - (p) => - p.name && - p.name.toLowerCase().includes(search.toLowerCase()) && - (lowVolume || Number(p.volume24h.usd) > 5000) && - (lowLiquidity || Number(p.tradingLiquidityTKN.usd) > 50000) && - (lowEarnRate || p.apr7d.total > 0.15) - ); + const data = useMemo(() => { + return pools + ? pools.filter( + (p) => + p.symbol.toLowerCase().includes(search.toLowerCase()) && + (lowVolume || Number(p.volume24h?.usd) > 5000) && + (lowLiquidity || Number(p.tradingLiquidityTKN.usd) > 50000) && + (lowEarnRate || (p.apr7d?.total ?? 0) > 0.15) + ) + : []; }, [pools, search, lowVolume, lowLiquidity, lowEarnRate]); const toolTip = useCallback( - (row: PoolV3) => ( + (row: PoolV3Chain) => (
-
- Liquidity -
- {toBigNumber(row.stakedBalance.usd).isZero() - ? 'New' - : prettifyNumber(row.stakedBalance.usd, true)} + {row.stakedBalance.usd && ( +
+ Liquidity +
+ {toBigNumber(row.stakedBalance.usd).isZero() + ? 'New' + : prettifyNumber(row.stakedBalance.usd, true)} +
-
-
- Volume 7d -
- {toBigNumber(row.volume7d.usd).isZero() - ? 'New' - : prettifyNumber(row.volume7d.usd, true)} + )} + {row.volume7d?.usd && ( +
+ Volume 7d +
+ {toBigNumber(row.volume7d.usd).isZero() + ? 'New' + : prettifyNumber(row.volume7d.usd, true)} +
-
-
- Fees 7d -
- {toBigNumber(row.fees7d.usd).isZero() - ? 'New' - : prettifyNumber(row.fees7d.usd, true)} + )} + {row.fees7d?.usd && ( +
+ Fees 7d +
+ {toBigNumber(row.fees7d.usd).isZero() + ? 'New' + : prettifyNumber(row.fees7d.usd, true)} +
-
+ )}
), [] ); - const columns = useMemo[]>( + const columns = useMemo[]>( () => [ { id: 'name', Header: 'Name', - accessor: 'name', + accessor: 'symbol', Cell: (cellData) => ( (
Pool Logo @@ -108,16 +115,33 @@ export const PoolsTable = ({ minWidth: 185, sortDescFirst: true, }, + { + id: 'tknBalance', + Header: 'Tkn Balance', + accessor: 'tknBalance', + minWidth: 185, + sortDescFirst: true, + }, + { + id: 'bnTknBalance', + Header: 'BnTkn Balance', + accessor: 'bnTknBalance', + minWidth: 185, + sortDescFirst: true, + }, { id: 'apr', Header: 'Earn', accessor: 'apr7d', Cell: (cellData) => (
- {toBigNumber(cellData.value.total).isZero() && - cellData.row.original.tradingEnabled === false - ? 'New' - : `${cellData.value.total.toFixed(2)}%`} + {cellData.value + ? toBigNumber(cellData.value.total).isZero() && + !cellData.row.original.tradingEnabled + ? 'New' + : `${cellData.value.total.toFixed(2)}%` + : 'N/A'} + {} {cellData.row.original.latestProgram?.isActive && ( <> @@ -200,11 +224,11 @@ export const PoolsTable = ({ setLowEarnRate={setLowEarnRate} />
- + data={data} columns={columns} defaultSort={defaultSort} - isLoading={!pools.length} + isLoading={isLoading} search={search} />
diff --git a/src/elements/layoutHeader/LayoutHeader.tsx b/src/elements/layoutHeader/LayoutHeader.tsx index 9bfbaa8ed..fa9bbe9b7 100644 --- a/src/elements/layoutHeader/LayoutHeader.tsx +++ b/src/elements/layoutHeader/LayoutHeader.tsx @@ -13,12 +13,14 @@ import { getIsAppBusy } from 'store/bancor/bancor'; import { BancorURL } from 'router/bancorURL.service'; import { Navigate } from 'components/navigate/Navigate'; import { PopoverV3 } from 'components/popover/PopoverV3'; +import { useIsFetching } from 'react-query'; export const LayoutHeader = () => { const wallet = useWalletConnect(); const [isTop, setIsTop] = useState(true); const isLoading = useAppSelector(getIsAppBusy); + const isFetching = useIsFetching(); useEffect(() => { const listener = () => setIsTop(window.pageYOffset === 0); @@ -69,7 +71,7 @@ export const LayoutHeader = () => {
- {isLoading && ( + {!!(isLoading || isFetching) && (
diff --git a/src/index.tsx b/src/index.tsx index 2563ccef8..b2a76e6a1 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -10,6 +10,8 @@ import { Web3ReactProvider } from '@web3-react/core'; import 'styles/index.css'; import { QueryClient, QueryClientProvider } from 'react-query'; import { ReactQueryDevtools } from 'react-query/devtools'; +import { persistQueryClient } from 'react-query/persistQueryClient'; +import { createWebStoragePersister } from 'react-query/createWebStoragePersister'; const queryClient = new QueryClient({ defaultOptions: { @@ -17,10 +19,21 @@ const queryClient = new QueryClient({ refetchInterval: 60000, staleTime: 30000, useErrorBoundary: true, + cacheTime: 1000 * 60 * 60 * 24, // 24 hours }, }, }); +const localStoragePersister = createWebStoragePersister({ + key: 'bancor-test-local', + storage: window.localStorage, +}); + +persistQueryClient({ + queryClient, + persister: localStoragePersister, +}); + ReactDOM.render( diff --git a/src/queries/useApiDataV2.ts b/src/queries/useApiDataV2.ts index 2605f3560..e90468000 100644 --- a/src/queries/useApiDataV2.ts +++ b/src/queries/useApiDataV2.ts @@ -3,5 +3,8 @@ import { BancorApi } from 'services/api/bancorApi/bancorApi'; import { WelcomeData } from 'services/api/bancorApi/bancorApi.types'; export const useApiDataV2 = () => { - return useQuery(['v2', 'api'], BancorApi.v2.getWelcome); + return useQuery( + ['api', 'v2', 'welcome'], + BancorApi.v2.getWelcome + ); }; diff --git a/src/queries/useApiPoolsV3.ts b/src/queries/useApiPoolsV3.ts index 98bed12b5..b595550d0 100644 --- a/src/queries/useApiPoolsV3.ts +++ b/src/queries/useApiPoolsV3.ts @@ -3,8 +3,9 @@ import { BancorApi } from 'services/api/bancorApi/bancorApi'; import { APIPoolV3 } from 'services/api/bancorApi/bancorApi.types'; export const useApiPoolsV3 = () => { - return useQuery( - ['v3', 'api', 'pools'], - BancorApi.v3.getPools - ); + const queryKey = ['api', 'v3', 'pools']; + return useQuery(queryKey, BancorApi.v3.getPools, { + useErrorBoundary: true, + onError: (err) => console.error('query failed', queryKey, err), + }); }; diff --git a/src/queries/useApiTokensV3.ts b/src/queries/useApiTokensV3.ts index a12cea45b..1d4370e47 100644 --- a/src/queries/useApiTokensV3.ts +++ b/src/queries/useApiTokensV3.ts @@ -1,10 +1,24 @@ import { useQuery } from 'react-query'; import { BancorApi } from 'services/api/bancorApi/bancorApi'; import { APITokenV3 } from 'services/api/bancorApi/bancorApi.types'; +import { useDispatch } from 'react-redux'; +import { genericFailedNotification } from 'services/notifications/notifications'; export const useApiTokensV3 = () => { + const dispatch = useDispatch(); + return useQuery( - ['v3', 'api', 'tokens'], - BancorApi.v3.getTokens + ['api', 'v3', 'tokens'], + BancorApi.v3.getTokens, + { + useErrorBoundary: false, + onError: (err) => { + genericFailedNotification( + dispatch, + `${err.message}`, + `Server Error: ${['api', 'v3', 'tokens'].join('->')}` + ); + }, + } ); }; diff --git a/src/queries/useBalances.ts b/src/queries/useBalances.ts index 552f47d74..48120c6c1 100644 --- a/src/queries/useBalances.ts +++ b/src/queries/useBalances.ts @@ -1,14 +1,28 @@ import { useQuery } from 'react-query'; import { fetchTokenBalanceMulticall } from 'services/web3/token/token'; -import { useApiPoolsV3 } from 'queries/useApiPoolsV3'; +import { useAppSelector } from 'store/index'; +import { useV3ChainData } from 'queries/useV3ChainData'; +import { ethToken } from 'services/web3/config'; -export const useTokenBalances = (user?: string) => { - const { data: pools } = useApiPoolsV3(); - const ids = pools ? pools.map((p) => p.poolDltId) : []; +export const useBalances = () => { + const user = useAppSelector((state) => state.user.account); + const { data: pools } = useV3ChainData(); + const tknIds: string[] = []; + const bnTknIds: string[] = []; - return useQuery>( - ['v3', 'token', 'balances', user], - () => fetchTokenBalanceMulticall(ids, user!), - { enabled: !!user && !!pools } + !!pools && + pools.forEach((p) => { + tknIds.push(p.poolDltId); + bnTknIds.push(p.poolTokenDltId); + }); + + return useQuery | undefined>( + ['chain', 'v3', 'balances', user], + () => + fetchTokenBalanceMulticall( + [...tknIds, ...bnTknIds].filter((id) => id !== ethToken), + user! + ), + { enabled: !!user && !!pools, useErrorBoundary: true } ); }; diff --git a/src/queries/usePoolsV3.ts b/src/queries/usePoolsV3.ts new file mode 100644 index 000000000..575efa9f4 --- /dev/null +++ b/src/queries/usePoolsV3.ts @@ -0,0 +1,109 @@ +import { PoolV3Chain, useV3ChainData } from 'queries/useV3ChainData'; +import { useApiPoolsV3 } from 'queries/useApiPoolsV3'; +import { useMemo } from 'react'; +import { toBigNumber } from 'utils/helperFunctions'; +import { calcApr } from 'utils/formulas'; +import { standardsRewardsAPR } from 'services/observables/pools'; +import { useApiTokensV3 } from 'queries/useApiTokensV3'; +import { useBalances } from 'queries/useBalances'; +import { utils } from 'ethers'; + +export const usePoolsV3 = () => { + const chain = useV3ChainData(); + const apiPools = useApiPoolsV3(); + const apiTokens = useApiTokensV3(); + const balances = useBalances(); + + const data = useMemo(() => { + if (!chain.data) return undefined; + const apiPoolsMap = new Map(apiPools.data?.map((p) => [p.poolDltId, p])); + const apiTokensMap = new Map(apiTokens.data?.map((p) => [p.dltId, p])); + return chain.data.map((x) => { + const tknBalance = balances.data?.get && balances.data?.get(x.poolDltId); + const bnTknBalance = + balances.data?.get && balances.data?.get(x.poolTokenDltId); + const pool: PoolV3Chain = { + ...x, + tknBalance: tknBalance + ? utils.formatUnits(tknBalance, x.decimals) + : undefined, + bnTknBalance: bnTknBalance + ? utils.formatUnits(bnTknBalance, x.decimals) + : undefined, + }; + const apiPool = apiPoolsMap?.get(x.poolDltId); + const apiToken = apiTokensMap?.get(x.poolDltId); + if (!apiPool || !apiToken) { + return pool; + } + + // FIXES STAKED BALANCE = 0 WHEN TRADING ENABLED = FALSE + const stakedBalance = { ...apiPool.stakedBalance }; + if ( + apiPool.tradingEnabled === false && + toBigNumber(stakedBalance.usd).isZero() + ) { + stakedBalance.usd = toBigNumber(apiPool.stakedBalance.tkn) + .times(apiToken.rate.usd) + .toString(); + } + + // Calculate APR + const standardRewardsApr24H = standardsRewardsAPR(apiPool, pool.programs); + const standardRewardsApr7d = standardsRewardsAPR(apiPool, pool.programs); + + const tradingFeesApr24h = calcApr(apiPool.fees24h.usd, stakedBalance.usd); + const tradingFeesApr7d = calcApr( + apiPool.fees7d.usd, + stakedBalance.usd, + true + ); + + // TODO - add values once available + const autoCompoundingApr24H = 0; + const autoCompoundingApr7d = 0; + + const totalApr24H = toBigNumber(tradingFeesApr24h) + .plus(standardRewardsApr24H) + .plus(autoCompoundingApr24H) + .toNumber(); + + const totalApr7d = toBigNumber(tradingFeesApr7d) + .plus(autoCompoundingApr7d) + .plus(standardRewardsApr7d) + .toNumber(); + return { + ...pool, + ...{ + stakedBalance, + fees24h: apiPool.fees24h, + fees7d: apiPool.fees7d, + volume7d: apiPool.volume7d, + volume24h: apiPool.volume24h, + standardRewardsStaked: apiPool.standardRewardsStaked, + standardRewardsClaimed24h: apiPool.standardRewardsClaimed24h, + standardRewardsProviderJoined: apiPool.standardRewardsProviderJoined, + standardRewardsProviderLeft: apiPool.standardRewardsProviderLeft, + logoURI: + 'https://d1wmp5nysbq9xl.cloudfront.net/ethereum/tokens/' + + pool.poolDltId.toLowerCase() + + '.svg', + apr24h: { + tradingFees: tradingFeesApr24h, + standardRewards: standardRewardsApr24H, + autoCompounding: autoCompoundingApr24H, + total: totalApr24H, + }, + apr7d: { + tradingFees: tradingFeesApr7d, + standardRewards: standardRewardsApr7d, + autoCompounding: autoCompoundingApr7d, + total: totalApr7d, + }, + }, + }; + }); + }, [apiPools.data, apiTokens.data, balances?.data, chain.data]); + + return { ...chain, data }; +}; diff --git a/src/queries/useStatistics.ts b/src/queries/useStatistics.ts index 8491fb3e8..4a55f1dd3 100644 --- a/src/queries/useStatistics.ts +++ b/src/queries/useStatistics.ts @@ -97,7 +97,7 @@ export const useStatistics = () => { const { data: apiDataV2 } = useApiDataV2(); return useQuery( - ['v3', 'statistics'], + ['api', 'v3', 'statistics'], () => fetchStatistics(apiDataV2!), { enabled: !!apiDataV2 } ); diff --git a/src/queries/useV3ChainData.ts b/src/queries/useV3ChainData.ts new file mode 100644 index 000000000..bf2c97952 --- /dev/null +++ b/src/queries/useV3ChainData.ts @@ -0,0 +1,351 @@ +import { useQuery } from 'react-query'; +import { MultiCall } from 'services/web3/multicall/multicall'; +import { ContractsApi } from 'services/web3/v3/contractsApi'; +import { ethToken } from 'services/web3/config'; +import { BigNumber, utils } from 'ethers'; +import { RewardsProgramRaw } from 'services/web3/v3/portfolio/standardStaking'; +import dayjs from 'dayjs'; + +export interface PriceDictionaryV3 { + bnt?: string; + usd?: string; + eur?: string; + eth?: string; + tkn: string; +} + +export interface PoolV3Chain { + poolDltId: string; + poolTokenDltId: string; + name: string; + symbol: string; + decimals: number; + tradingLiquidityBNT: PriceDictionaryV3; + tradingLiquidityTKN: PriceDictionaryV3; + volume24h?: PriceDictionaryV3; + fees24h?: PriceDictionaryV3; + stakedBalance: PriceDictionaryV3; + tradingFeePPM: string; + tradingEnabled: boolean; + depositingEnabled: boolean; + standardRewardsClaimed24h?: PriceDictionaryV3; + standardRewardsProviderJoined?: PriceDictionaryV3; + standardRewardsProviderLeft?: PriceDictionaryV3; + standardRewardsStaked?: PriceDictionaryV3; + volume7d?: PriceDictionaryV3; + fees7d?: PriceDictionaryV3; + apr24h?: { + tradingFees: number; + standardRewards: number; + autoCompounding: number; + total: number; + }; + apr7d?: { + tradingFees: number; + standardRewards: number; + autoCompounding: number; + total: number; + }; + programs: RewardsProgramRaw[]; + latestProgram?: RewardsProgramRaw; + logoURI: string; + tknBalance?: string; + bnTknBalance?: string; +} + +const fetchMulticall = async ( + calls: MultiCall[], + toUtf8String = false, + blockHeight?: number +) => { + try { + const encoded = calls.map((call) => ({ + target: call.contractAddress, + callData: call.interface.encodeFunctionData( + call.methodName, + call.methodParameters + ), + })); + + const encodedRes = await ContractsApi.Multicall.read.tryAggregate( + false, + encoded, + { + blockTag: blockHeight, + } + ); + + return encodedRes.map((call, i) => { + if (!call.success) { + console.log(calls[i]); + throw new Error('multicall failed'); + } + if (toUtf8String) { + return utils.toUtf8String(call.returnData).replace(/[^a-zA-Z0-9]/g, ''); + } + const res = calls[i].interface.decodeFunctionResult( + calls[i].methodName, + call.returnData + ); + return res[0]; + }); + } catch (error) { + throw error; + } +}; + +const fetchEthData = async (): Promise => { + const ethDataCalls: MultiCall[] = [ + { + contractAddress: ContractsApi.BancorNetworkInfo.contractAddress, + interface: ContractsApi.BancorNetworkInfo.read.interface, + methodName: 'poolToken', + methodParameters: [ethToken], + }, + { + contractAddress: ContractsApi.BancorNetworkInfo.contractAddress, + interface: ContractsApi.BancorNetworkInfo.read.interface, + methodName: 'tradingLiquidity', + methodParameters: [ethToken], + }, + { + contractAddress: ContractsApi.BancorNetworkInfo.contractAddress, + interface: ContractsApi.BancorNetworkInfo.read.interface, + methodName: 'tradingEnabled', + methodParameters: [ethToken], + }, + { + contractAddress: ContractsApi.BancorNetworkInfo.contractAddress, + interface: ContractsApi.BancorNetworkInfo.read.interface, + methodName: 'depositingEnabled', + methodParameters: [ethToken], + }, + { + contractAddress: ContractsApi.BancorNetworkInfo.contractAddress, + interface: ContractsApi.BancorNetworkInfo.read.interface, + methodName: 'stakedBalance', + methodParameters: [ethToken], + }, + { + contractAddress: ContractsApi.BancorNetworkInfo.contractAddress, + interface: ContractsApi.BancorNetworkInfo.read.interface, + methodName: 'tradingFeePPM', + methodParameters: [ethToken], + }, + { + contractAddress: ContractsApi.StandardRewards.contractAddress, + interface: ContractsApi.StandardRewards.read.interface, + methodName: 'latestProgramId', + methodParameters: [ethToken], + }, + { + contractAddress: ContractsApi.StandardRewards.contractAddress, + interface: ContractsApi.StandardRewards.read.interface, + methodName: 'latestProgramId', + methodParameters: [ethToken], + }, + ]; + const res = await fetchMulticall(ethDataCalls); + + return { + poolDltId: ethToken, + name: 'Ethereum', + symbol: 'ETH', + poolTokenDltId: res[0], + decimals: 18, + tradingEnabled: res[2], + tradingLiquidityBNT: { + bnt: utils.formatUnits(res[1].bntTradingLiquidity, 18), + tkn: utils.formatUnits(res[1].bntTradingLiquidity, 18), + }, + tradingLiquidityTKN: { + tkn: utils.formatUnits(res[1].baseTokenTradingLiquidity, 18), + }, + depositingEnabled: res[3], + stakedBalance: { tkn: utils.formatUnits(res[4], 18) }, + tradingFeePPM: res[5], + programs: [], + logoURI: + 'https://d1wmp5nysbq9xl.cloudfront.net/ethereum/tokens/' + + ethToken.toLowerCase() + + '.svg', + }; +}; + +const fetchChainV3Programs = async ( + ids: BigNumber[] +): Promise => { + const programs = await ContractsApi.StandardRewards.read.programs(ids); + return programs.map((program) => { + const data: RewardsProgramRaw = { + id: program.id.toString(), + pool: program.pool, + poolToken: program.poolToken, + rewardsToken: program.rewardsToken, + rewardRate: program.rewardRate.toString(), + isEnabled: program.isEnabled, + startTime: program.startTime, + endTime: program.endTime, + isActive: + program.isEnabled && + program.startTime <= dayjs.utc().unix() && + program.endTime >= dayjs.utc().unix(), + }; + return data; + }); +}; + +const fetchV3ChainData = async (): Promise => { + const [liquidityPools, programIds] = await Promise.all([ + ContractsApi.BancorNetwork.read.liquidityPools(), + ContractsApi.StandardRewards.read.programIds(), + ]); + + const pools = liquidityPools.filter((id) => id !== ethToken); + + const poolTokensCalls: MultiCall[] = []; + const tokenDecimalsCalls: MultiCall[] = []; + const tokenNamesCalls: MultiCall[] = []; + const tokenSymbolCalls: MultiCall[] = []; + const tradingLiquidityCalls: MultiCall[] = []; + const tradingEnabledCalls: MultiCall[] = []; + const depositingEnabledCalls: MultiCall[] = []; + const stakedBalanceCalls: MultiCall[] = []; + const tradingFeePPMCalls: MultiCall[] = []; + const latestProgramIdCalls: MultiCall[] = []; + + pools.forEach((id) => { + poolTokensCalls.push({ + contractAddress: ContractsApi.BancorNetworkInfo.contractAddress, + interface: ContractsApi.BancorNetworkInfo.read.interface, + methodName: 'poolToken', + methodParameters: [id], + }); + tokenDecimalsCalls.push({ + contractAddress: id, + interface: ContractsApi.Token(id).read.interface, + methodName: 'decimals', + methodParameters: [], + }); + tokenNamesCalls.push({ + contractAddress: id, + interface: ContractsApi.Token(id).read.interface, + methodName: 'name', + methodParameters: [], + }); + tokenSymbolCalls.push({ + contractAddress: id, + interface: ContractsApi.Token(id).read.interface, + methodName: 'symbol', + methodParameters: [], + }); + tradingLiquidityCalls.push({ + contractAddress: ContractsApi.BancorNetworkInfo.contractAddress, + interface: ContractsApi.BancorNetworkInfo.read.interface, + methodName: 'tradingLiquidity', + methodParameters: [id], + }); + tradingEnabledCalls.push({ + contractAddress: ContractsApi.BancorNetworkInfo.contractAddress, + interface: ContractsApi.BancorNetworkInfo.read.interface, + methodName: 'tradingEnabled', + methodParameters: [id], + }); + depositingEnabledCalls.push({ + contractAddress: ContractsApi.BancorNetworkInfo.contractAddress, + interface: ContractsApi.BancorNetworkInfo.read.interface, + methodName: 'depositingEnabled', + methodParameters: [id], + }); + stakedBalanceCalls.push({ + contractAddress: ContractsApi.BancorNetworkInfo.contractAddress, + interface: ContractsApi.BancorNetworkInfo.read.interface, + methodName: 'stakedBalance', + methodParameters: [id], + }); + tradingFeePPMCalls.push({ + contractAddress: ContractsApi.BancorNetworkInfo.contractAddress, + interface: ContractsApi.BancorNetworkInfo.read.interface, + methodName: 'tradingFeePPM', + methodParameters: [id], + }); + latestProgramIdCalls.push({ + contractAddress: ContractsApi.StandardRewards.contractAddress, + interface: ContractsApi.StandardRewards.read.interface, + methodName: 'latestProgramId', + methodParameters: [id], + }); + }); + + const [ + poolTokens, + tokenDecimals, + tokenNames, + tokenSymbols, + tradingEnabled, + tradingLiquidity, + depositingEnabled, + stakedBalance, + tradingFeePPM, + latestProgramIds, + ethData, + programs, + ] = await Promise.all([ + fetchMulticall(poolTokensCalls), + fetchMulticall(tokenDecimalsCalls), + fetchMulticall(tokenNamesCalls, true), + fetchMulticall(tokenSymbolCalls, true), + fetchMulticall(tradingEnabledCalls), + fetchMulticall(tradingLiquidityCalls), + fetchMulticall(depositingEnabledCalls), + fetchMulticall(stakedBalanceCalls), + fetchMulticall(tradingFeePPMCalls), + fetchMulticall(latestProgramIdCalls), + fetchEthData(), + fetchChainV3Programs(programIds), + ]); + + const data: PoolV3Chain[] = pools.map((id, i) => ({ + poolDltId: id, + name: tokenNames[i], + symbol: tokenSymbols[i], + poolTokenDltId: poolTokens[i], + decimals: tokenDecimals[i], + tradingEnabled: tradingEnabled[i], + tradingLiquidityBNT: { + bnt: utils.formatUnits( + tradingLiquidity[i].baseTokenTradingLiquidity, + tokenDecimals[i] + ), + tkn: utils.formatUnits(tradingLiquidity[i].bntTradingLiquidity, 18), + }, + tradingLiquidityTKN: { + tkn: utils.formatUnits( + tradingLiquidity[i].baseTokenTradingLiquidity, + tokenDecimals[i] + ), + }, + depositingEnabled: depositingEnabled[i], + stakedBalance: { + tkn: utils.formatUnits(stakedBalance[i], tokenDecimals[i]), + }, + tradingFeePPM: tradingFeePPM[i], + latestProgram: latestProgramIds[i] + ? latestProgramIds[i].toString() + : undefined, + programs: programs.filter((p) => p.pool === id), + logoURI: + 'https://d1wmp5nysbq9xl.cloudfront.net/ethereum/tokens/' + + id.toLowerCase() + + '.svg', + })); + data.push(ethData); + return data; +}; + +export const useV3ChainData = () => { + return useQuery(['chain', 'v3', 'pools'], fetchV3ChainData, { + refetchInterval: 144 * 1000, + staleTime: 88 * 1000, + }); +}; diff --git a/src/services/api/bancorApi/bancorApi.types.ts b/src/services/api/bancorApi/bancorApi.types.ts index b4d3a9559..234833975 100644 --- a/src/services/api/bancorApi/bancorApi.types.ts +++ b/src/services/api/bancorApi/bancorApi.types.ts @@ -79,6 +79,14 @@ export interface PriceDictionary { tkn: string; } +export interface PriceDictionaryV3 { + bnt?: string; + usd?: string; + eur?: string; + eth?: string; + tkn: string; +} + export interface APIPoolV3 { poolDltId: string; poolTokenDltId: string; diff --git a/src/services/api/bancorApi/bancorApiV3.ts b/src/services/api/bancorApi/bancorApiV3.ts index 4d0612699..e2f8fbc81 100644 --- a/src/services/api/bancorApi/bancorApiV3.ts +++ b/src/services/api/bancorApi/bancorApiV3.ts @@ -17,33 +17,19 @@ const axiosInstance = axios.create({ export abstract class BancorV3Api { static getPools = async (): Promise => { - try { - const { data } = await axiosInstance.get>( - '/pools' - ); - return data.data; - } catch (error) { - console.error(error); - } - - return []; + const { data } = await axiosInstance.get>('/pools'); + return data.data; }; static getTokens = async (): Promise => { - try { - const { data } = await axiosInstance.get>( - '/tokens' - ); - return data.data.map((token) => ({ - ...token, - // TODO remove after Bancor API v3 is updated - rateHistory7d: [], - })); - } catch (error) { - console.error(error); - } - - return []; + const { data } = await axiosInstance.get>( + '/tokens' + ); + return data.data.map((token) => ({ + ...token, + // TODO remove after Bancor API v3 is updated + rateHistory7d: [], + })); }; static getStatistics = async (): Promise => { diff --git a/src/services/notifications/notifications.ts b/src/services/notifications/notifications.ts index 77cbe3c4c..121e87823 100644 --- a/src/services/notifications/notifications.ts +++ b/src/services/notifications/notifications.ts @@ -676,12 +676,13 @@ export const rewardsClaimedNotification = ( export const genericFailedNotification = ( dispatch: any, - msg = 'Unknown error occurred' + msg = 'Unknown error occurred', + title = 'Transaction Failed' ) => showNotification( { type: NotificationType.error, - title: 'Transaction Failed', + title, msg: `${msg} - Please try again or contact support`, }, dispatch diff --git a/src/services/web3/multicall/multicall.ts b/src/services/web3/multicall/multicall.ts index b9c3a62c9..ed88b8818 100644 --- a/src/services/web3/multicall/multicall.ts +++ b/src/services/web3/multicall/multicall.ts @@ -1,7 +1,5 @@ -import { web3 } from 'services/web3'; -import { Multicall__factory } from 'services/web3/abis/types'; -import { multiCallContract } from 'services/web3/config'; import { Interface } from '@ethersproject/abi'; +import { ContractsApi } from 'services/web3/v3/contractsApi'; export interface MultiCall { contractAddress: string; @@ -11,11 +9,6 @@ export interface MultiCall { } export const multicall = async (calls: MultiCall[], blockHeight?: number) => { - const multicallContract = Multicall__factory.connect( - multiCallContract, - web3.provider - ); - try { const encoded = calls.map((call) => ({ target: call.contractAddress.toLocaleLowerCase(), @@ -24,9 +17,13 @@ export const multicall = async (calls: MultiCall[], blockHeight?: number) => { call.methodParameters ), })); - const encodedRes = await multicallContract.tryAggregate(false, encoded, { - blockTag: blockHeight, - }); + const encodedRes = await ContractsApi.Multicall.read.tryAggregate( + false, + encoded, + { + blockTag: blockHeight, + } + ); return encodedRes.map((call, i) => { if (!call.success) return []; diff --git a/src/services/web3/token/token.ts b/src/services/web3/token/token.ts index c13e0361b..7556d6a77 100644 --- a/src/services/web3/token/token.ts +++ b/src/services/web3/token/token.ts @@ -14,6 +14,9 @@ export const fetchTokenBalanceMulticall = async ( tokenIds: string[], user: string ): Promise> => { + if (!user || tokenIds.length === 0) { + throw new Error('Multicall Error no user provided'); + } const calls = tokenIds.map((tokenId) => buildTokenBalanceCall(tokenId, user)); const res = await multicall(calls); if (!res || !res.length) { diff --git a/src/services/web3/v3/contractsApi.ts b/src/services/web3/v3/contractsApi.ts index be481a5b9..8c8a07df2 100644 --- a/src/services/web3/v3/contractsApi.ts +++ b/src/services/web3/v3/contractsApi.ts @@ -17,6 +17,8 @@ import { PendingWithdrawals__factory, BancorPortal, BancorPortal__factory, + Multicall, + Multicall__factory, } from 'services/web3/abis/types'; import { web3, writeWeb3 } from 'services/web3/index'; import { providers } from 'ethers'; @@ -28,6 +30,7 @@ import poolCollectionType1Address from 'services/web3/abis/v3/PoolCollectionType import stakingRewardsClaimAddress from 'services/web3/abis/StakingRewardsClaim.json'; import standardRewardsAddress from 'services/web3/abis/v3/StandardRewards_Proxy.json'; import bancorPortalAddress from 'services/web3/abis/v3/BancorPortal_Proxy.json'; +import { multiCallContract } from 'services/web3/config'; export class BancorContract { constructor(contractAddress: string, contractFactory: any) { @@ -109,6 +112,11 @@ export abstract class ContractsApi { BancorPortal__factory ); + static Multicall = new BancorContract( + multiCallContract, + Multicall__factory + ); + static Token = (tokenAddress: string) => { return new BancorContract(tokenAddress, Token__factory); }; diff --git a/yarn.lock b/yarn.lock index 6e46125bd..bfa5427a1 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1131,7 +1131,7 @@ dependencies: regenerator-runtime "^0.12.0" -"@babel/runtime@^7.0.0", "@babel/runtime@^7.10.2", "@babel/runtime@^7.11.2", "@babel/runtime@^7.12.5", "@babel/runtime@^7.15.4", "@babel/runtime@^7.16.3", "@babel/runtime@^7.17.8", "@babel/runtime@^7.18.3", "@babel/runtime@^7.3.1", "@babel/runtime@^7.5.0", "@babel/runtime@^7.5.5", "@babel/runtime@^7.6.2", "@babel/runtime@^7.7.2", "@babel/runtime@^7.7.6", "@babel/runtime@^7.8.4", "@babel/runtime@^7.9.2": +"@babel/runtime@^7.0.0", "@babel/runtime@^7.10.2", "@babel/runtime@^7.11.2", "@babel/runtime@^7.12.5", "@babel/runtime@^7.15.4", "@babel/runtime@^7.16.3", "@babel/runtime@^7.17.8", "@babel/runtime@^7.17.9", "@babel/runtime@^7.18.3", "@babel/runtime@^7.3.1", "@babel/runtime@^7.5.0", "@babel/runtime@^7.5.5", "@babel/runtime@^7.6.2", "@babel/runtime@^7.7.2", "@babel/runtime@^7.7.6", "@babel/runtime@^7.8.4", "@babel/runtime@^7.9.2": version "7.18.6" resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.18.6.tgz#6a1ef59f838debd670421f8c7f2cbb8da9751580" integrity sha512-t9wi7/AW6XtKahAe20Yw0/mMljKq0B1r2fPdvaAdV/KPDZewFXdaaa6K7lxmZBZ8FBNpCiAT6iHPmd6QO9bKfQ== @@ -3958,6 +3958,11 @@ resolved "https://registry.yarnpkg.com/@types/unist/-/unist-2.0.6.tgz#250a7b16c3b91f672a24552ec64678eeb1d3a08d" integrity sha512-PBjIUxZHOuj0R15/xuwJYjFi+KZdNFrehocChv4g5hu6aFroHue8m0lBP0POdK2nKzbw0cgV1mws8+V/JAcEkQ== +"@types/use-sync-external-store@^0.0.3": + version "0.0.3" + resolved "https://registry.yarnpkg.com/@types/use-sync-external-store/-/use-sync-external-store-0.0.3.tgz#b6725d5f4af24ace33b36fafd295136e75509f43" + integrity sha512-EwmlvuaxPNej9+T4v5AuBPJa2x2UOJVdjCtDHgcDqitUeOtjnJKJ+apYjVcAoBEMjKW1VVFGZLUb5+qqa09XFA== + "@types/webpack-env@^1.16.0": version "1.17.0" resolved "https://registry.yarnpkg.com/@types/webpack-env/-/webpack-env-1.17.0.tgz#f99ce359f1bfd87da90cc4a57cab0a18f34a48d0" @@ -14078,6 +14083,13 @@ react-element-to-jsx-string@^14.3.4: is-plain-object "5.0.0" react-is "17.0.2" +react-error-boundary@^3.1.4: + version "3.1.4" + resolved "https://registry.yarnpkg.com/react-error-boundary/-/react-error-boundary-3.1.4.tgz#255db92b23197108757a888b01e5b729919abde0" + integrity sha512-uM9uPzZJTF6wRQORmSrvOIgt4lJ9MC1sNgEOj2XGsDTRE4kmpWxg7ENK9EWNKJRMAOY9z0MuF4yIfl6gp4sotA== + dependencies: + "@babel/runtime" "^7.12.5" + react-error-overlay@6.0.9, react-error-overlay@^6.0.11: version "6.0.9" resolved "https://registry.yarnpkg.com/react-error-overlay/-/react-error-overlay-6.0.9.tgz#3c743010c9359608c375ecd6bc76f35d93995b0a" @@ -14136,14 +14148,16 @@ react-popper@^2.2.5: react-fast-compare "^3.0.1" warning "^4.0.2" -react-query@^3.39.1: - version "3.39.1" - resolved "https://registry.yarnpkg.com/react-query/-/react-query-3.39.1.tgz#3876c0fdac7a3b5a84e195534e5fa8fbdd628847" - integrity sha512-qYKT1bavdDiQZbngWZyPotlBVzcBjDYEJg5RQLBa++5Ix5jjfbEYJmHSZRZD+USVHUSvl/ey9Hu+QfF1QAK80A== +react-query@^4.0.0-beta.23: + version "4.0.0-beta.23" + resolved "https://registry.yarnpkg.com/react-query/-/react-query-4.0.0-beta.23.tgz#76713547670ef1f991ae828b3d51df63ec6e035c" + integrity sha512-e6mNBVAYGy0M1OwX0mhRB/lCkOedKeqTUrbPjNCqvm8hQGUsJJobqfHVvTv8o6JJaOO2MFcxKF4vZM+PEKbHZA== dependencies: - "@babel/runtime" "^7.5.5" + "@babel/runtime" "^7.17.9" + "@types/use-sync-external-store" "^0.0.3" broadcast-channel "^3.4.1" match-sorter "^6.0.2" + use-sync-external-store "^1.1.0" react-redux@^7.2.6: version "7.2.8" @@ -16698,6 +16712,11 @@ use-async-effect@^2.2.3: resolved "https://registry.yarnpkg.com/use-async-effect/-/use-async-effect-2.2.6.tgz#00f2dee71e2f6188c5daf6a067e2bc151f7566b7" integrity sha512-wKUpaHkuF4rzBHawP87o1KzoK2IxJ6De8fUyQ3GN2114zb4zqT87+SEbCHS+F+0inZ2Y+k6Tm1LOCQgYTSD9ww== +use-sync-external-store@^1.1.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz#7dbefd6ef3fe4e767a0cf5d7287aacfb5846928a" + integrity sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA== + use@^3.1.0: version "3.1.1" resolved "https://registry.yarnpkg.com/use/-/use-3.1.1.tgz#d50c8cac79a19fbc20f2911f56eb973f4e10070f" From d60264a211dbc6b29cf72988f83218c30f6c3d11 Mon Sep 17 00:00:00 2001 From: Jan Langheimer Date: Fri, 8 Jul 2022 17:03:37 +0200 Subject: [PATCH 07/36] remove alert when BNT --- src/elements/admin/AdminQueryTest.tsx | 19 +++ src/index.tsx | 26 ++- src/pages/Admin.tsx | 5 + .../chain/useChainDepositingEnabled.ts | 18 +++ src/queries/chain/useChainPoolByID.ts | 9 ++ src/queries/chain/useChainPoolIds.ts | 16 ++ src/queries/chain/useChainPoolTokenIds.ts | 17 ++ src/queries/chain/useChainPools.ts | 117 ++++++++++++++ src/queries/chain/useChainStakedBalance.ts | 19 +++ src/queries/chain/useChainTokenDecimals.ts | 17 ++ src/queries/chain/useChainTokenName.ts | 17 ++ src/queries/chain/useChainTokenSymbol.ts | 17 ++ src/queries/chain/useChainTradingEnabled.ts | 17 ++ src/queries/chain/useChainTradingFee.ts | 17 ++ src/queries/chain/useChainTradingLiquidity.ts | 22 +++ src/queries/queryKeyFactory.ts | 45 ++++++ src/queries/queryOptions.ts | 11 ++ src/queries/usePoolsV3.ts | 4 - src/queries/useV3ChainData.ts | 153 ++++++++---------- src/services/web3/multicall/multicall.ts | 42 +++++ .../web3/multicall/multicallFunctions.ts | 84 ++++++++++ 21 files changed, 592 insertions(+), 100 deletions(-) create mode 100644 src/elements/admin/AdminQueryTest.tsx create mode 100644 src/queries/chain/useChainDepositingEnabled.ts create mode 100644 src/queries/chain/useChainPoolByID.ts create mode 100644 src/queries/chain/useChainPoolIds.ts create mode 100644 src/queries/chain/useChainPoolTokenIds.ts create mode 100644 src/queries/chain/useChainPools.ts create mode 100644 src/queries/chain/useChainStakedBalance.ts create mode 100644 src/queries/chain/useChainTokenDecimals.ts create mode 100644 src/queries/chain/useChainTokenName.ts create mode 100644 src/queries/chain/useChainTokenSymbol.ts create mode 100644 src/queries/chain/useChainTradingEnabled.ts create mode 100644 src/queries/chain/useChainTradingFee.ts create mode 100644 src/queries/chain/useChainTradingLiquidity.ts create mode 100644 src/queries/queryKeyFactory.ts create mode 100644 src/queries/queryOptions.ts create mode 100644 src/services/web3/multicall/multicallFunctions.ts diff --git a/src/elements/admin/AdminQueryTest.tsx b/src/elements/admin/AdminQueryTest.tsx new file mode 100644 index 000000000..7d4f740c7 --- /dev/null +++ b/src/elements/admin/AdminQueryTest.tsx @@ -0,0 +1,19 @@ +import { useChainPools } from 'queries/chain/useChainPools'; + +export const AdminQueryTest = () => { + const { data: chainData, isLoading, isFetching } = useChainPools(); + + return ( +
+ admin query test +
+ {isFetching && 'fetching...'} + {isLoading ? ( + 'loading...' + ) : ( +
{JSON.stringify(chainData, null, 2)}
+ )} +
+
+ ); +}; diff --git a/src/index.tsx b/src/index.tsx index b2a76e6a1..ba26d0e57 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -10,29 +10,27 @@ import { Web3ReactProvider } from '@web3-react/core'; import 'styles/index.css'; import { QueryClient, QueryClientProvider } from 'react-query'; import { ReactQueryDevtools } from 'react-query/devtools'; -import { persistQueryClient } from 'react-query/persistQueryClient'; -import { createWebStoragePersister } from 'react-query/createWebStoragePersister'; -const queryClient = new QueryClient({ +export const queryClient = new QueryClient({ defaultOptions: { queries: { refetchInterval: 60000, staleTime: 30000, useErrorBoundary: true, - cacheTime: 1000 * 60 * 60 * 24, // 24 hours + // cacheTime: 1000 * 60 * 60 * 24, // 24 hours }, }, }); - -const localStoragePersister = createWebStoragePersister({ - key: 'bancor-test-local', - storage: window.localStorage, -}); - -persistQueryClient({ - queryClient, - persister: localStoragePersister, -}); +// +// const localStoragePersister = createWebStoragePersister({ +// key: 'bancor-test-local', +// storage: window.localStorage, +// }); +// +// persistQueryClient({ +// queryClient, +// persister: localStoragePersister, +// }); ReactDOM.render( diff --git a/src/pages/Admin.tsx b/src/pages/Admin.tsx index 8954260c4..f11a9a44b 100644 --- a/src/pages/Admin.tsx +++ b/src/pages/Admin.tsx @@ -2,12 +2,17 @@ import { AdminTknData } from 'elements/admin/AdminTknData'; import { AdminUseMainnet } from 'elements/admin/AdminUseMainnet'; import { AdminUseFork } from 'elements/admin/AdminUseFork'; import { AdminControls } from 'elements/admin/AdminControls'; +import { AdminQueryTest } from 'elements/admin/AdminQueryTest'; export const Admin = () => { return (

Bancor Network Configurator

+ + +
+
diff --git a/src/queries/chain/useChainDepositingEnabled.ts b/src/queries/chain/useChainDepositingEnabled.ts new file mode 100644 index 000000000..3f8b42ce2 --- /dev/null +++ b/src/queries/chain/useChainDepositingEnabled.ts @@ -0,0 +1,18 @@ +import { useQuery } from 'react-query'; +import { QueryKey } from 'queries/queryKeyFactory'; +import { useChainPoolIds } from 'queries/chain/useChainPoolIds'; +import { queryOptionsNoInterval } from 'queries/queryOptions'; +import { + buildMulticallDepositingEnabled, + fetchMulticallHelper, +} from 'services/web3/multicall/multicallFunctions'; + +export const useChainDepositingEnabled = () => { + const { data: poolIds } = useChainPoolIds(); + return useQuery( + QueryKey.chainCoreDepositingEnabled(poolIds?.length), + () => + fetchMulticallHelper(poolIds!, buildMulticallDepositingEnabled), + queryOptionsNoInterval(!!poolIds) + ); +}; diff --git a/src/queries/chain/useChainPoolByID.ts b/src/queries/chain/useChainPoolByID.ts new file mode 100644 index 000000000..25babf64a --- /dev/null +++ b/src/queries/chain/useChainPoolByID.ts @@ -0,0 +1,9 @@ +import { useChainPools } from 'queries/chain/useChainPools'; + +export const useChainPoolByID = (id: string) => { + const pools = useChainPools(); + + const data = pools.data?.find((pool) => pool.poolDltId === id); + + return { ...pools, data }; +}; diff --git a/src/queries/chain/useChainPoolIds.ts b/src/queries/chain/useChainPoolIds.ts new file mode 100644 index 000000000..04e8c28b9 --- /dev/null +++ b/src/queries/chain/useChainPoolIds.ts @@ -0,0 +1,16 @@ +import { useQuery } from 'react-query'; +import { ContractsApi } from 'services/web3/v3/contractsApi'; +import { QueryKey } from 'queries/queryKeyFactory'; +import { ethToken } from 'services/web3/config'; +import { queryOptionsStaleTimeLow } from 'queries/queryOptions'; + +export const useChainPoolIds = () => { + return useQuery( + QueryKey.chainCorePoolIds(), + async () => { + const pools = await ContractsApi.BancorNetwork.read.liquidityPools(); + return pools.filter((id) => id !== ethToken); + }, + queryOptionsStaleTimeLow() + ); +}; diff --git a/src/queries/chain/useChainPoolTokenIds.ts b/src/queries/chain/useChainPoolTokenIds.ts new file mode 100644 index 000000000..1ee17d142 --- /dev/null +++ b/src/queries/chain/useChainPoolTokenIds.ts @@ -0,0 +1,17 @@ +import { useQuery } from 'react-query'; +import { QueryKey } from 'queries/queryKeyFactory'; +import { useChainPoolIds } from 'queries/chain/useChainPoolIds'; +import { queryOptionsNoInterval } from 'queries/queryOptions'; +import { + buildMulticallPoolToken, + fetchMulticallHelper, +} from 'services/web3/multicall/multicallFunctions'; + +export const useChainPoolTokenIds = () => { + const { data: poolIds } = useChainPoolIds(); + return useQuery( + QueryKey.chainCorePoolTokenIds(poolIds?.length), + () => fetchMulticallHelper(poolIds!, buildMulticallPoolToken), + queryOptionsNoInterval(!!poolIds) + ); +}; diff --git a/src/queries/chain/useChainPools.ts b/src/queries/chain/useChainPools.ts new file mode 100644 index 000000000..f7f348a5e --- /dev/null +++ b/src/queries/chain/useChainPools.ts @@ -0,0 +1,117 @@ +import { useChainPoolIds } from 'queries/chain/useChainPoolIds'; +import { useChainTokenSymbol } from 'queries/chain/useChainTokenSymbol'; +import { useChainTokenDecimals } from 'queries/chain/useChainTokenDecimals'; +import { useChainTokenName } from 'queries/chain/useChainTokenName'; +import { useChainTradingEnabled } from 'queries/chain/useChainTradingEnabled'; +import { useChainPoolTokenIds } from 'queries/chain/useChainPoolTokenIds'; +import { useChainTradingLiquidity } from 'queries/chain/useChainTradingLiquidity'; +import { utils } from 'ethers'; +import { useChainDepositingEnabled } from 'queries/chain/useChainDepositingEnabled'; +import { useChainStakedBalance } from 'queries/chain/useChainStakedBalance'; +import { PoolV3Chain } from 'queries/useV3ChainData'; +import { useChainTradingFee } from 'queries/chain/useChainTradingFee'; + +export const useChainPools = () => { + const poolIds = useChainPoolIds(); + const symbols = useChainTokenSymbol(); + const decimals = useChainTokenDecimals(); + const name = useChainTokenName(); + const tradingEnabled = useChainTradingEnabled(); + const poolTokens = useChainPoolTokenIds(); + const tradingLiquidity = useChainTradingLiquidity(); + const depositingEnabled = useChainDepositingEnabled(); + const stakedBalance = useChainStakedBalance(); + const tradingFee = useChainTradingFee(); + + const isLoading = + poolIds.isLoading || + symbols.isLoading || + decimals.isLoading || + tradingEnabled.isLoading || + poolTokens.isLoading || + tradingLiquidity.isLoading || + depositingEnabled.isLoading || + stakedBalance.isLoading || + tradingFee.isLoading || + name.isLoading; + + const isFetching = + poolIds.isFetching || + symbols.isFetching || + decimals.isFetching || + tradingEnabled.isFetching || + poolTokens.isFetching || + tradingLiquidity.isFetching || + depositingEnabled.isFetching || + stakedBalance.isFetching || + tradingFee.isFetching || + name.isFetching; + + const error = + poolIds.error || + symbols.error || + decimals.error || + name.error || + tradingEnabled.error || + tradingLiquidity.error || + depositingEnabled.error || + stakedBalance.error || + tradingFee.error || + poolTokens.error; + + const data = (): PoolV3Chain[] | undefined => { + if ( + !poolIds.data || + !symbols.data || + !decimals.data || + !name.data || + !tradingEnabled.data || + !tradingLiquidity.data || + !depositingEnabled.data || + !stakedBalance.data || + !tradingFee.data || + !poolTokens.data + ) { + return undefined; + } + + return poolIds.data.map((id) => { + const tokenDecimals = decimals.data.get(id)!; + const tokenTradingLiquidity = tradingLiquidity.data.get(id)!; + + return { + poolDltId: id, + poolTokenDltId: poolTokens.data.get(id)!, + symbol: symbols.data.get(id)!, + decimals: tokenDecimals, + name: name.data.get(id)!, + tradingFeePPM: tradingFee.data.get(id)!, + tradingEnabled: tradingEnabled.data.get(id)!, + depositingEnabled: depositingEnabled.data.get(id)!, + tradingLiquidityBNT: { + bnt: utils.formatUnits( + tokenTradingLiquidity.bntTradingLiquidity, + tokenDecimals + ), + tkn: utils.formatUnits(tokenTradingLiquidity.bntTradingLiquidity, 18), + }, + tradingLiquidityTKN: { + tkn: utils.formatUnits( + tokenTradingLiquidity.baseTokenTradingLiquidity, + tokenDecimals + ), + }, + stakedBalance: { + tkn: utils.formatUnits(stakedBalance.data.get(id)!, tokenDecimals), + }, + programs: [], + logoURI: + 'https://d1wmp5nysbq9xl.cloudfront.net/ethereum/tokens/' + + id.toLowerCase() + + '.svg', + }; + }); + }; + + return { data: data(), isLoading, error, isFetching }; +}; diff --git a/src/queries/chain/useChainStakedBalance.ts b/src/queries/chain/useChainStakedBalance.ts new file mode 100644 index 000000000..a57da3e48 --- /dev/null +++ b/src/queries/chain/useChainStakedBalance.ts @@ -0,0 +1,19 @@ +import { useQuery } from 'react-query'; +import { QueryKey } from 'queries/queryKeyFactory'; +import { useChainPoolIds } from 'queries/chain/useChainPoolIds'; +import { queryOptionsStaleTimeLow } from 'queries/queryOptions'; +import { + buildMulticallStakedBalance, + fetchMulticallHelper, +} from 'services/web3/multicall/multicallFunctions'; +import { BigNumberish } from 'ethers'; + +export const useChainStakedBalance = () => { + const { data: poolIds } = useChainPoolIds(); + return useQuery( + QueryKey.chainCoreStakedBalance(poolIds?.length), + () => + fetchMulticallHelper(poolIds!, buildMulticallStakedBalance), + queryOptionsStaleTimeLow(!!poolIds) + ); +}; diff --git a/src/queries/chain/useChainTokenDecimals.ts b/src/queries/chain/useChainTokenDecimals.ts new file mode 100644 index 000000000..4934c5632 --- /dev/null +++ b/src/queries/chain/useChainTokenDecimals.ts @@ -0,0 +1,17 @@ +import { useQuery } from 'react-query'; +import { QueryKey } from 'queries/queryKeyFactory'; +import { useChainPoolIds } from 'queries/chain/useChainPoolIds'; +import { + buildMulticallDecimal, + fetchMulticallHelper, +} from 'services/web3/multicall/multicallFunctions'; +import { queryOptionsNoInterval } from 'queries/queryOptions'; + +export const useChainTokenDecimals = () => { + const { data: poolIds } = useChainPoolIds(); + return useQuery( + QueryKey.chainCoreDecimals(poolIds?.length), + () => fetchMulticallHelper(poolIds!, buildMulticallDecimal), + queryOptionsNoInterval(!!poolIds) + ); +}; diff --git a/src/queries/chain/useChainTokenName.ts b/src/queries/chain/useChainTokenName.ts new file mode 100644 index 000000000..a3be23dd9 --- /dev/null +++ b/src/queries/chain/useChainTokenName.ts @@ -0,0 +1,17 @@ +import { useQuery } from 'react-query'; +import { QueryKey } from 'queries/queryKeyFactory'; +import { useChainPoolIds } from 'queries/chain/useChainPoolIds'; +import { queryOptionsNoInterval } from 'queries/queryOptions'; +import { + buildMulticallName, + fetchMulticallHelper, +} from 'services/web3/multicall/multicallFunctions'; + +export const useChainTokenName = () => { + const { data: poolIds } = useChainPoolIds(); + return useQuery( + QueryKey.chainCoreName(poolIds?.length), + () => fetchMulticallHelper(poolIds!, buildMulticallName, true), + queryOptionsNoInterval(!!poolIds) + ); +}; diff --git a/src/queries/chain/useChainTokenSymbol.ts b/src/queries/chain/useChainTokenSymbol.ts new file mode 100644 index 000000000..77ec2af30 --- /dev/null +++ b/src/queries/chain/useChainTokenSymbol.ts @@ -0,0 +1,17 @@ +import { useQuery } from 'react-query'; +import { QueryKey } from 'queries/queryKeyFactory'; +import { useChainPoolIds } from 'queries/chain/useChainPoolIds'; +import { queryOptionsNoInterval } from 'queries/queryOptions'; +import { + buildMulticallSymbol, + fetchMulticallHelper, +} from 'services/web3/multicall/multicallFunctions'; + +export const useChainTokenSymbol = () => { + const { data: poolIds } = useChainPoolIds(); + return useQuery( + QueryKey.chainCoreSymbols(poolIds?.length), + () => fetchMulticallHelper(poolIds!, buildMulticallSymbol, true), + queryOptionsNoInterval(!!poolIds) + ); +}; diff --git a/src/queries/chain/useChainTradingEnabled.ts b/src/queries/chain/useChainTradingEnabled.ts new file mode 100644 index 000000000..33034eb54 --- /dev/null +++ b/src/queries/chain/useChainTradingEnabled.ts @@ -0,0 +1,17 @@ +import { useQuery } from 'react-query'; +import { QueryKey } from 'queries/queryKeyFactory'; +import { useChainPoolIds } from 'queries/chain/useChainPoolIds'; +import { queryOptionsStaleTimeLow } from 'queries/queryOptions'; +import { + buildMulticallTradingEnabled, + fetchMulticallHelper, +} from 'services/web3/multicall/multicallFunctions'; + +export const useChainTradingEnabled = () => { + const { data: poolIds } = useChainPoolIds(); + return useQuery( + QueryKey.chainCoreTradingEnabled(poolIds?.length), + () => fetchMulticallHelper(poolIds!, buildMulticallTradingEnabled), + queryOptionsStaleTimeLow(!!poolIds) + ); +}; diff --git a/src/queries/chain/useChainTradingFee.ts b/src/queries/chain/useChainTradingFee.ts new file mode 100644 index 000000000..f40497b92 --- /dev/null +++ b/src/queries/chain/useChainTradingFee.ts @@ -0,0 +1,17 @@ +import { useQuery } from 'react-query'; +import { QueryKey } from 'queries/queryKeyFactory'; +import { useChainPoolIds } from 'queries/chain/useChainPoolIds'; +import { queryOptionsStaleTimeLow } from 'queries/queryOptions'; +import { + buildMulticallTradingFee, + fetchMulticallHelper, +} from 'services/web3/multicall/multicallFunctions'; + +export const useChainTradingFee = () => { + const { data: poolIds } = useChainPoolIds(); + return useQuery( + QueryKey.chainCoreTradingFee(poolIds?.length), + () => fetchMulticallHelper(poolIds!, buildMulticallTradingFee), + queryOptionsStaleTimeLow(!!poolIds) + ); +}; diff --git a/src/queries/chain/useChainTradingLiquidity.ts b/src/queries/chain/useChainTradingLiquidity.ts new file mode 100644 index 000000000..22f94182c --- /dev/null +++ b/src/queries/chain/useChainTradingLiquidity.ts @@ -0,0 +1,22 @@ +import { useQuery } from 'react-query'; +import { QueryKey } from 'queries/queryKeyFactory'; +import { useChainPoolIds } from 'queries/chain/useChainPoolIds'; +import { queryOptionsStaleTimeLow } from 'queries/queryOptions'; +import { + buildMulticallTradingLiquidity, + fetchMulticallHelper, +} from 'services/web3/multicall/multicallFunctions'; +import { TradingLiquidityStructOutput } from 'services/web3/abis/types/BancorNetworkInfo'; + +export const useChainTradingLiquidity = () => { + const { data: poolIds } = useChainPoolIds(); + return useQuery( + QueryKey.chainCoreTradingLiquidity(poolIds?.length), + () => + fetchMulticallHelper( + poolIds!, + buildMulticallTradingLiquidity + ), + queryOptionsStaleTimeLow(!!poolIds) + ); +}; diff --git a/src/queries/queryKeyFactory.ts b/src/queries/queryKeyFactory.ts new file mode 100644 index 000000000..d15c8fc59 --- /dev/null +++ b/src/queries/queryKeyFactory.ts @@ -0,0 +1,45 @@ +export abstract class QueryKey { + static v3 = () => ['v3']; + static chain = () => [...this.v3(), 'chain']; + static chainCore = (key?: number | string) => [...this.chain(), 'pools', key]; + static chainCorePoolIds = () => [...this.chainCore('poolIds')]; + static chainCorePoolTokenIds = (key?: number) => [ + ...this.chainCore(key), + 'poolTokenIds', + ]; + static chainCoreSymbols = (key?: number) => [ + ...this.chainCore(key), + 'symbols', + ]; + static chainCoreDecimals = (key?: number) => [ + ...this.chainCore(key), + 'decimals', + ]; + static chainCoreName = (key?: number) => [...this.chainCore(key), 'name']; + static chainCoreTradingEnabled = (key?: number) => [ + ...this.chainCore(key), + 'tradingEnabled', + ]; + static chainCoreTradingLiquidity = (key?: number) => [ + ...this.chainCore(key), + 'tradingLiquidity', + ]; + static chainCoreDepositingEnabled = (key?: number) => [ + ...this.chainCore(key), + 'depositingEnabled', + ]; + static chainCoreStakedBalance = (key?: number) => [ + ...this.chainCore(key), + 'stakedBalance', + ]; + static chainCoreTradingFee = (key?: number) => [ + ...this.chainCore(key), + 'tradingFee', + ]; + static chainCoreLatestProgramId = (key?: number) => [ + ...this.chainCore(key), + 'latestProgramId', + ]; + static chainPools = () => [...this.chain(), 'pools']; + static chainPoolsByID = (key?: string) => [...this.chainPools(), key]; +} diff --git a/src/queries/queryOptions.ts b/src/queries/queryOptions.ts new file mode 100644 index 000000000..0a7622731 --- /dev/null +++ b/src/queries/queryOptions.ts @@ -0,0 +1,11 @@ +export const queryOptionsNoInterval = (enabled?: boolean) => ({ + enabled, + refetchInterval: 0, + staleTime: 6 * 60 * 60 * 1000, +}); + +export const queryOptionsStaleTimeLow = (enabled?: boolean) => ({ + enabled, + refetchInterval: 5 * 60 * 1000, + staleTime: 5 * 60 * 1000, +}); diff --git a/src/queries/usePoolsV3.ts b/src/queries/usePoolsV3.ts index 575efa9f4..ac1db8ba2 100644 --- a/src/queries/usePoolsV3.ts +++ b/src/queries/usePoolsV3.ts @@ -84,10 +84,6 @@ export const usePoolsV3 = () => { standardRewardsClaimed24h: apiPool.standardRewardsClaimed24h, standardRewardsProviderJoined: apiPool.standardRewardsProviderJoined, standardRewardsProviderLeft: apiPool.standardRewardsProviderLeft, - logoURI: - 'https://d1wmp5nysbq9xl.cloudfront.net/ethereum/tokens/' + - pool.poolDltId.toLowerCase() + - '.svg', apr24h: { tradingFees: tradingFeesApr24h, standardRewards: standardRewardsApr24H, diff --git a/src/queries/useV3ChainData.ts b/src/queries/useV3ChainData.ts index bf2c97952..9c321171d 100644 --- a/src/queries/useV3ChainData.ts +++ b/src/queries/useV3ChainData.ts @@ -1,5 +1,5 @@ import { useQuery } from 'react-query'; -import { MultiCall } from 'services/web3/multicall/multicall'; +import { fetchMulticall, MultiCall } from 'services/web3/multicall/multicall'; import { ContractsApi } from 'services/web3/v3/contractsApi'; import { ethToken } from 'services/web3/config'; import { BigNumber, utils } from 'ethers'; @@ -14,6 +14,13 @@ export interface PriceDictionaryV3 { tkn: string; } +export interface PoolApr { + tradingFees: number; + standardRewards: number; + autoCompounding: number; + total: number; +} + export interface PoolV3Chain { poolDltId: string; poolTokenDltId: string; @@ -22,78 +29,27 @@ export interface PoolV3Chain { decimals: number; tradingLiquidityBNT: PriceDictionaryV3; tradingLiquidityTKN: PriceDictionaryV3; - volume24h?: PriceDictionaryV3; - fees24h?: PriceDictionaryV3; stakedBalance: PriceDictionaryV3; - tradingFeePPM: string; + tradingFeePPM: number; tradingEnabled: boolean; depositingEnabled: boolean; - standardRewardsClaimed24h?: PriceDictionaryV3; - standardRewardsProviderJoined?: PriceDictionaryV3; - standardRewardsProviderLeft?: PriceDictionaryV3; - standardRewardsStaked?: PriceDictionaryV3; - volume7d?: PriceDictionaryV3; - fees7d?: PriceDictionaryV3; - apr24h?: { - tradingFees: number; - standardRewards: number; - autoCompounding: number; - total: number; - }; - apr7d?: { - tradingFees: number; - standardRewards: number; - autoCompounding: number; - total: number; - }; programs: RewardsProgramRaw[]; - latestProgram?: RewardsProgramRaw; logoURI: string; + latestProgram?: RewardsProgramRaw; tknBalance?: string; bnTknBalance?: string; + volume24h?: PriceDictionaryV3; + fees24h?: PriceDictionaryV3; + volume7d?: PriceDictionaryV3; + fees7d?: PriceDictionaryV3; + apr24h?: PoolApr; + apr7d?: PoolApr; + standardRewardsClaimed24h?: PriceDictionaryV3; + standardRewardsProviderJoined?: PriceDictionaryV3; + standardRewardsProviderLeft?: PriceDictionaryV3; + standardRewardsStaked?: PriceDictionaryV3; } -const fetchMulticall = async ( - calls: MultiCall[], - toUtf8String = false, - blockHeight?: number -) => { - try { - const encoded = calls.map((call) => ({ - target: call.contractAddress, - callData: call.interface.encodeFunctionData( - call.methodName, - call.methodParameters - ), - })); - - const encodedRes = await ContractsApi.Multicall.read.tryAggregate( - false, - encoded, - { - blockTag: blockHeight, - } - ); - - return encodedRes.map((call, i) => { - if (!call.success) { - console.log(calls[i]); - throw new Error('multicall failed'); - } - if (toUtf8String) { - return utils.toUtf8String(call.returnData).replace(/[^a-zA-Z0-9]/g, ''); - } - const res = calls[i].interface.decodeFunctionResult( - calls[i].methodName, - call.returnData - ); - return res[0]; - }); - } catch (error) { - throw error; - } -}; - const fetchEthData = async (): Promise => { const ethDataCalls: MultiCall[] = [ { @@ -138,14 +94,8 @@ const fetchEthData = async (): Promise => { methodName: 'latestProgramId', methodParameters: [ethToken], }, - { - contractAddress: ContractsApi.StandardRewards.contractAddress, - interface: ContractsApi.StandardRewards.read.interface, - methodName: 'latestProgramId', - methodParameters: [ethToken], - }, ]; - const res = await fetchMulticall(ethDataCalls); + const res = await fetchMulticall(ethDataCalls); return { poolDltId: ethToken, @@ -291,16 +241,16 @@ const fetchV3ChainData = async (): Promise => { ethData, programs, ] = await Promise.all([ - fetchMulticall(poolTokensCalls), - fetchMulticall(tokenDecimalsCalls), - fetchMulticall(tokenNamesCalls, true), - fetchMulticall(tokenSymbolCalls, true), - fetchMulticall(tradingEnabledCalls), - fetchMulticall(tradingLiquidityCalls), - fetchMulticall(depositingEnabledCalls), - fetchMulticall(stakedBalanceCalls), - fetchMulticall(tradingFeePPMCalls), - fetchMulticall(latestProgramIdCalls), + fetchMulticall(poolTokensCalls), + fetchMulticall(tokenDecimalsCalls), + fetchMulticall(tokenNamesCalls, true), + fetchMulticall(tokenSymbolCalls, true), + fetchMulticall(tradingEnabledCalls), + fetchMulticall(tradingLiquidityCalls), + fetchMulticall(depositingEnabledCalls), + fetchMulticall(stakedBalanceCalls), + fetchMulticall(tradingFeePPMCalls), + fetchMulticall(latestProgramIdCalls), fetchEthData(), fetchChainV3Programs(programIds), ]); @@ -331,7 +281,7 @@ const fetchV3ChainData = async (): Promise => { }, tradingFeePPM: tradingFeePPM[i], latestProgram: latestProgramIds[i] - ? latestProgramIds[i].toString() + ? programs.find((p) => p.pool === id) : undefined, programs: programs.filter((p) => p.pool === id), logoURI: @@ -343,6 +293,45 @@ const fetchV3ChainData = async (): Promise => { return data; }; +const fetchV3ChainPoolTokens = async ( + poolIds: string[] +): Promise> => { + const calls: MultiCall[] = poolIds.map((id) => ({ + contractAddress: ContractsApi.BancorNetworkInfo.contractAddress, + interface: ContractsApi.BancorNetworkInfo.read.interface, + methodName: 'poolToken', + methodParameters: [id], + })); + + const data = await fetchMulticall(calls); + + return new Map(data.map((id, i) => [poolIds[i], id])); +}; + +export const useV3ChainPoolIds = () => { + return useQuery( + ['chain', 'v3', 'poolIds'], + () => ContractsApi.BancorNetwork.read.liquidityPools(), + { + refetchInterval: 144 * 1000, + staleTime: 88 * 1000, + } + ); +}; + +export const useV3ChainPoolTokenIds = () => { + const { data: poolIds } = useV3ChainPoolIds(); + return useQuery( + ['chain', 'v3', 'poolTokenIds'], + () => fetchV3ChainPoolTokens(poolIds!), + { + enabled: poolIds !== undefined, + refetchInterval: 144 * 1000, + staleTime: 88 * 1000, + } + ); +}; + export const useV3ChainData = () => { return useQuery(['chain', 'v3', 'pools'], fetchV3ChainData, { refetchInterval: 144 * 1000, diff --git a/src/services/web3/multicall/multicall.ts b/src/services/web3/multicall/multicall.ts index ed88b8818..c9f6559aa 100644 --- a/src/services/web3/multicall/multicall.ts +++ b/src/services/web3/multicall/multicall.ts @@ -1,5 +1,6 @@ import { Interface } from '@ethersproject/abi'; import { ContractsApi } from 'services/web3/v3/contractsApi'; +import { utils } from 'ethers'; export interface MultiCall { contractAddress: string; @@ -37,3 +38,44 @@ export const multicall = async (calls: MultiCall[], blockHeight?: number) => { console.error(error); } }; + +export const fetchMulticall = async ( + calls: MultiCall[], + toUtf8String = false, + blockHeight?: number +): Promise => { + try { + const encoded = calls.map((call) => ({ + target: call.contractAddress, + callData: call.interface.encodeFunctionData( + call.methodName, + call.methodParameters + ), + })); + + const encodedRes = await ContractsApi.Multicall.read.tryAggregate( + false, + encoded, + { + blockTag: blockHeight, + } + ); + + return encodedRes.map((call, i) => { + if (!call.success) { + console.log(calls[i]); + throw new Error('multicall failed'); + } + if (toUtf8String) { + return utils.toUtf8String(call.returnData).replace(/[^a-zA-Z0-9]/g, ''); + } + const res = calls[i].interface.decodeFunctionResult( + calls[i].methodName, + call.returnData + ); + return res[0]; + }); + } catch (error) { + throw error; + } +}; diff --git a/src/services/web3/multicall/multicallFunctions.ts b/src/services/web3/multicall/multicallFunctions.ts new file mode 100644 index 000000000..4acf4597e --- /dev/null +++ b/src/services/web3/multicall/multicallFunctions.ts @@ -0,0 +1,84 @@ +import { fetchMulticall, MultiCall } from 'services/web3/multicall/multicall'; +import { ContractsApi } from 'services/web3/v3/contractsApi'; + +export const fetchMulticallHelper = async ( + poolIds: string[], + buildMulticall: (id: string) => MultiCall, + toUtf8String?: boolean +): Promise> => { + const calls: MultiCall[] = poolIds.map((id) => buildMulticall(id)); + + const data = await fetchMulticall(calls, toUtf8String); + + return new Map(data.map((id, i) => [poolIds[i], id])); +}; + +export const buildMulticallSymbol = (id: string) => ({ + contractAddress: id, + interface: ContractsApi.Token(id).read.interface, + methodName: 'symbol', + methodParameters: [], +}); + +export const buildMulticallName = (id: string) => ({ + contractAddress: id, + interface: ContractsApi.Token(id).read.interface, + methodName: 'name', + methodParameters: [], +}); + +export const buildMulticallDecimal = (id: string) => ({ + contractAddress: id, + interface: ContractsApi.Token(id).read.interface, + methodName: 'decimals', + methodParameters: [], +}); + +export const buildMulticallPoolToken = (id: string) => ({ + contractAddress: ContractsApi.BancorNetworkInfo.contractAddress, + interface: ContractsApi.BancorNetworkInfo.read.interface, + methodName: 'poolToken', + methodParameters: [id], +}); + +export const buildMulticallTradingEnabled = (id: string) => ({ + contractAddress: ContractsApi.BancorNetworkInfo.contractAddress, + interface: ContractsApi.BancorNetworkInfo.read.interface, + methodName: 'tradingEnabled', + methodParameters: [id], +}); + +export const buildMulticallTradingLiquidity = (id: string) => ({ + contractAddress: ContractsApi.BancorNetworkInfo.contractAddress, + interface: ContractsApi.BancorNetworkInfo.read.interface, + methodName: 'tradingLiquidity', + methodParameters: [id], +}); + +export const buildMulticallDepositingEnabled = (id: string) => ({ + contractAddress: ContractsApi.BancorNetworkInfo.contractAddress, + interface: ContractsApi.BancorNetworkInfo.read.interface, + methodName: 'depositingEnabled', + methodParameters: [id], +}); + +export const buildMulticallStakedBalance = (id: string) => ({ + contractAddress: ContractsApi.BancorNetworkInfo.contractAddress, + interface: ContractsApi.BancorNetworkInfo.read.interface, + methodName: 'stakedBalance', + methodParameters: [id], +}); + +export const buildMulticallTradingFee = (id: string) => ({ + contractAddress: ContractsApi.BancorNetworkInfo.contractAddress, + interface: ContractsApi.BancorNetworkInfo.read.interface, + methodName: 'tradingFeePPM', + methodParameters: [id], +}); + +export const buildMulticallLatestProgramId = (id: string) => ({ + contractAddress: ContractsApi.StandardRewards.contractAddress, + interface: ContractsApi.StandardRewards.read.interface, + methodName: 'latestProgramId', + methodParameters: [id], +}); From 97b579b5c017c7a2675157028adbccc0c7298c39 Mon Sep 17 00:00:00 2001 From: Jan Langheimer Date: Mon, 11 Jul 2022 22:08:57 +0200 Subject: [PATCH 08/36] introduce new api for getting pool data --- package.json | 3 +- src/elements/admin/AdminQueryTest.tsx | 13 ++- .../earn/pools/poolsTable/PoolsTable.tsx | 24 ++--- src/queries/api/useApiApr.ts | 90 +++++++++++++++++++ src/queries/api/useApiFees.ts | 31 +++++++ src/queries/api/useApiPools.ts | 27 ++++++ src/queries/chain/useChainPoolByID.ts | 4 +- src/queries/chain/useChainPoolTokenIds.ts | 14 ++- src/queries/chain/useChainPools.ts | 55 ++++++------ src/queries/chain/useChainPrograms.ts | 27 ++++++ src/queries/chain/useChainTokenDecimals.ts | 14 ++- src/queries/chain/useChainTokenSymbol.ts | 14 ++- src/queries/chain/useChainTradingEnabled.ts | 14 ++- src/queries/chain/useChainTradingFee.ts | 4 +- src/queries/chain/useChainTradingLiquidity.ts | 35 +++++++- src/queries/chain/usePoolPick.ts | 85 ++++++++++++++++++ src/queries/queryKeyFactory.ts | 8 ++ src/queries/useApiPoolsV3.ts | 10 ++- src/queries/useV3ChainData.ts | 74 ++++++++------- yarn.lock | 5 ++ 20 files changed, 455 insertions(+), 96 deletions(-) create mode 100644 src/queries/api/useApiApr.ts create mode 100644 src/queries/api/useApiFees.ts create mode 100644 src/queries/api/useApiPools.ts create mode 100644 src/queries/chain/useChainPrograms.ts create mode 100644 src/queries/chain/usePoolPick.ts diff --git a/package.json b/package.json index 01a7ef9b3..11f3aaef9 100644 --- a/package.json +++ b/package.json @@ -51,7 +51,8 @@ "source-map-explorer": "^2.5.2", "swiper": "^7.4.1", "use-async-effect": "^2.2.3", - "web-vitals": "^1.0.1" + "web-vitals": "^1.0.1", + "zod": "^3.17.3" }, "devDependencies": { "@faker-js/faker": "^6.0.0-alpha.5", diff --git a/src/elements/admin/AdminQueryTest.tsx b/src/elements/admin/AdminQueryTest.tsx index 7d4f740c7..023b735e8 100644 --- a/src/elements/admin/AdminQueryTest.tsx +++ b/src/elements/admin/AdminQueryTest.tsx @@ -1,18 +1,17 @@ -import { useChainPools } from 'queries/chain/useChainPools'; +import { useChainPoolIds } from 'queries/chain/useChainPoolIds'; +import { usePoolPick } from 'queries/chain/usePoolPick'; export const AdminQueryTest = () => { - const { data: chainData, isLoading, isFetching } = useChainPools(); + const { data: poolIds, isLoading, isFetching } = useChainPoolIds(); + + const test = usePoolPick(poolIds ? poolIds[0] : '', ['poolDltId', 'symbol']); return (
admin query test
{isFetching && 'fetching...'} - {isLoading ? ( - 'loading...' - ) : ( -
{JSON.stringify(chainData, null, 2)}
- )} + {isLoading ? 'loading...' :
{JSON.stringify(test, null, 2)}
}
); diff --git a/src/elements/earn/pools/poolsTable/PoolsTable.tsx b/src/elements/earn/pools/poolsTable/PoolsTable.tsx index 365ff40e1..d7baab431 100644 --- a/src/elements/earn/pools/poolsTable/PoolsTable.tsx +++ b/src/elements/earn/pools/poolsTable/PoolsTable.tsx @@ -46,9 +46,9 @@ export const PoolsTable = ({ ? pools.filter( (p) => p.symbol.toLowerCase().includes(search.toLowerCase()) && - (lowVolume || Number(p.volume24h?.usd) > 5000) && - (lowLiquidity || Number(p.tradingLiquidityTKN.usd) > 50000) && - (lowEarnRate || (p.apr7d?.total ?? 0) > 0.15) + (lowVolume || Number(p.volume?.volume24h?.usd) > 5000) && + (lowLiquidity || Number(p.tradingLiquidity.TKN.usd) > 50000) && + (lowEarnRate || (p.apr?.apr7d?.total ?? 0) > 0.15) ) : []; }, [pools, search, lowVolume, lowLiquidity, lowEarnRate]); @@ -66,23 +66,23 @@ export const PoolsTable = ({
)} - {row.volume7d?.usd && ( + {row.volume?.volume7d?.usd && (
Volume 7d
- {toBigNumber(row.volume7d.usd).isZero() + {toBigNumber(row.volume.volume7d.usd).isZero() ? 'New' - : prettifyNumber(row.volume7d.usd, true)} + : prettifyNumber(row.volume.volume7d.usd, true)}
)} - {row.fees7d?.usd && ( + {row.fees?.fees7d.usd && (
Fees 7d
- {toBigNumber(row.fees7d.usd).isZero() + {toBigNumber(row.fees.fees7d.usd).isZero() ? 'New' - : prettifyNumber(row.fees7d.usd, true)} + : prettifyNumber(row.fees.fees7d.usd, true)}
)} @@ -132,14 +132,14 @@ export const PoolsTable = ({ { id: 'apr', Header: 'Earn', - accessor: 'apr7d', + accessor: 'apr', Cell: (cellData) => (
{cellData.value - ? toBigNumber(cellData.value.total).isZero() && + ? toBigNumber(cellData.value.apr7d.total).isZero() && !cellData.row.original.tradingEnabled ? 'New' - : `${cellData.value.total.toFixed(2)}%` + : `${cellData.value.apr7d.total.toFixed(2)}%` : 'N/A'} {} diff --git a/src/queries/api/useApiApr.ts b/src/queries/api/useApiApr.ts new file mode 100644 index 000000000..538f22e25 --- /dev/null +++ b/src/queries/api/useApiApr.ts @@ -0,0 +1,90 @@ +import { useChainPrograms } from 'queries/chain/useChainPrograms'; +import { useMemo } from 'react'; +import { toBigNumber } from 'utils/helperFunctions'; +import { standardsRewardsAPR } from 'services/observables/pools'; +import { calcApr } from 'utils/formulas'; +import { useChainPoolIds } from 'queries/chain/useChainPoolIds'; +import { useApiPools } from 'queries/api/useApiPools'; + +interface Props { + enabled?: boolean; +} + +export const useApiApr = ({ enabled = true }: Props = {}) => { + const { data: poolIds } = useChainPoolIds(); + const { getApiPoolByID } = useApiPools({ enabled }); + const { data: programsMap } = useChainPrograms({ enabled }); + + const data = useMemo( + () => + new Map( + poolIds?.map((id) => { + const apiPool = getApiPoolByID(id); + const programs = programsMap?.get(id); + + if (!apiPool) { + return [id, undefined]; + } + // FIXES STAKED BALANCE = 0 WHEN TRADING ENABLED = FALSE + const stakedBalance = { ...apiPool.stakedBalance }; + if ( + apiPool.tradingEnabled === false && + toBigNumber(stakedBalance.usd).isZero() + ) { + stakedBalance.usd = toBigNumber(apiPool.stakedBalance.tkn) + // TODO - add apiToken.rate + .times('0') + .toString(); + } + + // Calculate APR + const standardRewardsApr24H = standardsRewardsAPR(apiPool, programs); + const standardRewardsApr7d = standardsRewardsAPR(apiPool, programs); + + const tradingFeesApr24h = calcApr( + apiPool.fees24h.usd, + stakedBalance.usd + ); + const tradingFeesApr7d = calcApr( + apiPool.fees7d.usd, + stakedBalance.usd, + true + ); + + // TODO - add values once available + const autoCompoundingApr24H = 0; + const autoCompoundingApr7d = 0; + + const totalApr24H = toBigNumber(tradingFeesApr24h) + .plus(standardRewardsApr24H) + .plus(autoCompoundingApr24H) + .toNumber(); + + const totalApr7d = toBigNumber(tradingFeesApr7d) + .plus(autoCompoundingApr7d) + .plus(standardRewardsApr7d) + .toNumber(); + const apr = { + apr24h: { + tradingFees: tradingFeesApr24h, + standardRewards: standardRewardsApr24H, + autoCompounding: autoCompoundingApr24H, + total: totalApr24H, + }, + apr7d: { + tradingFees: tradingFeesApr7d, + standardRewards: standardRewardsApr7d, + autoCompounding: autoCompoundingApr7d, + total: totalApr7d, + }, + }; + return [id, { ...apr }]; + }) + ), + [getApiPoolByID, poolIds, programsMap] + ); + + const getAprByID = (id: string) => data.get(id); + + return { data, getAprByID }; +}; diff --git a/src/queries/api/useApiFees.ts b/src/queries/api/useApiFees.ts new file mode 100644 index 000000000..ea43c9e66 --- /dev/null +++ b/src/queries/api/useApiFees.ts @@ -0,0 +1,31 @@ +import { useMemo } from 'react'; +import { useChainPoolIds } from 'queries/chain/useChainPoolIds'; +import { useApiPools } from 'queries/api/useApiPools'; + +interface Props { + enabled?: boolean; +} + +export const useApiFees = ({ enabled = true }: Props = {}) => { + const { data: poolIds } = useChainPoolIds(); + const { getApiPoolByID } = useApiPools({ enabled }); + + const data = useMemo( + () => + new Map( + poolIds?.map((id) => { + const apiPool = getApiPoolByID(id); + + if (!apiPool) { + return [id, undefined]; + } + return [id, { fees7d: apiPool.fees7d, fees24h: apiPool.fees24h }]; + }) + ), + [getApiPoolByID, poolIds] + ); + + const getFeeByID = (id: string) => data.get(id); + + return { data, getFeeByID }; +}; diff --git a/src/queries/api/useApiPools.ts b/src/queries/api/useApiPools.ts new file mode 100644 index 000000000..4682b922d --- /dev/null +++ b/src/queries/api/useApiPools.ts @@ -0,0 +1,27 @@ +import { useQuery } from 'react-query'; +import { BancorApi } from 'services/api/bancorApi/bancorApi'; +import { QueryKey } from 'queries/queryKeyFactory'; + +interface Props { + enabled?: boolean; +} + +export const useApiPools = ({ enabled = true }: Props = {}) => { + const queryKey = QueryKey.apiPools(); + const query = useQuery( + queryKey, + async () => { + const pools = await BancorApi.v3.getPools(); + return new Map(pools.map((p) => [p.poolDltId, p])); + }, + { + enabled, + useErrorBoundary: true, + onError: (err) => console.error('query failed', queryKey, err), + } + ); + + const getApiPoolByID = (id: string) => query.data?.get(id); + + return { ...query, getApiPoolByID }; +}; diff --git a/src/queries/chain/useChainPoolByID.ts b/src/queries/chain/useChainPoolByID.ts index 25babf64a..6438a83b2 100644 --- a/src/queries/chain/useChainPoolByID.ts +++ b/src/queries/chain/useChainPoolByID.ts @@ -3,7 +3,7 @@ import { useChainPools } from 'queries/chain/useChainPools'; export const useChainPoolByID = (id: string) => { const pools = useChainPools(); - const data = pools.data?.find((pool) => pool.poolDltId === id); + //const data = pools.data?.find((pool) => pool.poolDltId === id); - return { ...pools, data }; + //return { ...pools, data }; }; diff --git a/src/queries/chain/useChainPoolTokenIds.ts b/src/queries/chain/useChainPoolTokenIds.ts index 1ee17d142..4b20cfc96 100644 --- a/src/queries/chain/useChainPoolTokenIds.ts +++ b/src/queries/chain/useChainPoolTokenIds.ts @@ -7,11 +7,19 @@ import { fetchMulticallHelper, } from 'services/web3/multicall/multicallFunctions'; -export const useChainPoolTokenIds = () => { +interface Props { + enabled?: boolean; +} + +export const useChainPoolTokenIds = ({ enabled = true }: Props = {}) => { const { data: poolIds } = useChainPoolIds(); - return useQuery( + const query = useQuery( QueryKey.chainCorePoolTokenIds(poolIds?.length), () => fetchMulticallHelper(poolIds!, buildMulticallPoolToken), - queryOptionsNoInterval(!!poolIds) + queryOptionsNoInterval(!!poolIds && enabled) ); + + const getPoolTokenByID = (id: string) => query.data?.get(id); + + return { ...query, getPoolTokenByID }; }; diff --git a/src/queries/chain/useChainPools.ts b/src/queries/chain/useChainPools.ts index f7f348a5e..0c6b0d947 100644 --- a/src/queries/chain/useChainPools.ts +++ b/src/queries/chain/useChainPools.ts @@ -59,7 +59,7 @@ export const useChainPools = () => { tradingFee.error || poolTokens.error; - const data = (): PoolV3Chain[] | undefined => { + const _buildPool = (id: string): PoolV3Chain | undefined => { if ( !poolIds.data || !symbols.data || @@ -75,43 +75,46 @@ export const useChainPools = () => { return undefined; } - return poolIds.data.map((id) => { - const tokenDecimals = decimals.data.get(id)!; - const tokenTradingLiquidity = tradingLiquidity.data.get(id)!; + const tokenDecimals = decimals.data.get(id)!; + const tokenTradingLiquidity = tradingLiquidity.data.get(id)!; - return { - poolDltId: id, - poolTokenDltId: poolTokens.data.get(id)!, - symbol: symbols.data.get(id)!, - decimals: tokenDecimals, - name: name.data.get(id)!, - tradingFeePPM: tradingFee.data.get(id)!, - tradingEnabled: tradingEnabled.data.get(id)!, - depositingEnabled: depositingEnabled.data.get(id)!, - tradingLiquidityBNT: { + const pool: PoolV3Chain = { + poolDltId: id, + poolTokenDltId: poolTokens.data.get(id)!, + symbol: symbols.data.get(id)!, + decimals: tokenDecimals, + name: name.data.get(id)!, + tradingFeePPM: tradingFee.data.get(id)!, + tradingEnabled: tradingEnabled.data.get(id)!, + depositingEnabled: depositingEnabled.data.get(id)!, + tradingLiquidity: { + BNT: { bnt: utils.formatUnits( tokenTradingLiquidity.bntTradingLiquidity, tokenDecimals ), tkn: utils.formatUnits(tokenTradingLiquidity.bntTradingLiquidity, 18), }, - tradingLiquidityTKN: { + TKN: { tkn: utils.formatUnits( tokenTradingLiquidity.baseTokenTradingLiquidity, tokenDecimals ), }, - stakedBalance: { - tkn: utils.formatUnits(stakedBalance.data.get(id)!, tokenDecimals), - }, - programs: [], - logoURI: - 'https://d1wmp5nysbq9xl.cloudfront.net/ethereum/tokens/' + - id.toLowerCase() + - '.svg', - }; - }); + }, + stakedBalance: { + tkn: utils.formatUnits(stakedBalance.data.get(id)!, tokenDecimals), + }, + programs: [], + logoURI: + 'https://d1wmp5nysbq9xl.cloudfront.net/ethereum/tokens/' + + id.toLowerCase() + + '.svg', + }; + return pool; }; - return { data: data(), isLoading, error, isFetching }; + const getPoolByID = (id: string) => _buildPool(id); + + return { isLoading, error, isFetching, getPoolByID }; }; diff --git a/src/queries/chain/useChainPrograms.ts b/src/queries/chain/useChainPrograms.ts new file mode 100644 index 000000000..d8265f616 --- /dev/null +++ b/src/queries/chain/useChainPrograms.ts @@ -0,0 +1,27 @@ +import { useQuery } from 'react-query'; +import { QueryKey } from 'queries/queryKeyFactory'; +import { useChainPoolIds } from 'queries/chain/useChainPoolIds'; +import { queryOptionsNoInterval } from 'queries/queryOptions'; +import { fetchAllStandardRewards } from 'services/web3/v3/portfolio/standardStaking'; + +interface Props { + enabled?: boolean; +} + +export const useChainPrograms = ({ enabled = true }: Props = {}) => { + const { data: poolIds } = useChainPoolIds(); + const query = useQuery( + QueryKey.chainCorePrograms(poolIds?.length), + async () => { + const programs = await fetchAllStandardRewards(); + return new Map( + poolIds?.map((id) => [id, programs.filter((p) => p.pool === id)]) + ); + }, + queryOptionsNoInterval(!!poolIds && enabled) + ); + + const getProgramsByID = (id: string) => query.data?.get(id); + + return { ...query, getProgramsByID }; +}; diff --git a/src/queries/chain/useChainTokenDecimals.ts b/src/queries/chain/useChainTokenDecimals.ts index 4934c5632..5941d5910 100644 --- a/src/queries/chain/useChainTokenDecimals.ts +++ b/src/queries/chain/useChainTokenDecimals.ts @@ -7,11 +7,19 @@ import { } from 'services/web3/multicall/multicallFunctions'; import { queryOptionsNoInterval } from 'queries/queryOptions'; -export const useChainTokenDecimals = () => { +interface Props { + enabled?: boolean; +} + +export const useChainTokenDecimals = ({ enabled = true }: Props = {}) => { const { data: poolIds } = useChainPoolIds(); - return useQuery( + const query = useQuery( QueryKey.chainCoreDecimals(poolIds?.length), () => fetchMulticallHelper(poolIds!, buildMulticallDecimal), - queryOptionsNoInterval(!!poolIds) + queryOptionsNoInterval(!!poolIds && enabled) ); + + const getDecimalsByID = (id: string) => query.data?.get(id); + + return { ...query, getDecimalsByID }; }; diff --git a/src/queries/chain/useChainTokenSymbol.ts b/src/queries/chain/useChainTokenSymbol.ts index 77ec2af30..0a10bf171 100644 --- a/src/queries/chain/useChainTokenSymbol.ts +++ b/src/queries/chain/useChainTokenSymbol.ts @@ -7,11 +7,19 @@ import { fetchMulticallHelper, } from 'services/web3/multicall/multicallFunctions'; -export const useChainTokenSymbol = () => { +interface Props { + enabled?: boolean; +} + +export const useChainTokenSymbol = ({ enabled = true }: Props = {}) => { const { data: poolIds } = useChainPoolIds(); - return useQuery( + const query = useQuery( QueryKey.chainCoreSymbols(poolIds?.length), () => fetchMulticallHelper(poolIds!, buildMulticallSymbol, true), - queryOptionsNoInterval(!!poolIds) + queryOptionsNoInterval(!!poolIds && enabled) ); + + const getSymbolByID = (id: string) => query.data?.get(id); + + return { ...query, getSymbolByID }; }; diff --git a/src/queries/chain/useChainTradingEnabled.ts b/src/queries/chain/useChainTradingEnabled.ts index 33034eb54..40e1d3f9b 100644 --- a/src/queries/chain/useChainTradingEnabled.ts +++ b/src/queries/chain/useChainTradingEnabled.ts @@ -7,11 +7,19 @@ import { fetchMulticallHelper, } from 'services/web3/multicall/multicallFunctions'; -export const useChainTradingEnabled = () => { +interface Props { + enabled?: boolean; +} + +export const useChainTradingEnabled = ({ enabled = true }: Props = {}) => { const { data: poolIds } = useChainPoolIds(); - return useQuery( + const query = useQuery( QueryKey.chainCoreTradingEnabled(poolIds?.length), () => fetchMulticallHelper(poolIds!, buildMulticallTradingEnabled), - queryOptionsStaleTimeLow(!!poolIds) + queryOptionsStaleTimeLow(!!poolIds && enabled) ); + + const getTradingEnabledByID = (id: string) => query.data?.get(id); + + return { ...query, getTradingEnabledByID }; }; diff --git a/src/queries/chain/useChainTradingFee.ts b/src/queries/chain/useChainTradingFee.ts index f40497b92..c2bee95e0 100644 --- a/src/queries/chain/useChainTradingFee.ts +++ b/src/queries/chain/useChainTradingFee.ts @@ -12,6 +12,8 @@ export const useChainTradingFee = () => { return useQuery( QueryKey.chainCoreTradingFee(poolIds?.length), () => fetchMulticallHelper(poolIds!, buildMulticallTradingFee), - queryOptionsStaleTimeLow(!!poolIds) + { + ...queryOptionsStaleTimeLow(!!poolIds), + } ); }; diff --git a/src/queries/chain/useChainTradingLiquidity.ts b/src/queries/chain/useChainTradingLiquidity.ts index 22f94182c..fd8ada08c 100644 --- a/src/queries/chain/useChainTradingLiquidity.ts +++ b/src/queries/chain/useChainTradingLiquidity.ts @@ -7,16 +7,45 @@ import { fetchMulticallHelper, } from 'services/web3/multicall/multicallFunctions'; import { TradingLiquidityStructOutput } from 'services/web3/abis/types/BancorNetworkInfo'; +import { useChainTokenDecimals } from 'queries/chain/useChainTokenDecimals'; +import { utils } from 'ethers'; -export const useChainTradingLiquidity = () => { +interface Props { + enabled?: boolean; +} + +export const useChainTradingLiquidity = ({ enabled = true }: Props = {}) => { const { data: poolIds } = useChainPoolIds(); - return useQuery( + const { data: decimals } = useChainTokenDecimals({ enabled }); + + const query = useQuery( QueryKey.chainCoreTradingLiquidity(poolIds?.length), () => fetchMulticallHelper( poolIds!, buildMulticallTradingLiquidity ), - queryOptionsStaleTimeLow(!!poolIds) + queryOptionsStaleTimeLow(!!poolIds && enabled) ); + + const getTradingLiquidityByID = (id: string) => { + const dec = decimals?.get(id); + const liq = query.data?.get(id); + if (!liq || !dec) { + // TODO error handling + return undefined; + } + + return { + BNT: { + bnt: utils.formatUnits(liq.bntTradingLiquidity, dec), + tkn: utils.formatUnits(liq.bntTradingLiquidity, 18), + }, + TKN: { + tkn: utils.formatUnits(liq.baseTokenTradingLiquidity, dec), + }, + }; + }; + + return { ...query, getTradingLiquidityByID }; }; diff --git a/src/queries/chain/usePoolPick.ts b/src/queries/chain/usePoolPick.ts new file mode 100644 index 000000000..1a1de86db --- /dev/null +++ b/src/queries/chain/usePoolPick.ts @@ -0,0 +1,85 @@ +import { PoolV3Chain } from 'queries/useV3ChainData'; +import { useChainTokenSymbol } from 'queries/chain/useChainTokenSymbol'; +import { useChainTokenDecimals } from 'queries/chain/useChainTokenDecimals'; +import { useChainPoolTokenIds } from 'queries/chain/useChainPoolTokenIds'; +import { useChainPrograms } from 'queries/chain/useChainPrograms'; +import { useChainTradingEnabled } from 'queries/chain/useChainTradingEnabled'; +import { useApiApr } from 'queries/api/useApiApr'; +import { useChainTradingLiquidity } from 'queries/chain/useChainTradingLiquidity'; +import { useApiFees } from 'queries/api/useApiFees'; + +type Pool = Pick< + PoolV3Chain, + | 'symbol' + | 'decimals' + | 'poolTokenDltId' + | 'programs' + | 'tradingEnabled' + | 'poolDltId' + | 'apr' + | 'tradingLiquidity' + | 'fees' +>; + +type PoolKey = keyof Pool; +type Fetchers = { + [key in PoolKey]: (id: string) => Pool[key] | undefined; +}; + +const useFetchers = (select: PoolKey[]): Fetchers => { + const set = new Set(select.map((key) => key)); + + const { getSymbolByID } = useChainTokenSymbol({ + enabled: set.has('symbol'), + }); + + const { getDecimalsByID } = useChainTokenDecimals({ + enabled: set.has('decimals'), + }); + + const { getPoolTokenByID } = useChainPoolTokenIds({ + enabled: set.has('poolTokenDltId'), + }); + + const { getProgramsByID } = useChainPrograms({ + enabled: set.has('programs'), + }); + + const { getTradingEnabledByID } = useChainTradingEnabled({ + enabled: set.has('tradingEnabled'), + }); + + const { getTradingLiquidityByID } = useChainTradingLiquidity({ + enabled: set.has('tradingLiquidity'), + }); + + const { getFeeByID } = useApiFees({ + enabled: set.has('fees'), + }); + + const { getAprByID } = useApiApr({ + enabled: set.has('apr'), + }); + + return { + poolDltId: (id) => id, + symbol: getSymbolByID, + decimals: getDecimalsByID, + poolTokenDltId: getPoolTokenByID, + programs: getProgramsByID, + tradingEnabled: getTradingEnabledByID, + apr: getAprByID, + tradingLiquidity: getTradingLiquidityByID, + fees: getFeeByID, + }; +}; + +export const usePoolPick = (id: string, select: T) => { + const fetchers = useFetchers(select); + + return select.reduce((res, key) => { + // @ts-ignore + res[key] = fetchers[key](id); + return res; + }, {}) as Pick; +}; diff --git a/src/queries/queryKeyFactory.ts b/src/queries/queryKeyFactory.ts index d15c8fc59..714b73309 100644 --- a/src/queries/queryKeyFactory.ts +++ b/src/queries/queryKeyFactory.ts @@ -40,6 +40,14 @@ export abstract class QueryKey { ...this.chainCore(key), 'latestProgramId', ]; + static chainCorePrograms = (key?: number) => [ + ...this.chainCore(key), + 'programs', + ]; static chainPools = () => [...this.chain(), 'pools']; static chainPoolsByID = (key?: string) => [...this.chainPools(), key]; + + static api = () => [...this.v3(), 'api']; + static apiPools = () => [...this.api(), 'pools']; + static apiFees = () => [...this.api(), 'fees']; } diff --git a/src/queries/useApiPoolsV3.ts b/src/queries/useApiPoolsV3.ts index b595550d0..f998f840f 100644 --- a/src/queries/useApiPoolsV3.ts +++ b/src/queries/useApiPoolsV3.ts @@ -1,10 +1,16 @@ import { useQuery } from 'react-query'; import { BancorApi } from 'services/api/bancorApi/bancorApi'; import { APIPoolV3 } from 'services/api/bancorApi/bancorApi.types'; +import { QueryKey } from 'queries/queryKeyFactory'; -export const useApiPoolsV3 = () => { - const queryKey = ['api', 'v3', 'pools']; +interface Props { + enabled?: boolean; +} + +export const useApiPoolsV3 = ({ enabled = true }: Props = {}) => { + const queryKey = QueryKey.apiPools(); return useQuery(queryKey, BancorApi.v3.getPools, { + enabled, useErrorBoundary: true, onError: (err) => console.error('query failed', queryKey, err), }); diff --git a/src/queries/useV3ChainData.ts b/src/queries/useV3ChainData.ts index 9c321171d..e0d5bd3cb 100644 --- a/src/queries/useV3ChainData.ts +++ b/src/queries/useV3ChainData.ts @@ -27,8 +27,10 @@ export interface PoolV3Chain { name: string; symbol: string; decimals: number; - tradingLiquidityBNT: PriceDictionaryV3; - tradingLiquidityTKN: PriceDictionaryV3; + tradingLiquidity: { + BNT: PriceDictionaryV3; + TKN: PriceDictionaryV3; + }; stakedBalance: PriceDictionaryV3; tradingFeePPM: number; tradingEnabled: boolean; @@ -38,16 +40,24 @@ export interface PoolV3Chain { latestProgram?: RewardsProgramRaw; tknBalance?: string; bnTknBalance?: string; - volume24h?: PriceDictionaryV3; - fees24h?: PriceDictionaryV3; - volume7d?: PriceDictionaryV3; - fees7d?: PriceDictionaryV3; - apr24h?: PoolApr; - apr7d?: PoolApr; - standardRewardsClaimed24h?: PriceDictionaryV3; - standardRewardsProviderJoined?: PriceDictionaryV3; - standardRewardsProviderLeft?: PriceDictionaryV3; - standardRewardsStaked?: PriceDictionaryV3; + volume?: { + volume7d: PriceDictionaryV3; + volume24h: PriceDictionaryV3; + }; + fees?: { + fees7d: PriceDictionaryV3; + fees24h: PriceDictionaryV3; + }; + apr?: { + apr24h: PoolApr; + apr7d: PoolApr; + }; + standardRewards?: { + claimed24h: PriceDictionaryV3; + providerJoined: PriceDictionaryV3; + providerLeft: PriceDictionaryV3; + staked: PriceDictionaryV3; + }; } const fetchEthData = async (): Promise => { @@ -104,12 +114,14 @@ const fetchEthData = async (): Promise => { poolTokenDltId: res[0], decimals: 18, tradingEnabled: res[2], - tradingLiquidityBNT: { - bnt: utils.formatUnits(res[1].bntTradingLiquidity, 18), - tkn: utils.formatUnits(res[1].bntTradingLiquidity, 18), - }, - tradingLiquidityTKN: { - tkn: utils.formatUnits(res[1].baseTokenTradingLiquidity, 18), + tradingLiquidity: { + BNT: { + bnt: utils.formatUnits(res[1].bntTradingLiquidity, 18), + tkn: utils.formatUnits(res[1].bntTradingLiquidity, 18), + }, + TKN: { + tkn: utils.formatUnits(res[1].baseTokenTradingLiquidity, 18), + }, }, depositingEnabled: res[3], stakedBalance: { tkn: utils.formatUnits(res[4], 18) }, @@ -262,18 +274,20 @@ const fetchV3ChainData = async (): Promise => { poolTokenDltId: poolTokens[i], decimals: tokenDecimals[i], tradingEnabled: tradingEnabled[i], - tradingLiquidityBNT: { - bnt: utils.formatUnits( - tradingLiquidity[i].baseTokenTradingLiquidity, - tokenDecimals[i] - ), - tkn: utils.formatUnits(tradingLiquidity[i].bntTradingLiquidity, 18), - }, - tradingLiquidityTKN: { - tkn: utils.formatUnits( - tradingLiquidity[i].baseTokenTradingLiquidity, - tokenDecimals[i] - ), + tradingLiquidity: { + BNT: { + bnt: utils.formatUnits( + tradingLiquidity[i].baseTokenTradingLiquidity, + tokenDecimals[i] + ), + tkn: utils.formatUnits(tradingLiquidity[i].bntTradingLiquidity, 18), + }, + TKN: { + tkn: utils.formatUnits( + tradingLiquidity[i].baseTokenTradingLiquidity, + tokenDecimals[i] + ), + }, }, depositingEnabled: depositingEnabled[i], stakedBalance: { diff --git a/yarn.lock b/yarn.lock index bfa5427a1..904587de3 100644 --- a/yarn.lock +++ b/yarn.lock @@ -17853,6 +17853,11 @@ yocto-queue@^0.1.0: resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b" integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q== +zod@^3.17.3: + version "3.17.3" + resolved "https://registry.yarnpkg.com/zod/-/zod-3.17.3.tgz#86abbc670ff0063a4588d85a4dcc917d6e4af2ba" + integrity sha512-4oKP5zvG6GGbMlqBkI5FESOAweldEhSOZ6LI6cG+JzUT7ofj1ZOC0PJudpQOpT1iqOFpYYtX5Pw0+o403y4bcg== + zwitch@^1.0.0: version "1.0.5" resolved "https://registry.yarnpkg.com/zwitch/-/zwitch-1.0.5.tgz#d11d7381ffed16b742f6af7b3f223d5cd9fe9920" From f8812a9ec4949b78e23516d3dc7dac69363975d2 Mon Sep 17 00:00:00 2001 From: Jan Langheimer Date: Tue, 12 Jul 2022 10:04:49 +0200 Subject: [PATCH 09/36] introduce new api for pool table and top pools --- src/elements/admin/AdminQueryTest.tsx | 14 ++++- src/elements/earn/pools/TopPools.tsx | 24 +++++--- .../earn/pools/poolsTable/PoolsTable.tsx | 56 +++++++++-------- src/queries/api/useApiStakedBalance.ts | 31 ++++++++++ src/queries/api/useApiVolume.ts | 34 +++++++++++ src/queries/chain/useChainLatestProgram.ts | 42 +++++++++++++ src/queries/chain/usePoolPick.ts | 61 ++++++++++++++----- 7 files changed, 210 insertions(+), 52 deletions(-) create mode 100644 src/queries/api/useApiStakedBalance.ts create mode 100644 src/queries/api/useApiVolume.ts create mode 100644 src/queries/chain/useChainLatestProgram.ts diff --git a/src/elements/admin/AdminQueryTest.tsx b/src/elements/admin/AdminQueryTest.tsx index 023b735e8..3e46c334e 100644 --- a/src/elements/admin/AdminQueryTest.tsx +++ b/src/elements/admin/AdminQueryTest.tsx @@ -1,17 +1,27 @@ import { useChainPoolIds } from 'queries/chain/useChainPoolIds'; import { usePoolPick } from 'queries/chain/usePoolPick'; +import { useMemo } from 'react'; export const AdminQueryTest = () => { const { data: poolIds, isLoading, isFetching } = useChainPoolIds(); - const test = usePoolPick(poolIds ? poolIds[0] : '', ['poolDltId', 'symbol']); + const { getMany } = usePoolPick([ + 'poolDltId', + 'symbol', + 'fees', + 'latestProgram', + ]); + + const all = useMemo(() => { + return getMany(poolIds || []); + }, [getMany, poolIds]); return (
admin query test
{isFetching && 'fetching...'} - {isLoading ? 'loading...' :
{JSON.stringify(test, null, 2)}
} + {isLoading ? 'loading...' :
{JSON.stringify(all, null, 2)}
}
); diff --git a/src/elements/earn/pools/TopPools.tsx b/src/elements/earn/pools/TopPools.tsx index 76c28c933..cdacb90fb 100644 --- a/src/elements/earn/pools/TopPools.tsx +++ b/src/elements/earn/pools/TopPools.tsx @@ -1,13 +1,24 @@ import { Ticker } from 'components/ticker/Ticker'; -import { useAppSelector } from 'store'; -import { getTopPoolsV3 } from 'store/bancor/pool'; import { ReactComponent as IconGift } from 'assets/icons/gift.svg'; import { Image } from 'components/image/Image'; import { DepositDisabledModal } from 'elements/earn/pools/poolsTable/v3/DepositDisabledModal'; +import { usePoolPick } from 'queries/chain/usePoolPick'; +import { useMemo } from 'react'; +import { orderBy } from 'lodash'; +import { useChainPoolIds } from 'queries/chain/useChainPoolIds'; // import { DepositV3Modal } from './poolsTable/v3/DepositV3Modal'; export const TopPools = () => { - const pools = useAppSelector(getTopPoolsV3); + const { getMany } = usePoolPick(['symbol', 'apr', 'latestProgram']); + const { data: poolIds } = useChainPoolIds(); + + const pools = useMemo(() => { + return orderBy( + getMany(poolIds ?? []).filter((p) => p.apr && p.apr.apr7d.total > 0), + 'apr.apr7d.total', + 'desc' + ).slice(0, 20); + }, [getMany, poolIds]); return (
@@ -25,16 +36,13 @@ export const TopPools = () => { className="flex items-center justify-center min-w-[170px] h-[75px] rounded-[6px] bg-white dark:bg-charcoal border border-silver dark:border-grey transition-all duration-300" > Token Logo
-
- {pool.reserveToken.symbol} -
+
{pool.symbol}
- {pool.apr7d.total.toFixed(2)}% + {pool.apr?.apr7d.total.toFixed(2)}% {pool.latestProgram?.isActive && ( )} diff --git a/src/elements/earn/pools/poolsTable/PoolsTable.tsx b/src/elements/earn/pools/poolsTable/PoolsTable.tsx index d7baab431..327168ae7 100644 --- a/src/elements/earn/pools/poolsTable/PoolsTable.tsx +++ b/src/elements/earn/pools/poolsTable/PoolsTable.tsx @@ -1,4 +1,3 @@ -import { Token } from 'services/observables/tokens'; import { useCallback, useMemo, useState } from 'react'; import { SortingRule } from 'react-table'; import { DataTable, TableColumn } from 'components/table/DataTable'; @@ -15,8 +14,22 @@ import { sortNumbersByKey } from 'utils/pureFunctions'; import { Navigate } from 'components/navigate/Navigate'; import { PopoverV3 } from 'components/popover/PopoverV3'; import { Image } from 'components/image/Image'; -import { usePoolsV3 } from 'queries/usePoolsV3'; -import { PoolV3Chain } from 'queries/useV3ChainData'; +import { useChainPoolIds } from 'queries/chain/useChainPoolIds'; +import { PoolNew, usePoolPick } from 'queries/chain/usePoolPick'; + +const poolKeys = [ + 'poolDltId', + 'symbol', + 'fees', + 'tradingLiquidity', + 'apr', + 'volume', + 'tradingEnabled', + 'stakedBalance', + 'latestProgram', +] as const; + +type Pool = Pick; export const PoolsTable = ({ rewards, @@ -37,11 +50,17 @@ export const PoolsTable = ({ lowEarnRate: boolean; setLowEarnRate: Function; }) => { - const { data: pools, isLoading } = usePoolsV3(); + const { data: poolIds, isLoading } = useChainPoolIds(); + + const { getMany } = usePoolPick([...poolKeys]); + + const pools: Pool[] = useMemo(() => { + return getMany(poolIds || []); + }, [getMany, poolIds]); const [search, setSearch] = useState(''); - const data = useMemo(() => { + const data = useMemo(() => { return pools ? pools.filter( (p) => @@ -54,7 +73,7 @@ export const PoolsTable = ({ }, [pools, search, lowVolume, lowLiquidity, lowEarnRate]); const toolTip = useCallback( - (row: PoolV3Chain) => ( + (row: Pool) => (
{row.stakedBalance.usd && (
@@ -91,7 +110,7 @@ export const PoolsTable = ({ [] ); - const columns = useMemo[]>( + const columns = useMemo[]>( () => [ { id: 'name', @@ -103,7 +122,6 @@ export const PoolsTable = ({ buttonElement={() => (
Pool Logo @@ -115,20 +133,6 @@ export const PoolsTable = ({ minWidth: 185, sortDescFirst: true, }, - { - id: 'tknBalance', - Header: 'Tkn Balance', - accessor: 'tknBalance', - minWidth: 185, - sortDescFirst: true, - }, - { - id: 'bnTknBalance', - Header: 'BnTkn Balance', - accessor: 'bnTknBalance', - minWidth: 185, - sortDescFirst: true, - }, { id: 'apr', Header: 'Earn', @@ -163,7 +167,7 @@ export const PoolsTable = ({
), sortType: (a, b) => - sortNumbersByKey(a.original, b.original, ['apr7d', 'total']), + sortNumbersByKey(a.original, b.original, ['apr', 'apr7d', 'total']), tooltip: 'Estimated APR based on the last 7d trading fees, auto compounding and standard rewards', minWidth: 100, @@ -194,8 +198,8 @@ export const PoolsTable = ({ [toolTip] ); - const defaultSort: SortingRule = { - id: 'apr', + const defaultSort: SortingRule = { + id: 'apr.apr7d.total', desc: true, }; @@ -224,7 +228,7 @@ export const PoolsTable = ({ setLowEarnRate={setLowEarnRate} />
- + data={data} columns={columns} defaultSort={defaultSort} diff --git a/src/queries/api/useApiStakedBalance.ts b/src/queries/api/useApiStakedBalance.ts new file mode 100644 index 000000000..5f8d648bd --- /dev/null +++ b/src/queries/api/useApiStakedBalance.ts @@ -0,0 +1,31 @@ +import { useMemo } from 'react'; +import { useChainPoolIds } from 'queries/chain/useChainPoolIds'; +import { useApiPools } from 'queries/api/useApiPools'; + +interface Props { + enabled?: boolean; +} + +export const useApiStakedBalance = ({ enabled = true }: Props = {}) => { + const { data: poolIds } = useChainPoolIds(); + const { getApiPoolByID } = useApiPools({ enabled }); + + const data = useMemo( + () => + new Map( + poolIds?.map((id) => { + const apiPool = getApiPoolByID(id); + + if (!apiPool) { + return [id, undefined]; + } + return [id, { ...apiPool.stakedBalance }]; + }) + ), + [getApiPoolByID, poolIds] + ); + + const getStakedBalanceByID = (id: string) => data.get(id); + + return { data, getStakedBalanceByID }; +}; diff --git a/src/queries/api/useApiVolume.ts b/src/queries/api/useApiVolume.ts new file mode 100644 index 000000000..6539e0f23 --- /dev/null +++ b/src/queries/api/useApiVolume.ts @@ -0,0 +1,34 @@ +import { useMemo } from 'react'; +import { useChainPoolIds } from 'queries/chain/useChainPoolIds'; +import { useApiPools } from 'queries/api/useApiPools'; + +interface Props { + enabled?: boolean; +} + +export const useApiVolume = ({ enabled = true }: Props = {}) => { + const { data: poolIds } = useChainPoolIds(); + const { getApiPoolByID } = useApiPools({ enabled }); + + const data = useMemo( + () => + new Map( + poolIds?.map((id) => { + const apiPool = getApiPoolByID(id); + + if (!apiPool) { + return [id, undefined]; + } + return [ + id, + { volume7d: apiPool.volume7d, volume24h: apiPool.volume24h }, + ]; + }) + ), + [getApiPoolByID, poolIds] + ); + + const getVolumeByID = (id: string) => data.get(id); + + return { data, getVolumeByID }; +}; diff --git a/src/queries/chain/useChainLatestProgram.ts b/src/queries/chain/useChainLatestProgram.ts new file mode 100644 index 000000000..b72acace8 --- /dev/null +++ b/src/queries/chain/useChainLatestProgram.ts @@ -0,0 +1,42 @@ +import { useQuery } from 'react-query'; +import { QueryKey } from 'queries/queryKeyFactory'; +import { useChainPoolIds } from 'queries/chain/useChainPoolIds'; +import { queryOptionsNoInterval } from 'queries/queryOptions'; +import { + buildMulticallLatestProgramId, + fetchMulticallHelper, +} from 'services/web3/multicall/multicallFunctions'; +import { useChainPrograms } from 'queries/chain/useChainPrograms'; +import { BigNumberish } from 'ethers'; + +interface Props { + enabled?: boolean; +} + +export const useChainLatestProgram = ({ enabled = true }: Props = {}) => { + const { data: poolIds } = useChainPoolIds(); + const { data: programsMap } = useChainPrograms(); + + const query = useQuery( + QueryKey.chainCoreLatestProgramId(poolIds?.length), + async () => { + const ids = await fetchMulticallHelper( + poolIds!, + buildMulticallLatestProgramId + ); + return new Map( + poolIds?.map((id) => { + const programs = programsMap + ?.get(id) + ?.find((p) => p.id === ids.get(id)?.toString()); + return [id, programs]; + }) + ); + }, + queryOptionsNoInterval(!!poolIds && !!programsMap && enabled) + ); + + const getLatestProgramByID = (id: string) => query.data?.get(id); + + return { ...query, getLatestProgramByID }; +}; diff --git a/src/queries/chain/usePoolPick.ts b/src/queries/chain/usePoolPick.ts index 1a1de86db..e593d6470 100644 --- a/src/queries/chain/usePoolPick.ts +++ b/src/queries/chain/usePoolPick.ts @@ -7,23 +7,24 @@ import { useChainTradingEnabled } from 'queries/chain/useChainTradingEnabled'; import { useApiApr } from 'queries/api/useApiApr'; import { useChainTradingLiquidity } from 'queries/chain/useChainTradingLiquidity'; import { useApiFees } from 'queries/api/useApiFees'; +import { useApiVolume } from 'queries/api/useApiVolume'; +import { useApiStakedBalance } from 'queries/api/useApiStakedBalance'; +import { useChainLatestProgram } from 'queries/chain/useChainLatestProgram'; -type Pool = Pick< +export type PoolNew = Omit< PoolV3Chain, - | 'symbol' - | 'decimals' - | 'poolTokenDltId' - | 'programs' - | 'tradingEnabled' - | 'poolDltId' - | 'apr' - | 'tradingLiquidity' - | 'fees' + | 'name' + | 'logoURI' + | 'standardRewards' + | 'tradingFeePPM' + | 'depositingEnabled' + | 'tknBalance' + | 'bnTknBalance' >; -type PoolKey = keyof Pool; +export type PoolKey = keyof PoolNew; type Fetchers = { - [key in PoolKey]: (id: string) => Pool[key] | undefined; + [key in PoolKey]: (id: string) => PoolNew[key] | undefined; }; const useFetchers = (select: PoolKey[]): Fetchers => { @@ -53,6 +54,10 @@ const useFetchers = (select: PoolKey[]): Fetchers => { enabled: set.has('tradingLiquidity'), }); + const { getLatestProgramByID } = useChainLatestProgram({ + enabled: set.has('latestProgram'), + }); + const { getFeeByID } = useApiFees({ enabled: set.has('fees'), }); @@ -61,6 +66,14 @@ const useFetchers = (select: PoolKey[]): Fetchers => { enabled: set.has('apr'), }); + const { getVolumeByID } = useApiVolume({ + enabled: set.has('volume'), + }); + + const { getStakedBalanceByID } = useApiStakedBalance({ + enabled: set.has('stakedBalance'), + }); + return { poolDltId: (id) => id, symbol: getSymbolByID, @@ -71,15 +84,31 @@ const useFetchers = (select: PoolKey[]): Fetchers => { apr: getAprByID, tradingLiquidity: getTradingLiquidityByID, fees: getFeeByID, + volume: getVolumeByID, + stakedBalance: getStakedBalanceByID, + latestProgram: getLatestProgramByID, }; }; -export const usePoolPick = (id: string, select: T) => { - const fetchers = useFetchers(select); - +const selectReduce = ( + id: string, + select: T, + fetchers: Fetchers +) => { return select.reduce((res, key) => { // @ts-ignore res[key] = fetchers[key](id); return res; - }, {}) as Pick; + }, {}) as Pick; +}; + +export const usePoolPick = (select: T) => { + const fetchers = useFetchers(select); + + const getOne = (id: string) => selectReduce(id, select, fetchers); + + const getMany = (ids: string[]) => + ids.map((id) => selectReduce(id, select, fetchers)); + + return { getOne, getMany }; }; From bc6a8b79cb2197057aced3833b13af2ca873b36c Mon Sep 17 00:00:00 2001 From: Jan Langheimer Date: Tue, 12 Jul 2022 21:37:08 +0200 Subject: [PATCH 10/36] cleanup part 1 --- src/elements/admin/AdminQueryTest.tsx | 15 +- src/elements/earn/pools/TopPools.tsx | 10 +- .../earn/pools/poolsTable/PoolsTable.tsx | 13 +- src/queries/api/useApiApr.ts | 133 +++++++++--------- src/queries/api/useApiBnt.ts | 16 +++ src/queries/api/useApiFees.ts | 35 ++--- src/queries/api/useApiPools.ts | 3 +- src/queries/api/useApiStakedBalance.ts | 35 ++--- src/queries/api/useApiVolume.ts | 38 +++-- src/queries/chain/useChainLatestProgram.ts | 8 +- src/queries/chain/useChainPoolIds.ts | 6 +- src/queries/chain/useChainPoolTokenIds.ts | 4 +- src/queries/chain/useChainPrograms.ts | 4 +- src/queries/chain/useChainTokenDecimals.ts | 14 +- src/queries/chain/useChainTokenSymbol.ts | 15 +- src/queries/chain/useChainTradingEnabled.ts | 4 +- src/queries/chain/useChainTradingLiquidity.ts | 28 +++- src/queries/chain/usePoolPick.ts | 100 ++++++++----- src/queries/queryKeyFactory.ts | 3 +- src/services/api/bancorApi/bancorApiV3.ts | 50 +++++++ 20 files changed, 330 insertions(+), 204 deletions(-) create mode 100644 src/queries/api/useApiBnt.ts diff --git a/src/elements/admin/AdminQueryTest.tsx b/src/elements/admin/AdminQueryTest.tsx index 3e46c334e..45fa4fcb6 100644 --- a/src/elements/admin/AdminQueryTest.tsx +++ b/src/elements/admin/AdminQueryTest.tsx @@ -1,26 +1,17 @@ import { useChainPoolIds } from 'queries/chain/useChainPoolIds'; import { usePoolPick } from 'queries/chain/usePoolPick'; -import { useMemo } from 'react'; export const AdminQueryTest = () => { - const { data: poolIds, isLoading, isFetching } = useChainPoolIds(); + const { data: poolIds } = useChainPoolIds(); - const { getMany } = usePoolPick([ - 'poolDltId', - 'symbol', - 'fees', - 'latestProgram', - ]); + const { getMany, isLoading } = usePoolPick(['fees', 'symbol']); - const all = useMemo(() => { - return getMany(poolIds || []); - }, [getMany, poolIds]); + const { data: all } = getMany(poolIds || []); return (
admin query test
- {isFetching && 'fetching...'} {isLoading ? 'loading...' :
{JSON.stringify(all, null, 2)}
}
diff --git a/src/elements/earn/pools/TopPools.tsx b/src/elements/earn/pools/TopPools.tsx index cdacb90fb..eb063d24f 100644 --- a/src/elements/earn/pools/TopPools.tsx +++ b/src/elements/earn/pools/TopPools.tsx @@ -9,23 +9,25 @@ import { useChainPoolIds } from 'queries/chain/useChainPoolIds'; // import { DepositV3Modal } from './poolsTable/v3/DepositV3Modal'; export const TopPools = () => { - const { getMany } = usePoolPick(['symbol', 'apr', 'latestProgram']); const { data: poolIds } = useChainPoolIds(); + const { getMany } = usePoolPick(['symbol', 'apr', 'latestProgram']); + + const { data, isLoading } = getMany(poolIds || []); const pools = useMemo(() => { return orderBy( - getMany(poolIds ?? []).filter((p) => p.apr && p.apr.apr7d.total > 0), + data.filter((p) => p.apr && p.apr.apr7d.total > 0), 'apr.apr7d.total', 'desc' ).slice(0, 20); - }, [getMany, poolIds]); + }, [data]); return (

Top Performing

- {pools.length + {!isLoading ? pools.map((pool, index) => { return ( { - const { data: poolIds, isLoading } = useChainPoolIds(); + const { data: poolIds } = useChainPoolIds(); const { getMany } = usePoolPick([...poolKeys]); - const pools: Pool[] = useMemo(() => { - return getMany(poolIds || []); - }, [getMany, poolIds]); + const { data: pools, isLoading } = getMany(poolIds || []); const [search, setSearch] = useState(''); const data = useMemo(() => { - return pools + return pools && !isLoading ? pools.filter( (p) => p.symbol.toLowerCase().includes(search.toLowerCase()) && @@ -70,7 +67,7 @@ export const PoolsTable = ({ (lowEarnRate || (p.apr?.apr7d?.total ?? 0) > 0.15) ) : []; - }, [pools, search, lowVolume, lowLiquidity, lowEarnRate]); + }, [pools, search, lowVolume, lowLiquidity, lowEarnRate, isLoading]); const toolTip = useCallback( (row: Pool) => ( @@ -176,7 +173,7 @@ export const PoolsTable = ({ { id: 'actions', Header: '', - accessor: 'poolDltId', + accessor: 'symbol', Cell: (_) => ( ( diff --git a/src/queries/api/useApiApr.ts b/src/queries/api/useApiApr.ts index 538f22e25..7c8f1b1b9 100644 --- a/src/queries/api/useApiApr.ts +++ b/src/queries/api/useApiApr.ts @@ -1,5 +1,4 @@ import { useChainPrograms } from 'queries/chain/useChainPrograms'; -import { useMemo } from 'react'; import { toBigNumber } from 'utils/helperFunctions'; import { standardsRewardsAPR } from 'services/observables/pools'; import { calcApr } from 'utils/formulas'; @@ -11,80 +10,80 @@ interface Props { } export const useApiApr = ({ enabled = true }: Props = {}) => { - const { data: poolIds } = useChainPoolIds(); - const { getApiPoolByID } = useApiPools({ enabled }); - const { data: programsMap } = useChainPrograms({ enabled }); + const poolIds = useChainPoolIds(); + const apiPools = useApiPools({ enabled }); + const programsMap = useChainPrograms({ enabled }); - const data = useMemo( - () => - new Map( - poolIds?.map((id) => { - const apiPool = getApiPoolByID(id); - const programs = programsMap?.get(id); + const data = new Map( + poolIds.data?.map((id) => { + const apiPool = apiPools.getApiPoolByID(id); + const programs = programsMap.data?.get(id); - if (!apiPool) { - return [id, undefined]; - } - // FIXES STAKED BALANCE = 0 WHEN TRADING ENABLED = FALSE - const stakedBalance = { ...apiPool.stakedBalance }; - if ( - apiPool.tradingEnabled === false && - toBigNumber(stakedBalance.usd).isZero() - ) { - stakedBalance.usd = toBigNumber(apiPool.stakedBalance.tkn) - // TODO - add apiToken.rate - .times('0') - .toString(); - } + if (!apiPool) { + return [id, undefined]; + } + // FIXES STAKED BALANCE = 0 WHEN TRADING ENABLED = FALSE + const stakedBalance = { ...apiPool.stakedBalance }; + if ( + apiPool.tradingEnabled === false && + toBigNumber(stakedBalance.usd).isZero() + ) { + stakedBalance.usd = toBigNumber(apiPool.stakedBalance.tkn) + // TODO - add apiToken.rate + .times('0') + .toString(); + } - // Calculate APR - const standardRewardsApr24H = standardsRewardsAPR(apiPool, programs); - const standardRewardsApr7d = standardsRewardsAPR(apiPool, programs); + // Calculate APR + const standardRewardsApr24H = standardsRewardsAPR(apiPool, programs); + const standardRewardsApr7d = standardsRewardsAPR(apiPool, programs); - const tradingFeesApr24h = calcApr( - apiPool.fees24h.usd, - stakedBalance.usd - ); - const tradingFeesApr7d = calcApr( - apiPool.fees7d.usd, - stakedBalance.usd, - true - ); + const tradingFeesApr24h = calcApr(apiPool.fees24h.usd, stakedBalance.usd); + const tradingFeesApr7d = calcApr( + apiPool.fees7d.usd, + stakedBalance.usd, + true + ); - // TODO - add values once available - const autoCompoundingApr24H = 0; - const autoCompoundingApr7d = 0; + // TODO - add values once available + const autoCompoundingApr24H = 0; + const autoCompoundingApr7d = 0; - const totalApr24H = toBigNumber(tradingFeesApr24h) - .plus(standardRewardsApr24H) - .plus(autoCompoundingApr24H) - .toNumber(); + const totalApr24H = toBigNumber(tradingFeesApr24h) + .plus(standardRewardsApr24H) + .plus(autoCompoundingApr24H) + .toNumber(); - const totalApr7d = toBigNumber(tradingFeesApr7d) - .plus(autoCompoundingApr7d) - .plus(standardRewardsApr7d) - .toNumber(); - const apr = { - apr24h: { - tradingFees: tradingFeesApr24h, - standardRewards: standardRewardsApr24H, - autoCompounding: autoCompoundingApr24H, - total: totalApr24H, - }, - apr7d: { - tradingFees: tradingFeesApr7d, - standardRewards: standardRewardsApr7d, - autoCompounding: autoCompoundingApr7d, - total: totalApr7d, - }, - }; - return [id, { ...apr }]; - }) - ), - [getApiPoolByID, poolIds, programsMap] + const totalApr7d = toBigNumber(tradingFeesApr7d) + .plus(autoCompoundingApr7d) + .plus(standardRewardsApr7d) + .toNumber(); + const apr = { + apr24h: { + tradingFees: tradingFeesApr24h, + standardRewards: standardRewardsApr24H, + autoCompounding: autoCompoundingApr24H, + total: totalApr24H, + }, + apr7d: { + tradingFees: tradingFeesApr7d, + standardRewards: standardRewardsApr7d, + autoCompounding: autoCompoundingApr7d, + total: totalApr7d, + }, + }; + return [id, { ...apr }]; + }) ); - const getAprByID = (id: string) => data.get(id); + const getByID = (id: string) => data.get(id); - return { data, getAprByID }; + return { + data, + getByID, + isLoading: poolIds.isLoading || apiPools.isLoading || programsMap.isLoading, + isFetching: + poolIds.isFetching || apiPools.isFetching || programsMap.isFetching, + isError: poolIds.isError || apiPools.isError || programsMap.isError, + }; }; diff --git a/src/queries/api/useApiBnt.ts b/src/queries/api/useApiBnt.ts new file mode 100644 index 000000000..2591a94a6 --- /dev/null +++ b/src/queries/api/useApiBnt.ts @@ -0,0 +1,16 @@ +import { useQuery } from 'react-query'; +import { BancorApi } from 'services/api/bancorApi/bancorApi'; +import { QueryKey } from 'queries/queryKeyFactory'; + +interface Props { + enabled?: boolean; +} + +export const useApiBnt = ({ enabled = true }: Props = {}) => { + const queryKey = QueryKey.apiBnt(); + return useQuery(queryKey, BancorApi.v3.getBnt, { + enabled, + useErrorBoundary: true, + onError: (err) => console.error('query failed', queryKey, err), + }); +}; diff --git a/src/queries/api/useApiFees.ts b/src/queries/api/useApiFees.ts index ea43c9e66..c09d7c3c4 100644 --- a/src/queries/api/useApiFees.ts +++ b/src/queries/api/useApiFees.ts @@ -1,4 +1,3 @@ -import { useMemo } from 'react'; import { useChainPoolIds } from 'queries/chain/useChainPoolIds'; import { useApiPools } from 'queries/api/useApiPools'; @@ -7,25 +6,27 @@ interface Props { } export const useApiFees = ({ enabled = true }: Props = {}) => { - const { data: poolIds } = useChainPoolIds(); - const { getApiPoolByID } = useApiPools({ enabled }); + const poolIds = useChainPoolIds(); + const apiPools = useApiPools({ enabled }); - const data = useMemo( - () => - new Map( - poolIds?.map((id) => { - const apiPool = getApiPoolByID(id); + const data = new Map( + poolIds.data?.map((id) => { + const apiPool = apiPools.getApiPoolByID(id); - if (!apiPool) { - return [id, undefined]; - } - return [id, { fees7d: apiPool.fees7d, fees24h: apiPool.fees24h }]; - }) - ), - [getApiPoolByID, poolIds] + if (!apiPool) { + return [id, undefined]; + } + return [id, { fees7d: apiPool.fees7d, fees24h: apiPool.fees24h }]; + }) ); - const getFeeByID = (id: string) => data.get(id); + const getByID = (id: string) => data.get(id); - return { data, getFeeByID }; + return { + data, + getByID, + isLoading: apiPools.isLoading || poolIds.isLoading, + isFetching: apiPools.isFetching || poolIds.isFetching, + isError: apiPools.isError || poolIds.isError, + }; }; diff --git a/src/queries/api/useApiPools.ts b/src/queries/api/useApiPools.ts index 4682b922d..a7f7cb499 100644 --- a/src/queries/api/useApiPools.ts +++ b/src/queries/api/useApiPools.ts @@ -8,10 +8,11 @@ interface Props { export const useApiPools = ({ enabled = true }: Props = {}) => { const queryKey = QueryKey.apiPools(); + const query = useQuery( queryKey, async () => { - const pools = await BancorApi.v3.getPools(); + const pools = await BancorApi.v3.getPoolsWithBNT(); return new Map(pools.map((p) => [p.poolDltId, p])); }, { diff --git a/src/queries/api/useApiStakedBalance.ts b/src/queries/api/useApiStakedBalance.ts index 5f8d648bd..72070d09a 100644 --- a/src/queries/api/useApiStakedBalance.ts +++ b/src/queries/api/useApiStakedBalance.ts @@ -1,4 +1,3 @@ -import { useMemo } from 'react'; import { useChainPoolIds } from 'queries/chain/useChainPoolIds'; import { useApiPools } from 'queries/api/useApiPools'; @@ -7,25 +6,27 @@ interface Props { } export const useApiStakedBalance = ({ enabled = true }: Props = {}) => { - const { data: poolIds } = useChainPoolIds(); - const { getApiPoolByID } = useApiPools({ enabled }); + const poolIds = useChainPoolIds(); + const apiPools = useApiPools({ enabled }); - const data = useMemo( - () => - new Map( - poolIds?.map((id) => { - const apiPool = getApiPoolByID(id); + const data = new Map( + poolIds.data?.map((id) => { + const apiPool = apiPools.getApiPoolByID(id); - if (!apiPool) { - return [id, undefined]; - } - return [id, { ...apiPool.stakedBalance }]; - }) - ), - [getApiPoolByID, poolIds] + if (!apiPool) { + return [id, undefined]; + } + return [id, { ...apiPool.stakedBalance }]; + }) ); - const getStakedBalanceByID = (id: string) => data.get(id); + const getByID = (id: string) => data.get(id); - return { data, getStakedBalanceByID }; + return { + data, + getByID, + isLoading: apiPools.isLoading || poolIds.isLoading, + isFetching: apiPools.isFetching || poolIds.isFetching, + isError: apiPools.isError || poolIds.isError, + }; }; diff --git a/src/queries/api/useApiVolume.ts b/src/queries/api/useApiVolume.ts index 6539e0f23..ae9a7f7a9 100644 --- a/src/queries/api/useApiVolume.ts +++ b/src/queries/api/useApiVolume.ts @@ -1,4 +1,3 @@ -import { useMemo } from 'react'; import { useChainPoolIds } from 'queries/chain/useChainPoolIds'; import { useApiPools } from 'queries/api/useApiPools'; @@ -7,28 +6,27 @@ interface Props { } export const useApiVolume = ({ enabled = true }: Props = {}) => { - const { data: poolIds } = useChainPoolIds(); - const { getApiPoolByID } = useApiPools({ enabled }); + const poolIds = useChainPoolIds(); + const apiPools = useApiPools({ enabled }); - const data = useMemo( - () => - new Map( - poolIds?.map((id) => { - const apiPool = getApiPoolByID(id); + const data = new Map( + poolIds.data?.map((id) => { + const apiPool = apiPools.getApiPoolByID(id); - if (!apiPool) { - return [id, undefined]; - } - return [ - id, - { volume7d: apiPool.volume7d, volume24h: apiPool.volume24h }, - ]; - }) - ), - [getApiPoolByID, poolIds] + if (!apiPool) { + return [id, undefined]; + } + return [id, { volume7d: apiPool.volume7d, volume24h: apiPool.volume24h }]; + }) ); - const getVolumeByID = (id: string) => data.get(id); + const getByID = (id: string) => data.get(id); - return { data, getVolumeByID }; + return { + data, + getByID, + isLoading: apiPools.isLoading || poolIds.isLoading, + isFetching: apiPools.isFetching || poolIds.isFetching, + isError: apiPools.isError || poolIds.isError, + }; }; diff --git a/src/queries/chain/useChainLatestProgram.ts b/src/queries/chain/useChainLatestProgram.ts index b72acace8..2677238d3 100644 --- a/src/queries/chain/useChainLatestProgram.ts +++ b/src/queries/chain/useChainLatestProgram.ts @@ -15,10 +15,10 @@ interface Props { export const useChainLatestProgram = ({ enabled = true }: Props = {}) => { const { data: poolIds } = useChainPoolIds(); - const { data: programsMap } = useChainPrograms(); + const { data: programsMap } = useChainPrograms({ enabled }); const query = useQuery( - QueryKey.chainCoreLatestProgramId(poolIds?.length), + QueryKey.chainCoreLatestProgram(poolIds?.length), async () => { const ids = await fetchMulticallHelper( poolIds!, @@ -36,7 +36,7 @@ export const useChainLatestProgram = ({ enabled = true }: Props = {}) => { queryOptionsNoInterval(!!poolIds && !!programsMap && enabled) ); - const getLatestProgramByID = (id: string) => query.data?.get(id); + const getByID = (id: string) => query.data?.get(id); - return { ...query, getLatestProgramByID }; + return { ...query, getByID }; }; diff --git a/src/queries/chain/useChainPoolIds.ts b/src/queries/chain/useChainPoolIds.ts index 04e8c28b9..37659ef43 100644 --- a/src/queries/chain/useChainPoolIds.ts +++ b/src/queries/chain/useChainPoolIds.ts @@ -1,15 +1,17 @@ import { useQuery } from 'react-query'; import { ContractsApi } from 'services/web3/v3/contractsApi'; import { QueryKey } from 'queries/queryKeyFactory'; -import { ethToken } from 'services/web3/config'; +// import { ethToken } from 'services/web3/config'; import { queryOptionsStaleTimeLow } from 'queries/queryOptions'; +import { bntToken } from 'services/web3/config'; export const useChainPoolIds = () => { return useQuery( QueryKey.chainCorePoolIds(), async () => { const pools = await ContractsApi.BancorNetwork.read.liquidityPools(); - return pools.filter((id) => id !== ethToken); + //return pools.filter((id) => id !== ethToken); + return [bntToken, ...pools]; }, queryOptionsStaleTimeLow() ); diff --git a/src/queries/chain/useChainPoolTokenIds.ts b/src/queries/chain/useChainPoolTokenIds.ts index 4b20cfc96..65e1478d5 100644 --- a/src/queries/chain/useChainPoolTokenIds.ts +++ b/src/queries/chain/useChainPoolTokenIds.ts @@ -19,7 +19,7 @@ export const useChainPoolTokenIds = ({ enabled = true }: Props = {}) => { queryOptionsNoInterval(!!poolIds && enabled) ); - const getPoolTokenByID = (id: string) => query.data?.get(id); + const getByID = (id: string) => query.data?.get(id); - return { ...query, getPoolTokenByID }; + return { ...query, getByID }; }; diff --git a/src/queries/chain/useChainPrograms.ts b/src/queries/chain/useChainPrograms.ts index d8265f616..3a9965df1 100644 --- a/src/queries/chain/useChainPrograms.ts +++ b/src/queries/chain/useChainPrograms.ts @@ -21,7 +21,7 @@ export const useChainPrograms = ({ enabled = true }: Props = {}) => { queryOptionsNoInterval(!!poolIds && enabled) ); - const getProgramsByID = (id: string) => query.data?.get(id); + const getByID = (id: string) => query.data?.get(id); - return { ...query, getProgramsByID }; + return { ...query, getByID }; }; diff --git a/src/queries/chain/useChainTokenDecimals.ts b/src/queries/chain/useChainTokenDecimals.ts index 5941d5910..2fd00a2a7 100644 --- a/src/queries/chain/useChainTokenDecimals.ts +++ b/src/queries/chain/useChainTokenDecimals.ts @@ -6,6 +6,7 @@ import { fetchMulticallHelper, } from 'services/web3/multicall/multicallFunctions'; import { queryOptionsNoInterval } from 'queries/queryOptions'; +import { ethToken } from 'services/web3/config'; interface Props { enabled?: boolean; @@ -15,11 +16,18 @@ export const useChainTokenDecimals = ({ enabled = true }: Props = {}) => { const { data: poolIds } = useChainPoolIds(); const query = useQuery( QueryKey.chainCoreDecimals(poolIds?.length), - () => fetchMulticallHelper(poolIds!, buildMulticallDecimal), + async () => { + const decimals = await fetchMulticallHelper( + poolIds!.filter((id) => id !== ethToken), + buildMulticallDecimal + ); + decimals.set(ethToken, 18); + return decimals; + }, queryOptionsNoInterval(!!poolIds && enabled) ); - const getDecimalsByID = (id: string) => query.data?.get(id); + const getByID = (id: string) => query.data?.get(id); - return { ...query, getDecimalsByID }; + return { ...query, getByID }; }; diff --git a/src/queries/chain/useChainTokenSymbol.ts b/src/queries/chain/useChainTokenSymbol.ts index 0a10bf171..22cd36f39 100644 --- a/src/queries/chain/useChainTokenSymbol.ts +++ b/src/queries/chain/useChainTokenSymbol.ts @@ -6,6 +6,7 @@ import { buildMulticallSymbol, fetchMulticallHelper, } from 'services/web3/multicall/multicallFunctions'; +import { ethToken } from 'services/web3/config'; interface Props { enabled?: boolean; @@ -15,11 +16,19 @@ export const useChainTokenSymbol = ({ enabled = true }: Props = {}) => { const { data: poolIds } = useChainPoolIds(); const query = useQuery( QueryKey.chainCoreSymbols(poolIds?.length), - () => fetchMulticallHelper(poolIds!, buildMulticallSymbol, true), + async () => { + const symbols = await fetchMulticallHelper( + poolIds!, + buildMulticallSymbol, + true + ); + symbols.set(ethToken, 'ETH'); + return symbols; + }, queryOptionsNoInterval(!!poolIds && enabled) ); - const getSymbolByID = (id: string) => query.data?.get(id); + const getByID = (id: string) => query.data?.get(id); - return { ...query, getSymbolByID }; + return { ...query, getByID }; }; diff --git a/src/queries/chain/useChainTradingEnabled.ts b/src/queries/chain/useChainTradingEnabled.ts index 40e1d3f9b..a699fa4ca 100644 --- a/src/queries/chain/useChainTradingEnabled.ts +++ b/src/queries/chain/useChainTradingEnabled.ts @@ -19,7 +19,7 @@ export const useChainTradingEnabled = ({ enabled = true }: Props = {}) => { queryOptionsStaleTimeLow(!!poolIds && enabled) ); - const getTradingEnabledByID = (id: string) => query.data?.get(id); + const getByID = (id: string) => query.data?.get(id); - return { ...query, getTradingEnabledByID }; + return { ...query, getByID }; }; diff --git a/src/queries/chain/useChainTradingLiquidity.ts b/src/queries/chain/useChainTradingLiquidity.ts index fd8ada08c..bb45eee57 100644 --- a/src/queries/chain/useChainTradingLiquidity.ts +++ b/src/queries/chain/useChainTradingLiquidity.ts @@ -9,6 +9,8 @@ import { import { TradingLiquidityStructOutput } from 'services/web3/abis/types/BancorNetworkInfo'; import { useChainTokenDecimals } from 'queries/chain/useChainTokenDecimals'; import { utils } from 'ethers'; +import { bntToken } from 'services/web3/config'; +import { useApiBnt } from 'queries/api/useApiBnt'; interface Props { enabled?: boolean; @@ -17,18 +19,38 @@ interface Props { export const useChainTradingLiquidity = ({ enabled = true }: Props = {}) => { const { data: poolIds } = useChainPoolIds(); const { data: decimals } = useChainTokenDecimals({ enabled }); + const { data: bnt } = useApiBnt({ enabled }); const query = useQuery( QueryKey.chainCoreTradingLiquidity(poolIds?.length), () => fetchMulticallHelper( - poolIds!, + poolIds!.filter((id) => id !== bntToken), buildMulticallTradingLiquidity ), queryOptionsStaleTimeLow(!!poolIds && enabled) ); - const getTradingLiquidityByID = (id: string) => { + const _getBNT = () => { + if (!bnt) { + return undefined; + } + + return { + BNT: { + ...bnt.tradingLiquidity, + tkn: bnt.tradingLiquidity.bnt, + }, + TKN: { + tkn: '0', + }, + }; + }; + + const getByID = (id: string) => { + if (id === bntToken) { + return _getBNT(); + } const dec = decimals?.get(id); const liq = query.data?.get(id); if (!liq || !dec) { @@ -47,5 +69,5 @@ export const useChainTradingLiquidity = ({ enabled = true }: Props = {}) => { }; }; - return { ...query, getTradingLiquidityByID }; + return { ...query, getByID }; }; diff --git a/src/queries/chain/usePoolPick.ts b/src/queries/chain/usePoolPick.ts index e593d6470..941962579 100644 --- a/src/queries/chain/usePoolPick.ts +++ b/src/queries/chain/usePoolPick.ts @@ -24,91 +24,119 @@ export type PoolNew = Omit< export type PoolKey = keyof PoolNew; type Fetchers = { - [key in PoolKey]: (id: string) => PoolNew[key] | undefined; + [key in PoolKey]: { + getByID: (id: string) => PoolNew[key] | undefined; + isLoading: boolean; + isFetching: boolean; + isError: boolean; + }; }; -const useFetchers = (select: PoolKey[]): Fetchers => { +type PoolReturn = Pick extends infer R + ? { [key in keyof R]: R[key] } + : never; + +const useFetchers = (select: PoolKey[]) => { const set = new Set(select.map((key) => key)); - const { getSymbolByID } = useChainTokenSymbol({ + const symbol = useChainTokenSymbol({ enabled: set.has('symbol'), }); - const { getDecimalsByID } = useChainTokenDecimals({ + const decimals = useChainTokenDecimals({ enabled: set.has('decimals'), }); - const { getPoolTokenByID } = useChainPoolTokenIds({ + const poolTokenDltId = useChainPoolTokenIds({ enabled: set.has('poolTokenDltId'), }); - const { getProgramsByID } = useChainPrograms({ + const programs = useChainPrograms({ enabled: set.has('programs'), }); - const { getTradingEnabledByID } = useChainTradingEnabled({ + const tradingEnabled = useChainTradingEnabled({ enabled: set.has('tradingEnabled'), }); - const { getTradingLiquidityByID } = useChainTradingLiquidity({ + const tradingLiquidity = useChainTradingLiquidity({ enabled: set.has('tradingLiquidity'), }); - const { getLatestProgramByID } = useChainLatestProgram({ + const latestProgram = useChainLatestProgram({ enabled: set.has('latestProgram'), }); - const { getFeeByID } = useApiFees({ + const fees = useApiFees({ enabled: set.has('fees'), }); - const { getAprByID } = useApiApr({ + const apr = useApiApr({ enabled: set.has('apr'), }); - const { getVolumeByID } = useApiVolume({ + const volume = useApiVolume({ enabled: set.has('volume'), }); - const { getStakedBalanceByID } = useApiStakedBalance({ + const stakedBalance = useApiStakedBalance({ enabled: set.has('stakedBalance'), }); - return { - poolDltId: (id) => id, - symbol: getSymbolByID, - decimals: getDecimalsByID, - poolTokenDltId: getPoolTokenByID, - programs: getProgramsByID, - tradingEnabled: getTradingEnabledByID, - apr: getAprByID, - tradingLiquidity: getTradingLiquidityByID, - fees: getFeeByID, - volume: getVolumeByID, - stakedBalance: getStakedBalanceByID, - latestProgram: getLatestProgramByID, + const fetchers: Fetchers = { + poolDltId: { + getByID: (id: string) => id, + isError: false, + isFetching: false, + isLoading: false, + }, + symbol, + decimals, + poolTokenDltId, + programs, + tradingEnabled, + apr, + tradingLiquidity, + fees, + volume, + stakedBalance, + latestProgram, }; + + const isLoading = select.some((res) => fetchers[res].isLoading); + const isFetching = select.some((res) => fetchers[res].isFetching); + const isError = select.some((res) => fetchers[res].isError); + + return { fetchers, isLoading, isFetching, isError }; }; const selectReduce = ( id: string, select: T, fetchers: Fetchers -) => { - return select.reduce((res, key) => { +): PoolReturn => + select.reduce((res, key) => { // @ts-ignore - res[key] = fetchers[key](id); + res[key] = fetchers[key].getByID(id); return res; - }, {}) as Pick; -}; + }, {} as PoolReturn); export const usePoolPick = (select: T) => { - const fetchers = useFetchers(select); + const { fetchers, isLoading, isFetching, isError } = useFetchers(select); - const getOne = (id: string) => selectReduce(id, select, fetchers); + const getOne = (id: string) => ({ + data: selectReduce(id, select, fetchers), + isLoading, + isFetching, + isError, + }); - const getMany = (ids: string[]) => - ids.map((id) => selectReduce(id, select, fetchers)); + const getMany = (ids: string[]) => ({ + data: ids.map((id) => selectReduce(id, select, fetchers)), + isLoading, + isFetching, + isError, + }); - return { getOne, getMany }; + return { getOne, getMany, isLoading, isFetching, isError }; }; diff --git a/src/queries/queryKeyFactory.ts b/src/queries/queryKeyFactory.ts index 714b73309..9c43befc3 100644 --- a/src/queries/queryKeyFactory.ts +++ b/src/queries/queryKeyFactory.ts @@ -36,7 +36,7 @@ export abstract class QueryKey { ...this.chainCore(key), 'tradingFee', ]; - static chainCoreLatestProgramId = (key?: number) => [ + static chainCoreLatestProgram = (key?: number) => [ ...this.chainCore(key), 'latestProgramId', ]; @@ -49,5 +49,6 @@ export abstract class QueryKey { static api = () => [...this.v3(), 'api']; static apiPools = () => [...this.api(), 'pools']; + static apiBnt = () => [...this.api(), 'bnt']; static apiFees = () => [...this.api(), 'fees']; } diff --git a/src/services/api/bancorApi/bancorApiV3.ts b/src/services/api/bancorApi/bancorApiV3.ts index e2f8fbc81..39ce7d90d 100644 --- a/src/services/api/bancorApi/bancorApiV3.ts +++ b/src/services/api/bancorApi/bancorApiV3.ts @@ -41,4 +41,54 @@ export abstract class BancorV3Api { const { data } = await axiosInstance.get>('/bnt'); return data.data; }; + + static getPoolsWithBNT = async (): Promise => { + const [bnt, pools] = await Promise.all([this.getBnt(), this.getPools()]); + const bntPool: APIPoolV3 = { + poolDltId: bnt.poolDltId, + poolTokenDltId: bnt.poolTokenDltId, + name: bnt.name, + decimals: bnt.decimals, + tradingLiquidityTKN: { + ...bnt.tradingLiquidity, + tkn: bnt.tradingLiquidity.bnt, + }, + tradingLiquidityBNT: { + bnt: '0', + usd: '0', + eur: '0', + eth: '0', + tkn: '0', + }, + volume24h: { ...bnt.volume24h, tkn: bnt.volume24h.bnt }, + fees24h: { ...bnt.fees24h, tkn: bnt.fees24h.bnt }, + stakedBalance: { ...bnt.stakedBalance, tkn: bnt.stakedBalance.bnt }, + standardRewardsClaimed24h: { + ...bnt.standardRewardsClaimed24h, + tkn: bnt.standardRewardsClaimed24h.bnt, + }, + standardRewardsStaked: { + ...bnt.standardRewardsStaked, + tkn: bnt.standardRewardsStaked.bnt, + }, + volume7d: bnt.volume7d, + fees7d: bnt.fees7d, + standardRewardsProviderJoined: { + bnt: '0', + usd: '0', + eur: '0', + eth: '0', + tkn: '0', + }, + standardRewardsProviderLeft: { + bnt: '0', + usd: '0', + eur: '0', + eth: '0', + tkn: '0', + }, + tradingEnabled: true, + }; + return [bntPool, ...pools]; + }; } From 5321734ccfc2dc11b6865d7b1a396e941ebb9518 Mon Sep 17 00:00:00 2001 From: Jan Langheimer Date: Tue, 19 Jul 2022 11:45:49 +0200 Subject: [PATCH 11/36] refactor vote to for usePoolPick react-query hook --- package.json | 2 + src/App.tsx | 22 +- src/elements/admin/AdminQueryTest.tsx | 9 +- src/elements/earn/pools/TopPools.tsx | 10 +- .../earn/pools/poolsTable/PoolsTable.tsx | 2 + src/elements/vote/VoteCard.tsx | 43 +++ src/elements/vote/VoteCardStep1.tsx | 71 ++++ src/elements/vote/VoteCardStep2.tsx | 20 + src/elements/vote/VoteStakeModal.tsx | 139 +++++++ src/elements/vote/useVoteStakedBalance.ts | 27 ++ src/index.tsx | 12 + src/pages/Vote2.tsx | 18 + src/queries/api/useApiPools.ts | 11 +- src/queries/chain/types.ts | 57 +++ src/queries/chain/useChainPoolByID.ts | 9 - src/queries/chain/useChainPools.ts | 120 ------ src/queries/chain/usePoolPick.ts | 24 +- src/queries/queryKeyFactory.ts | 5 + src/queries/useBalances.ts | 45 ++- src/queries/usePoolsV3.ts | 105 ------ src/queries/useTokens.ts | 4 +- src/queries/useV3ChainData.ts | 354 ------------------ src/router/useRoutesMain.tsx | 4 +- src/services/web3/approval/index.ts | 4 +- src/services/web3/config.ts | 1 + src/services/web3/v3/contractsApi.ts | 7 + yarn.lock | 65 +++- 27 files changed, 555 insertions(+), 635 deletions(-) create mode 100644 src/elements/vote/VoteCard.tsx create mode 100644 src/elements/vote/VoteCardStep1.tsx create mode 100644 src/elements/vote/VoteCardStep2.tsx create mode 100644 src/elements/vote/VoteStakeModal.tsx create mode 100644 src/elements/vote/useVoteStakedBalance.ts create mode 100644 src/pages/Vote2.tsx create mode 100644 src/queries/chain/types.ts delete mode 100644 src/queries/chain/useChainPoolByID.ts delete mode 100644 src/queries/chain/useChainPools.ts delete mode 100644 src/queries/usePoolsV3.ts delete mode 100644 src/queries/useV3ChainData.ts diff --git a/package.json b/package.json index 11f3aaef9..41ef9dded 100644 --- a/package.json +++ b/package.json @@ -8,6 +8,8 @@ "@headlessui/react": "^1.3.0", "@popperjs/core": "^2.9.3", "@reduxjs/toolkit": "^1.6.2", + "@sentry/react": "^7.6.0", + "@sentry/tracing": "^7.6.0", "@types/jest": "^26.0.15", "@types/lodash": "^4.14.170", "@types/node": "^12.0.0", diff --git a/src/App.tsx b/src/App.tsx index aa059a63c..9fead7eff 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -10,10 +10,7 @@ import { setSlippageTolerance, setUsdToggle, } from 'store/user/user'; -import { - Notification, - setNotifications, -} from 'store/notification/notification'; +import { setNotifications } from 'store/notification/notification'; import { store, useAppSelector } from 'store'; import { googleTagManager } from 'services/api/googleTagManager'; import { @@ -30,7 +27,8 @@ import { useWeb3React } from '@web3-react/core'; import { useAutoConnect } from 'services/web3/wallet/hooks'; import { setUser } from 'services/observables/user'; import { BancorRouter } from 'router/BancorRouter'; -import { ErrorBoundary, FallbackProps } from 'react-error-boundary'; +import { FallbackProps } from 'react-error-boundary'; +import * as Sentry from '@sentry/react'; function ErrorFallback({ error }: FallbackProps) { return ( @@ -49,9 +47,10 @@ const handleModeChange = (_: MediaQueryListEvent) => { export const App = () => { const dispatch = useDispatch(); const { chainId, account } = useWeb3React(); + const pathname = window.location.pathname; useAutoConnect(); const unsupportedNetwork = isUnsupportedNetwork(chainId); - const notifications = useAppSelector( + const notifications = useAppSelector( (state) => state.notification.notifications ); @@ -85,11 +84,14 @@ export const App = () => { const slippage = getSlippageToleranceLS(); if (slippage) dispatch(setSlippageTolerance(slippage)); - subscribeToObservables(dispatch); + if (pathname !== '/vote' && pathname !== '/earn') { + subscribeToObservables(dispatch); + } + console.log(pathname); const dark = getDarkModeLS(); dispatch(setDarkMode(dark)); - }, [dispatch]); + }, [dispatch, pathname]); useEffect(() => { setNotificationsLS(notifications); @@ -102,7 +104,7 @@ export const App = () => { return ( // @ts-ignore - + {unsupportedNetwork ? ( @@ -115,6 +117,6 @@ export const App = () => { - + ); }; diff --git a/src/elements/admin/AdminQueryTest.tsx b/src/elements/admin/AdminQueryTest.tsx index 45fa4fcb6..2a85dc69e 100644 --- a/src/elements/admin/AdminQueryTest.tsx +++ b/src/elements/admin/AdminQueryTest.tsx @@ -4,9 +4,14 @@ import { usePoolPick } from 'queries/chain/usePoolPick'; export const AdminQueryTest = () => { const { data: poolIds } = useChainPoolIds(); - const { getMany, isLoading } = usePoolPick(['fees', 'symbol']); + const { getMany } = usePoolPick([ + 'fees', + 'symbol', + 'balance', + 'stakedBalance', + ]); - const { data: all } = getMany(poolIds || []); + const { data: all, isLoading } = getMany(poolIds || []); return (
diff --git a/src/elements/earn/pools/TopPools.tsx b/src/elements/earn/pools/TopPools.tsx index eb063d24f..d8ceebfc1 100644 --- a/src/elements/earn/pools/TopPools.tsx +++ b/src/elements/earn/pools/TopPools.tsx @@ -10,13 +10,18 @@ import { useChainPoolIds } from 'queries/chain/useChainPoolIds'; export const TopPools = () => { const { data: poolIds } = useChainPoolIds(); - const { getMany } = usePoolPick(['symbol', 'apr', 'latestProgram']); + const { getMany } = usePoolPick([ + 'poolDltId', + 'symbol', + 'apr', + 'latestProgram', + ]); const { data, isLoading } = getMany(poolIds || []); const pools = useMemo(() => { return orderBy( - data.filter((p) => p.apr && p.apr.apr7d.total > 0), + data?.filter((p) => p.apr && p.apr.apr7d.total > 0), 'apr.apr7d.total', 'desc' ).slice(0, 20); @@ -38,6 +43,7 @@ export const TopPools = () => { className="flex items-center justify-center min-w-[170px] h-[75px] rounded-[6px] bg-white dark:bg-charcoal border border-silver dark:border-grey transition-all duration-300" > Token Logo diff --git a/src/elements/earn/pools/poolsTable/PoolsTable.tsx b/src/elements/earn/pools/poolsTable/PoolsTable.tsx index be4cf5549..70921c863 100644 --- a/src/elements/earn/pools/poolsTable/PoolsTable.tsx +++ b/src/elements/earn/pools/poolsTable/PoolsTable.tsx @@ -18,6 +18,7 @@ import { useChainPoolIds } from 'queries/chain/useChainPoolIds'; import { PoolNew, usePoolPick } from 'queries/chain/usePoolPick'; const poolKeys = [ + 'poolDltId', 'symbol', 'fees', 'tradingLiquidity', @@ -119,6 +120,7 @@ export const PoolsTable = ({ buttonElement={() => (
Pool Logo diff --git a/src/elements/vote/VoteCard.tsx b/src/elements/vote/VoteCard.tsx new file mode 100644 index 000000000..472262efe --- /dev/null +++ b/src/elements/vote/VoteCard.tsx @@ -0,0 +1,43 @@ +import { Button, ButtonSize } from 'components/button/Button'; +import { ReactNode } from 'react'; + +export interface VoteCardProps { + step: number; + title: string; + description: string; + buttonText: string; + onButtonClick: () => void; + children?: ReactNode; +} + +export const VoteCard = ({ + step, + children, + title, + description, + buttonText, + onButtonClick, +}: VoteCardProps) => { + return ( +
+
+ Step {step} + {title} +
+ +
+ +

{description}

+ +
+ + + +
+ +
{children}
+
+ ); +}; diff --git a/src/elements/vote/VoteCardStep1.tsx b/src/elements/vote/VoteCardStep1.tsx new file mode 100644 index 000000000..3c09ab276 --- /dev/null +++ b/src/elements/vote/VoteCardStep1.tsx @@ -0,0 +1,71 @@ +import { usePoolPick } from 'queries/chain/usePoolPick'; +import { useState } from 'react'; +import { vBntToken } from 'services/web3/config'; +import { useAppSelector } from 'store'; +import { prettifyNumber } from 'utils/helperFunctions'; +import { useVoteStakedBalance } from './useVoteStakedBalance'; +import { VoteCard } from './VoteCard'; +import { VoteStakeModal } from './VoteStakeModal'; + +const loadingElement =
; + +const VoteCardStep1Children = () => { + const account = useAppSelector((state) => state.user.account); + + const stakedBalanceQuery = useVoteStakedBalance(); + const stakedBalance = stakedBalanceQuery.data + ? prettifyNumber(stakedBalanceQuery.data) + ' vBNT' + : '--'; + + const { getOne } = usePoolPick(['balance']); + const vBntQuery = getOne(vBntToken); + + const unstakedBalance = vBntQuery.data?.balance + ? prettifyNumber(vBntQuery.data.balance.tkn) + ' vBNT' + : '--'; + + return ( +
+
+
+ {vBntQuery.isLoading && account ? loadingElement : unstakedBalance} +
+
Unstaked Balance
+
+
+
+ {stakedBalanceQuery.isLoading && account + ? loadingElement + : stakedBalance} +
+
Staked Balance
+
+
+ ); +}; + +const step = 1; +const title = 'Stake your vBNT'; +const buttonText = 'Stake Tokens'; +const description = + 'In order to participate in Bancor governance activities, you should first stake your vBNT tokens. Staked vBNT will be locked for the initial 3 days.'; + +export const VoteCardStep1 = () => { + const [isOpen, setIsOpen] = useState(false); + const onButtonClick = () => setIsOpen(true); + + return ( + <> + + + + + + ); +}; diff --git a/src/elements/vote/VoteCardStep2.tsx b/src/elements/vote/VoteCardStep2.tsx new file mode 100644 index 000000000..d11d9433c --- /dev/null +++ b/src/elements/vote/VoteCardStep2.tsx @@ -0,0 +1,20 @@ +import { VoteCard } from './VoteCard'; + +export const VoteCardStep2 = () => { + const step = 2; + const title = 'Make a Difference'; + const buttonText = 'Vote on Snapshot'; + const onButtonClick = () => {}; + const description = + 'Voting on Bancor DAO is free as it is using the Snapshot off-chain infrastructure. Every user can vote on every available proposal and help shape the future of the Bancor Protocol.'; + + return ( + + ); +}; diff --git a/src/elements/vote/VoteStakeModal.tsx b/src/elements/vote/VoteStakeModal.tsx new file mode 100644 index 000000000..bc283e1fe --- /dev/null +++ b/src/elements/vote/VoteStakeModal.tsx @@ -0,0 +1,139 @@ +import { Button, ButtonSize } from 'components/button/Button'; +import { ModalV3 } from 'components/modal/ModalV3'; +import { usePoolPick } from 'queries/chain/usePoolPick'; +import { useState } from 'react'; +import { useQueryClient } from 'react-query'; +import { getApproval, setApproval } from 'services/web3/approval'; +import { vBntToken } from 'services/web3/config'; +import { ContractsApi } from 'services/web3/v3/contractsApi'; +import { useAppSelector } from 'store'; +import useAsyncEffect from 'use-async-effect'; +import { expandToken } from 'utils/formulas'; + +interface Props { + isOpen: boolean; + setIsOpen: (state: boolean) => void; +} + +const useApproval = (id: string, amount: string, spender: string) => { + const account = useAppSelector((state) => state.user.account); + const { getOne } = usePoolPick(['decimals']); + const query = getOne(id); + const [approvalRequired, setApprovalRequired] = useState(false); + const [isLoadingAllowance, setIsLoadingAllowance] = useState(false); + + const isLoading = query.isLoading || isLoadingAllowance; + + const getAllowance = async () => { + if (!account || !query.data || query.isLoading) { + throw new Error('Error muhhh'); + } + setIsLoadingAllowance(true); + const amountWei = expandToken(amount, query.data.decimals); + + const { isApprovalRequired } = await getApproval( + id, + account, + spender, + amountWei + ); + setApprovalRequired(isApprovalRequired); + setIsLoadingAllowance(false); + }; + + const setAllowance = async (unlimited: boolean = true) => { + if (!account || !query.data || query.isLoading) { + throw new Error('Error'); + } + + const amountWei = expandToken(amount, query.data.decimals); + const res = await setApproval( + id, + account, + spender, + unlimited ? undefined : amountWei, + false + ); + await getAllowance(); + }; + + useAsyncEffect(async () => { + await getAllowance(); + }, [id, amount]); + + return { approvalRequired, isLoading, setAllowance }; +}; + +export const VoteStakeModal = ({ isOpen, setIsOpen }: Props) => { + const queryClient = useQueryClient(); + const { getOne } = usePoolPick(['balance', 'decimals']); + const vBntQuery = getOne(vBntToken); + const balance = vBntQuery.data?.balance ? vBntQuery.data.balance?.tkn : '0'; + const decimals = vBntQuery.data?.decimals; + const account = useAppSelector((state) => state.user.account); + + const { isLoading, approvalRequired, setAllowance } = useApproval( + vBntToken, + balance, + ContractsApi.Governance.contractAddress + ); + + const handleStake = async () => { + try { + if (!decimals) { + throw new Error('No decimals found'); + } + const balanceWei = expandToken(balance, decimals); + const tx = await ContractsApi.Governance.write.stake(balanceWei); + await tx.wait(); + queryClient.invalidateQueries(['chain']); + + console.log('muh'); + } catch (e: any) { + console.error(e.message); + } + }; + + const sendMoney = async () => { + if (!account) { + throw new Error('No decimals found'); + } + try { + const tx = await ContractsApi.Token(vBntToken).write.transfer( + '0xC030109bE8960f938Cf141F2E752D69960C785E4', + expandToken(1, 18) + ); + await tx.wait(); + queryClient.invalidateQueries(['chain', 'balances']); + console.log('muh'); + } catch (e: any) { + console.error(e.message); + } + }; + + return ( + +
+ Unstaked balance: {balance} + {!isLoading && approvalRequired && ( +
+
isLoading: {isLoading ? 'true' : 'false'}
+
approvalRequired: {approvalRequired ? 'true' : 'false'}
+ + +
+ )} + + +
+
+ ); +}; diff --git a/src/elements/vote/useVoteStakedBalance.ts b/src/elements/vote/useVoteStakedBalance.ts new file mode 100644 index 000000000..d8782218f --- /dev/null +++ b/src/elements/vote/useVoteStakedBalance.ts @@ -0,0 +1,27 @@ +import { usePoolPick } from 'queries/chain/usePoolPick'; +import { useQuery } from 'react-query'; +import { vBntToken } from 'services/web3/config'; +import { ContractsApi } from 'services/web3/v3/contractsApi'; +import { useAppSelector } from 'store'; +import { shrinkToken } from 'utils/formulas'; + +export const useVoteStakedBalance = () => { + const { getOne } = usePoolPick(['decimals']); + const vBNT = getOne(vBntToken); + const account = useAppSelector((state) => state.user.account); + + return useQuery( + ['chain', 'vote', 'stakedBalance', account], + async () => { + if (!account) { + throw new Error('Not logged in.'); + } + if (!vBNT.data) { + throw new Error('Data not fetched.'); + } + const staked = await ContractsApi.Governance.read.votesOf(account); + return shrinkToken(staked.toString(), vBNT.data.decimals); + }, + { enabled: !!account && !!vBNT.data } + ); +}; diff --git a/src/index.tsx b/src/index.tsx index ba26d0e57..21ff9c8cc 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -10,6 +10,18 @@ import { Web3ReactProvider } from '@web3-react/core'; import 'styles/index.css'; import { QueryClient, QueryClientProvider } from 'react-query'; import { ReactQueryDevtools } from 'react-query/devtools'; +import * as Sentry from '@sentry/react'; +import { BrowserTracing } from '@sentry/tracing'; + +Sentry.init({ + dsn: 'https://115b6423a34b41b7815a4256cf99dc32@o1317972.ingest.sentry.io/6571500', + integrations: [new BrowserTracing()], + + // Set tracesSampleRate to 1.0 to capture 100% + // of transactions for performance monitoring. + // We recommend adjusting this value in production + tracesSampleRate: 1.0, +}); export const queryClient = new QueryClient({ defaultOptions: { diff --git a/src/pages/Vote2.tsx b/src/pages/Vote2.tsx new file mode 100644 index 000000000..361df1a8b --- /dev/null +++ b/src/pages/Vote2.tsx @@ -0,0 +1,18 @@ +import { Page } from 'components/Page'; +import { VoteCardStep1 } from 'elements/vote/VoteCardStep1'; +import { VoteCardStep2 } from 'elements/vote/VoteCardStep2'; + +export const Vote2 = () => { + const title = 'Vote'; + const subtitle = + 'Bancor is a DAO managed by vBNT stakers who determine the future of the protocol with their proposals.'; + + return ( + +
+ + +
+
+ ); +}; diff --git a/src/queries/api/useApiPools.ts b/src/queries/api/useApiPools.ts index a7f7cb499..eeaa56be6 100644 --- a/src/queries/api/useApiPools.ts +++ b/src/queries/api/useApiPools.ts @@ -12,13 +12,18 @@ export const useApiPools = ({ enabled = true }: Props = {}) => { const query = useQuery( queryKey, async () => { - const pools = await BancorApi.v3.getPoolsWithBNT(); - return new Map(pools.map((p) => [p.poolDltId, p])); + try { + const pools = await BancorApi.v3.getPoolsWithBNT(); + return new Map(pools.map((p) => [p.poolDltId, p])); + } catch (e: any) { + throw new Error( + 'useQuery failed: ' + queryKey.join('-') + ' MSG: ' + e.message + ); + } }, { enabled, useErrorBoundary: true, - onError: (err) => console.error('query failed', queryKey, err), } ); diff --git a/src/queries/chain/types.ts b/src/queries/chain/types.ts new file mode 100644 index 000000000..5c28dd790 --- /dev/null +++ b/src/queries/chain/types.ts @@ -0,0 +1,57 @@ +import { RewardsProgramRaw } from 'services/web3/v3/portfolio/standardStaking'; + +export interface PriceDictionaryV3 { + bnt?: string; + usd?: string; + eur?: string; + eth?: string; + tkn: string; +} + +export interface PoolApr { + tradingFees: number; + standardRewards: number; + autoCompounding: number; + total: number; +} + +export interface PoolV3Chain { + poolDltId: string; + poolTokenDltId: string; + name: string; + symbol: string; + decimals: number; + tradingLiquidity: { + BNT: PriceDictionaryV3; + TKN: PriceDictionaryV3; + }; + stakedBalance: PriceDictionaryV3; + tradingFeePPM: number; + tradingEnabled: boolean; + depositingEnabled: boolean; + programs: RewardsProgramRaw[]; + logoURI: string; + latestProgram?: RewardsProgramRaw; + balance?: { + tkn: string; + bnTkn: string; + }; + volume?: { + volume7d: PriceDictionaryV3; + volume24h: PriceDictionaryV3; + }; + fees?: { + fees7d: PriceDictionaryV3; + fees24h: PriceDictionaryV3; + }; + apr?: { + apr24h: PoolApr; + apr7d: PoolApr; + }; + standardRewards?: { + claimed24h: PriceDictionaryV3; + providerJoined: PriceDictionaryV3; + providerLeft: PriceDictionaryV3; + staked: PriceDictionaryV3; + }; +} diff --git a/src/queries/chain/useChainPoolByID.ts b/src/queries/chain/useChainPoolByID.ts deleted file mode 100644 index 6438a83b2..000000000 --- a/src/queries/chain/useChainPoolByID.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { useChainPools } from 'queries/chain/useChainPools'; - -export const useChainPoolByID = (id: string) => { - const pools = useChainPools(); - - //const data = pools.data?.find((pool) => pool.poolDltId === id); - - //return { ...pools, data }; -}; diff --git a/src/queries/chain/useChainPools.ts b/src/queries/chain/useChainPools.ts deleted file mode 100644 index 0c6b0d947..000000000 --- a/src/queries/chain/useChainPools.ts +++ /dev/null @@ -1,120 +0,0 @@ -import { useChainPoolIds } from 'queries/chain/useChainPoolIds'; -import { useChainTokenSymbol } from 'queries/chain/useChainTokenSymbol'; -import { useChainTokenDecimals } from 'queries/chain/useChainTokenDecimals'; -import { useChainTokenName } from 'queries/chain/useChainTokenName'; -import { useChainTradingEnabled } from 'queries/chain/useChainTradingEnabled'; -import { useChainPoolTokenIds } from 'queries/chain/useChainPoolTokenIds'; -import { useChainTradingLiquidity } from 'queries/chain/useChainTradingLiquidity'; -import { utils } from 'ethers'; -import { useChainDepositingEnabled } from 'queries/chain/useChainDepositingEnabled'; -import { useChainStakedBalance } from 'queries/chain/useChainStakedBalance'; -import { PoolV3Chain } from 'queries/useV3ChainData'; -import { useChainTradingFee } from 'queries/chain/useChainTradingFee'; - -export const useChainPools = () => { - const poolIds = useChainPoolIds(); - const symbols = useChainTokenSymbol(); - const decimals = useChainTokenDecimals(); - const name = useChainTokenName(); - const tradingEnabled = useChainTradingEnabled(); - const poolTokens = useChainPoolTokenIds(); - const tradingLiquidity = useChainTradingLiquidity(); - const depositingEnabled = useChainDepositingEnabled(); - const stakedBalance = useChainStakedBalance(); - const tradingFee = useChainTradingFee(); - - const isLoading = - poolIds.isLoading || - symbols.isLoading || - decimals.isLoading || - tradingEnabled.isLoading || - poolTokens.isLoading || - tradingLiquidity.isLoading || - depositingEnabled.isLoading || - stakedBalance.isLoading || - tradingFee.isLoading || - name.isLoading; - - const isFetching = - poolIds.isFetching || - symbols.isFetching || - decimals.isFetching || - tradingEnabled.isFetching || - poolTokens.isFetching || - tradingLiquidity.isFetching || - depositingEnabled.isFetching || - stakedBalance.isFetching || - tradingFee.isFetching || - name.isFetching; - - const error = - poolIds.error || - symbols.error || - decimals.error || - name.error || - tradingEnabled.error || - tradingLiquidity.error || - depositingEnabled.error || - stakedBalance.error || - tradingFee.error || - poolTokens.error; - - const _buildPool = (id: string): PoolV3Chain | undefined => { - if ( - !poolIds.data || - !symbols.data || - !decimals.data || - !name.data || - !tradingEnabled.data || - !tradingLiquidity.data || - !depositingEnabled.data || - !stakedBalance.data || - !tradingFee.data || - !poolTokens.data - ) { - return undefined; - } - - const tokenDecimals = decimals.data.get(id)!; - const tokenTradingLiquidity = tradingLiquidity.data.get(id)!; - - const pool: PoolV3Chain = { - poolDltId: id, - poolTokenDltId: poolTokens.data.get(id)!, - symbol: symbols.data.get(id)!, - decimals: tokenDecimals, - name: name.data.get(id)!, - tradingFeePPM: tradingFee.data.get(id)!, - tradingEnabled: tradingEnabled.data.get(id)!, - depositingEnabled: depositingEnabled.data.get(id)!, - tradingLiquidity: { - BNT: { - bnt: utils.formatUnits( - tokenTradingLiquidity.bntTradingLiquidity, - tokenDecimals - ), - tkn: utils.formatUnits(tokenTradingLiquidity.bntTradingLiquidity, 18), - }, - TKN: { - tkn: utils.formatUnits( - tokenTradingLiquidity.baseTokenTradingLiquidity, - tokenDecimals - ), - }, - }, - stakedBalance: { - tkn: utils.formatUnits(stakedBalance.data.get(id)!, tokenDecimals), - }, - programs: [], - logoURI: - 'https://d1wmp5nysbq9xl.cloudfront.net/ethereum/tokens/' + - id.toLowerCase() + - '.svg', - }; - return pool; - }; - - const getPoolByID = (id: string) => _buildPool(id); - - return { isLoading, error, isFetching, getPoolByID }; -}; diff --git a/src/queries/chain/usePoolPick.ts b/src/queries/chain/usePoolPick.ts index 941962579..43b35f4c1 100644 --- a/src/queries/chain/usePoolPick.ts +++ b/src/queries/chain/usePoolPick.ts @@ -1,4 +1,3 @@ -import { PoolV3Chain } from 'queries/useV3ChainData'; import { useChainTokenSymbol } from 'queries/chain/useChainTokenSymbol'; import { useChainTokenDecimals } from 'queries/chain/useChainTokenDecimals'; import { useChainPoolTokenIds } from 'queries/chain/useChainPoolTokenIds'; @@ -10,16 +9,12 @@ import { useApiFees } from 'queries/api/useApiFees'; import { useApiVolume } from 'queries/api/useApiVolume'; import { useApiStakedBalance } from 'queries/api/useApiStakedBalance'; import { useChainLatestProgram } from 'queries/chain/useChainLatestProgram'; +import { PoolV3Chain } from './types'; +import { useBalances } from 'queries/useBalances'; export type PoolNew = Omit< PoolV3Chain, - | 'name' - | 'logoURI' - | 'standardRewards' - | 'tradingFeePPM' - | 'depositingEnabled' - | 'tknBalance' - | 'bnTknBalance' + 'name' | 'logoURI' | 'standardRewards' | 'tradingFeePPM' | 'depositingEnabled' >; export type PoolKey = keyof PoolNew; @@ -83,6 +78,10 @@ const useFetchers = (select: PoolKey[]) => { enabled: set.has('stakedBalance'), }); + const balance = useBalances({ + enabled: set.has('balance'), + }); + const fetchers: Fetchers = { poolDltId: { getByID: (id: string) => id, @@ -101,6 +100,7 @@ const useFetchers = (select: PoolKey[]) => { volume, stakedBalance, latestProgram, + balance, }; const isLoading = select.some((res) => fetchers[res].isLoading); @@ -124,15 +124,19 @@ const selectReduce = ( export const usePoolPick = (select: T) => { const { fetchers, isLoading, isFetching, isError } = useFetchers(select); + const isUndefined = isLoading || isError; + const getOne = (id: string) => ({ - data: selectReduce(id, select, fetchers), + data: !isUndefined ? selectReduce(id, select, fetchers) : undefined, isLoading, isFetching, isError, }); const getMany = (ids: string[]) => ({ - data: ids.map((id) => selectReduce(id, select, fetchers)), + data: !isUndefined + ? ids.map((id) => selectReduce(id, select, fetchers)) + : undefined, isLoading, isFetching, isError, diff --git a/src/queries/queryKeyFactory.ts b/src/queries/queryKeyFactory.ts index 9c43befc3..bad4af192 100644 --- a/src/queries/queryKeyFactory.ts +++ b/src/queries/queryKeyFactory.ts @@ -44,6 +44,11 @@ export abstract class QueryKey { ...this.chainCore(key), 'programs', ]; + static chainVoteBalance = (user?: string) => [ + ...this.chainCore(), + 'vote', + user, + ]; static chainPools = () => [...this.chain(), 'pools']; static chainPoolsByID = (key?: string) => [...this.chainPools(), key]; diff --git a/src/queries/useBalances.ts b/src/queries/useBalances.ts index 48120c6c1..347efbc3e 100644 --- a/src/queries/useBalances.ts +++ b/src/queries/useBalances.ts @@ -1,28 +1,47 @@ import { useQuery } from 'react-query'; import { fetchTokenBalanceMulticall } from 'services/web3/token/token'; import { useAppSelector } from 'store/index'; -import { useV3ChainData } from 'queries/useV3ChainData'; import { ethToken } from 'services/web3/config'; +import { useChainPoolIds } from './chain/useChainPoolIds'; +import { useChainPoolTokenIds } from './chain/useChainPoolTokenIds'; +import { useChainTokenDecimals } from './chain/useChainTokenDecimals'; +import { shrinkToken } from 'utils/formulas'; -export const useBalances = () => { +interface Props { + enabled?: boolean; +} + +export const useBalances = ({ enabled = true }: Props = {}) => { const user = useAppSelector((state) => state.user.account); - const { data: pools } = useV3ChainData(); - const tknIds: string[] = []; - const bnTknIds: string[] = []; + const { data: poolIds } = useChainPoolIds(); + const { data: poolTokenIds } = useChainPoolTokenIds({ enabled }); + const { data: decimals } = useChainTokenDecimals({ enabled }); - !!pools && - pools.forEach((p) => { - tknIds.push(p.poolDltId); - bnTknIds.push(p.poolTokenDltId); - }); + const tknIds = poolIds ?? []; + const bnTknIds = poolTokenIds ? Array.from(poolTokenIds.values()) : []; - return useQuery | undefined>( - ['chain', 'v3', 'balances', user], + const query = useQuery( + ['chain', 'balances', user], () => fetchTokenBalanceMulticall( [...tknIds, ...bnTknIds].filter((id) => id !== ethToken), user! ), - { enabled: !!user && !!pools, useErrorBoundary: true } + { + enabled: !!user && !!poolIds && !!poolTokenIds && !!decimals && enabled, + useErrorBoundary: false, + } ); + + const getByID = (id: string) => { + if (!user) return undefined; + const poolTokenId = poolTokenIds?.get(id) ?? ''; + const dec = decimals?.get(id) ?? 0; + return { + tkn: shrinkToken(query.data?.get(id) ?? '0', dec), + bnTkn: shrinkToken(query.data?.get(poolTokenId) ?? '0', dec), + }; + }; + + return { ...query, getByID, isLoading: query.isLoading && query.isFetching }; }; diff --git a/src/queries/usePoolsV3.ts b/src/queries/usePoolsV3.ts deleted file mode 100644 index ac1db8ba2..000000000 --- a/src/queries/usePoolsV3.ts +++ /dev/null @@ -1,105 +0,0 @@ -import { PoolV3Chain, useV3ChainData } from 'queries/useV3ChainData'; -import { useApiPoolsV3 } from 'queries/useApiPoolsV3'; -import { useMemo } from 'react'; -import { toBigNumber } from 'utils/helperFunctions'; -import { calcApr } from 'utils/formulas'; -import { standardsRewardsAPR } from 'services/observables/pools'; -import { useApiTokensV3 } from 'queries/useApiTokensV3'; -import { useBalances } from 'queries/useBalances'; -import { utils } from 'ethers'; - -export const usePoolsV3 = () => { - const chain = useV3ChainData(); - const apiPools = useApiPoolsV3(); - const apiTokens = useApiTokensV3(); - const balances = useBalances(); - - const data = useMemo(() => { - if (!chain.data) return undefined; - const apiPoolsMap = new Map(apiPools.data?.map((p) => [p.poolDltId, p])); - const apiTokensMap = new Map(apiTokens.data?.map((p) => [p.dltId, p])); - return chain.data.map((x) => { - const tknBalance = balances.data?.get && balances.data?.get(x.poolDltId); - const bnTknBalance = - balances.data?.get && balances.data?.get(x.poolTokenDltId); - const pool: PoolV3Chain = { - ...x, - tknBalance: tknBalance - ? utils.formatUnits(tknBalance, x.decimals) - : undefined, - bnTknBalance: bnTknBalance - ? utils.formatUnits(bnTknBalance, x.decimals) - : undefined, - }; - const apiPool = apiPoolsMap?.get(x.poolDltId); - const apiToken = apiTokensMap?.get(x.poolDltId); - if (!apiPool || !apiToken) { - return pool; - } - - // FIXES STAKED BALANCE = 0 WHEN TRADING ENABLED = FALSE - const stakedBalance = { ...apiPool.stakedBalance }; - if ( - apiPool.tradingEnabled === false && - toBigNumber(stakedBalance.usd).isZero() - ) { - stakedBalance.usd = toBigNumber(apiPool.stakedBalance.tkn) - .times(apiToken.rate.usd) - .toString(); - } - - // Calculate APR - const standardRewardsApr24H = standardsRewardsAPR(apiPool, pool.programs); - const standardRewardsApr7d = standardsRewardsAPR(apiPool, pool.programs); - - const tradingFeesApr24h = calcApr(apiPool.fees24h.usd, stakedBalance.usd); - const tradingFeesApr7d = calcApr( - apiPool.fees7d.usd, - stakedBalance.usd, - true - ); - - // TODO - add values once available - const autoCompoundingApr24H = 0; - const autoCompoundingApr7d = 0; - - const totalApr24H = toBigNumber(tradingFeesApr24h) - .plus(standardRewardsApr24H) - .plus(autoCompoundingApr24H) - .toNumber(); - - const totalApr7d = toBigNumber(tradingFeesApr7d) - .plus(autoCompoundingApr7d) - .plus(standardRewardsApr7d) - .toNumber(); - return { - ...pool, - ...{ - stakedBalance, - fees24h: apiPool.fees24h, - fees7d: apiPool.fees7d, - volume7d: apiPool.volume7d, - volume24h: apiPool.volume24h, - standardRewardsStaked: apiPool.standardRewardsStaked, - standardRewardsClaimed24h: apiPool.standardRewardsClaimed24h, - standardRewardsProviderJoined: apiPool.standardRewardsProviderJoined, - standardRewardsProviderLeft: apiPool.standardRewardsProviderLeft, - apr24h: { - tradingFees: tradingFeesApr24h, - standardRewards: standardRewardsApr24H, - autoCompounding: autoCompoundingApr24H, - total: totalApr24H, - }, - apr7d: { - tradingFees: tradingFeesApr7d, - standardRewards: standardRewardsApr7d, - autoCompounding: autoCompoundingApr7d, - total: totalApr7d, - }, - }, - }; - }); - }, [apiPools.data, apiTokens.data, balances?.data, chain.data]); - - return { ...chain, data }; -}; diff --git a/src/queries/useTokens.ts b/src/queries/useTokens.ts index a964325eb..fb0c8d1e2 100644 --- a/src/queries/useTokens.ts +++ b/src/queries/useTokens.ts @@ -1,10 +1,10 @@ import { useQuery } from 'react-query'; import { fetchTokenBalanceMulticall } from 'services/web3/token/token'; import { useApiPoolsV3 } from 'queries/useApiPoolsV3'; -import { useWeb3React } from '@web3-react/core'; +import { useAppSelector } from 'store'; export const useTokens = () => { - const { account } = useWeb3React(); + const account = useAppSelector((state) => state.user.account); const { data: pools } = useApiPoolsV3(); const ids = pools ? pools.map((p) => p.poolDltId) : []; diff --git a/src/queries/useV3ChainData.ts b/src/queries/useV3ChainData.ts deleted file mode 100644 index e0d5bd3cb..000000000 --- a/src/queries/useV3ChainData.ts +++ /dev/null @@ -1,354 +0,0 @@ -import { useQuery } from 'react-query'; -import { fetchMulticall, MultiCall } from 'services/web3/multicall/multicall'; -import { ContractsApi } from 'services/web3/v3/contractsApi'; -import { ethToken } from 'services/web3/config'; -import { BigNumber, utils } from 'ethers'; -import { RewardsProgramRaw } from 'services/web3/v3/portfolio/standardStaking'; -import dayjs from 'dayjs'; - -export interface PriceDictionaryV3 { - bnt?: string; - usd?: string; - eur?: string; - eth?: string; - tkn: string; -} - -export interface PoolApr { - tradingFees: number; - standardRewards: number; - autoCompounding: number; - total: number; -} - -export interface PoolV3Chain { - poolDltId: string; - poolTokenDltId: string; - name: string; - symbol: string; - decimals: number; - tradingLiquidity: { - BNT: PriceDictionaryV3; - TKN: PriceDictionaryV3; - }; - stakedBalance: PriceDictionaryV3; - tradingFeePPM: number; - tradingEnabled: boolean; - depositingEnabled: boolean; - programs: RewardsProgramRaw[]; - logoURI: string; - latestProgram?: RewardsProgramRaw; - tknBalance?: string; - bnTknBalance?: string; - volume?: { - volume7d: PriceDictionaryV3; - volume24h: PriceDictionaryV3; - }; - fees?: { - fees7d: PriceDictionaryV3; - fees24h: PriceDictionaryV3; - }; - apr?: { - apr24h: PoolApr; - apr7d: PoolApr; - }; - standardRewards?: { - claimed24h: PriceDictionaryV3; - providerJoined: PriceDictionaryV3; - providerLeft: PriceDictionaryV3; - staked: PriceDictionaryV3; - }; -} - -const fetchEthData = async (): Promise => { - const ethDataCalls: MultiCall[] = [ - { - contractAddress: ContractsApi.BancorNetworkInfo.contractAddress, - interface: ContractsApi.BancorNetworkInfo.read.interface, - methodName: 'poolToken', - methodParameters: [ethToken], - }, - { - contractAddress: ContractsApi.BancorNetworkInfo.contractAddress, - interface: ContractsApi.BancorNetworkInfo.read.interface, - methodName: 'tradingLiquidity', - methodParameters: [ethToken], - }, - { - contractAddress: ContractsApi.BancorNetworkInfo.contractAddress, - interface: ContractsApi.BancorNetworkInfo.read.interface, - methodName: 'tradingEnabled', - methodParameters: [ethToken], - }, - { - contractAddress: ContractsApi.BancorNetworkInfo.contractAddress, - interface: ContractsApi.BancorNetworkInfo.read.interface, - methodName: 'depositingEnabled', - methodParameters: [ethToken], - }, - { - contractAddress: ContractsApi.BancorNetworkInfo.contractAddress, - interface: ContractsApi.BancorNetworkInfo.read.interface, - methodName: 'stakedBalance', - methodParameters: [ethToken], - }, - { - contractAddress: ContractsApi.BancorNetworkInfo.contractAddress, - interface: ContractsApi.BancorNetworkInfo.read.interface, - methodName: 'tradingFeePPM', - methodParameters: [ethToken], - }, - { - contractAddress: ContractsApi.StandardRewards.contractAddress, - interface: ContractsApi.StandardRewards.read.interface, - methodName: 'latestProgramId', - methodParameters: [ethToken], - }, - ]; - const res = await fetchMulticall(ethDataCalls); - - return { - poolDltId: ethToken, - name: 'Ethereum', - symbol: 'ETH', - poolTokenDltId: res[0], - decimals: 18, - tradingEnabled: res[2], - tradingLiquidity: { - BNT: { - bnt: utils.formatUnits(res[1].bntTradingLiquidity, 18), - tkn: utils.formatUnits(res[1].bntTradingLiquidity, 18), - }, - TKN: { - tkn: utils.formatUnits(res[1].baseTokenTradingLiquidity, 18), - }, - }, - depositingEnabled: res[3], - stakedBalance: { tkn: utils.formatUnits(res[4], 18) }, - tradingFeePPM: res[5], - programs: [], - logoURI: - 'https://d1wmp5nysbq9xl.cloudfront.net/ethereum/tokens/' + - ethToken.toLowerCase() + - '.svg', - }; -}; - -const fetchChainV3Programs = async ( - ids: BigNumber[] -): Promise => { - const programs = await ContractsApi.StandardRewards.read.programs(ids); - return programs.map((program) => { - const data: RewardsProgramRaw = { - id: program.id.toString(), - pool: program.pool, - poolToken: program.poolToken, - rewardsToken: program.rewardsToken, - rewardRate: program.rewardRate.toString(), - isEnabled: program.isEnabled, - startTime: program.startTime, - endTime: program.endTime, - isActive: - program.isEnabled && - program.startTime <= dayjs.utc().unix() && - program.endTime >= dayjs.utc().unix(), - }; - return data; - }); -}; - -const fetchV3ChainData = async (): Promise => { - const [liquidityPools, programIds] = await Promise.all([ - ContractsApi.BancorNetwork.read.liquidityPools(), - ContractsApi.StandardRewards.read.programIds(), - ]); - - const pools = liquidityPools.filter((id) => id !== ethToken); - - const poolTokensCalls: MultiCall[] = []; - const tokenDecimalsCalls: MultiCall[] = []; - const tokenNamesCalls: MultiCall[] = []; - const tokenSymbolCalls: MultiCall[] = []; - const tradingLiquidityCalls: MultiCall[] = []; - const tradingEnabledCalls: MultiCall[] = []; - const depositingEnabledCalls: MultiCall[] = []; - const stakedBalanceCalls: MultiCall[] = []; - const tradingFeePPMCalls: MultiCall[] = []; - const latestProgramIdCalls: MultiCall[] = []; - - pools.forEach((id) => { - poolTokensCalls.push({ - contractAddress: ContractsApi.BancorNetworkInfo.contractAddress, - interface: ContractsApi.BancorNetworkInfo.read.interface, - methodName: 'poolToken', - methodParameters: [id], - }); - tokenDecimalsCalls.push({ - contractAddress: id, - interface: ContractsApi.Token(id).read.interface, - methodName: 'decimals', - methodParameters: [], - }); - tokenNamesCalls.push({ - contractAddress: id, - interface: ContractsApi.Token(id).read.interface, - methodName: 'name', - methodParameters: [], - }); - tokenSymbolCalls.push({ - contractAddress: id, - interface: ContractsApi.Token(id).read.interface, - methodName: 'symbol', - methodParameters: [], - }); - tradingLiquidityCalls.push({ - contractAddress: ContractsApi.BancorNetworkInfo.contractAddress, - interface: ContractsApi.BancorNetworkInfo.read.interface, - methodName: 'tradingLiquidity', - methodParameters: [id], - }); - tradingEnabledCalls.push({ - contractAddress: ContractsApi.BancorNetworkInfo.contractAddress, - interface: ContractsApi.BancorNetworkInfo.read.interface, - methodName: 'tradingEnabled', - methodParameters: [id], - }); - depositingEnabledCalls.push({ - contractAddress: ContractsApi.BancorNetworkInfo.contractAddress, - interface: ContractsApi.BancorNetworkInfo.read.interface, - methodName: 'depositingEnabled', - methodParameters: [id], - }); - stakedBalanceCalls.push({ - contractAddress: ContractsApi.BancorNetworkInfo.contractAddress, - interface: ContractsApi.BancorNetworkInfo.read.interface, - methodName: 'stakedBalance', - methodParameters: [id], - }); - tradingFeePPMCalls.push({ - contractAddress: ContractsApi.BancorNetworkInfo.contractAddress, - interface: ContractsApi.BancorNetworkInfo.read.interface, - methodName: 'tradingFeePPM', - methodParameters: [id], - }); - latestProgramIdCalls.push({ - contractAddress: ContractsApi.StandardRewards.contractAddress, - interface: ContractsApi.StandardRewards.read.interface, - methodName: 'latestProgramId', - methodParameters: [id], - }); - }); - - const [ - poolTokens, - tokenDecimals, - tokenNames, - tokenSymbols, - tradingEnabled, - tradingLiquidity, - depositingEnabled, - stakedBalance, - tradingFeePPM, - latestProgramIds, - ethData, - programs, - ] = await Promise.all([ - fetchMulticall(poolTokensCalls), - fetchMulticall(tokenDecimalsCalls), - fetchMulticall(tokenNamesCalls, true), - fetchMulticall(tokenSymbolCalls, true), - fetchMulticall(tradingEnabledCalls), - fetchMulticall(tradingLiquidityCalls), - fetchMulticall(depositingEnabledCalls), - fetchMulticall(stakedBalanceCalls), - fetchMulticall(tradingFeePPMCalls), - fetchMulticall(latestProgramIdCalls), - fetchEthData(), - fetchChainV3Programs(programIds), - ]); - - const data: PoolV3Chain[] = pools.map((id, i) => ({ - poolDltId: id, - name: tokenNames[i], - symbol: tokenSymbols[i], - poolTokenDltId: poolTokens[i], - decimals: tokenDecimals[i], - tradingEnabled: tradingEnabled[i], - tradingLiquidity: { - BNT: { - bnt: utils.formatUnits( - tradingLiquidity[i].baseTokenTradingLiquidity, - tokenDecimals[i] - ), - tkn: utils.formatUnits(tradingLiquidity[i].bntTradingLiquidity, 18), - }, - TKN: { - tkn: utils.formatUnits( - tradingLiquidity[i].baseTokenTradingLiquidity, - tokenDecimals[i] - ), - }, - }, - depositingEnabled: depositingEnabled[i], - stakedBalance: { - tkn: utils.formatUnits(stakedBalance[i], tokenDecimals[i]), - }, - tradingFeePPM: tradingFeePPM[i], - latestProgram: latestProgramIds[i] - ? programs.find((p) => p.pool === id) - : undefined, - programs: programs.filter((p) => p.pool === id), - logoURI: - 'https://d1wmp5nysbq9xl.cloudfront.net/ethereum/tokens/' + - id.toLowerCase() + - '.svg', - })); - data.push(ethData); - return data; -}; - -const fetchV3ChainPoolTokens = async ( - poolIds: string[] -): Promise> => { - const calls: MultiCall[] = poolIds.map((id) => ({ - contractAddress: ContractsApi.BancorNetworkInfo.contractAddress, - interface: ContractsApi.BancorNetworkInfo.read.interface, - methodName: 'poolToken', - methodParameters: [id], - })); - - const data = await fetchMulticall(calls); - - return new Map(data.map((id, i) => [poolIds[i], id])); -}; - -export const useV3ChainPoolIds = () => { - return useQuery( - ['chain', 'v3', 'poolIds'], - () => ContractsApi.BancorNetwork.read.liquidityPools(), - { - refetchInterval: 144 * 1000, - staleTime: 88 * 1000, - } - ); -}; - -export const useV3ChainPoolTokenIds = () => { - const { data: poolIds } = useV3ChainPoolIds(); - return useQuery( - ['chain', 'v3', 'poolTokenIds'], - () => fetchV3ChainPoolTokens(poolIds!), - { - enabled: poolIds !== undefined, - refetchInterval: 144 * 1000, - staleTime: 88 * 1000, - } - ); -}; - -export const useV3ChainData = () => { - return useQuery(['chain', 'v3', 'pools'], fetchV3ChainData, { - refetchInterval: 144 * 1000, - staleTime: 88 * 1000, - }); -}; diff --git a/src/router/useRoutesMain.tsx b/src/router/useRoutesMain.tsx index 4bc1d7351..ddd70ce06 100644 --- a/src/router/useRoutesMain.tsx +++ b/src/router/useRoutesMain.tsx @@ -1,7 +1,7 @@ import { Navigate, RouteObject } from 'react-router-dom'; import { Tokens } from 'pages/Tokens'; import { Fiat } from 'pages/Fiat'; -import { Vote } from 'pages/Vote'; +import { Vote2 } from 'pages/Vote2'; import { TermsOfUse } from 'pages/TermsOfUse'; import { PrivacyPolicy } from 'pages/PrivacyPolicy'; import { NotFound } from 'pages/NotFound'; @@ -34,7 +34,7 @@ export const useRoutesMain = (): RouteObject[] => { }, { path: BancorURL.vote, - element: , + element: , }, { path: BancorURL.termsOfUse, diff --git a/src/services/web3/approval/index.ts b/src/services/web3/approval/index.ts index 5a875b1b9..d9efa7f2f 100644 --- a/src/services/web3/approval/index.ts +++ b/src/services/web3/approval/index.ts @@ -28,7 +28,7 @@ export enum ApprovalContract { Governance, } -const getApproval = async ( +export const getApproval = async ( token: string, user: string, spender: string, @@ -47,7 +47,7 @@ const getApproval = async ( return { allowanceWei, isApprovalRequired }; }; -const setApproval = async ( +export const setApproval = async ( token: string, user: string, spender: string, diff --git a/src/services/web3/config.ts b/src/services/web3/config.ts index 90c99ae20..35d789ae3 100644 --- a/src/services/web3/config.ts +++ b/src/services/web3/config.ts @@ -14,6 +14,7 @@ export interface EthNetworkVariables { } export const bntToken: string = '0x1F573D6Fb3F13d689FF844B4cE37794d79a7FF1C'; +export const vBntToken: string = '0x48Fb253446873234F2fEBbF9BdeAA72d9d387f94'; export const systemStore: string = '0xc4C5634De585d43DaEC8fA2a6Fb6286cd9B87131'; export const ethToken: string = '0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE'; export const zeroAddress: string = '0x0000000000000000000000000000000000000000'; diff --git a/src/services/web3/v3/contractsApi.ts b/src/services/web3/v3/contractsApi.ts index 8c8a07df2..592ac30d2 100644 --- a/src/services/web3/v3/contractsApi.ts +++ b/src/services/web3/v3/contractsApi.ts @@ -19,6 +19,8 @@ import { BancorPortal__factory, Multicall, Multicall__factory, + Governance, + Governance__factory, } from 'services/web3/abis/types'; import { web3, writeWeb3 } from 'services/web3/index'; import { providers } from 'ethers'; @@ -117,6 +119,11 @@ export abstract class ContractsApi { Multicall__factory ); + static Governance = new BancorContract( + '0x892f481bd6e9d7d26ae365211d9b45175d5d00e4', + Governance__factory + ); + static Token = (tokenAddress: string) => { return new BancorContract(tokenAddress, Token__factory); }; diff --git a/yarn.lock b/yarn.lock index 904587de3..863421c59 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2351,6 +2351,69 @@ resolved "https://registry.yarnpkg.com/@rushstack/eslint-patch/-/eslint-patch-1.1.4.tgz#0c8b74c50f29ee44f423f7416829c0bf8bb5eb27" integrity sha512-LwzQKA4vzIct1zNZzBmRKI9QuNpLgTQMEjsQLf3BXuGYb3QPTP4Yjf6mkdX+X1mYttZ808QpOwAzZjv28kq7DA== +"@sentry/browser@7.6.0": + version "7.6.0" + resolved "https://registry.yarnpkg.com/@sentry/browser/-/browser-7.6.0.tgz#54bcd52747c40b2656d62d53541037a5724f3296" + integrity sha512-1gdvV8RtTnNFyc790t49MAgFuHAP43NEZvdQOMw5KFnDwSGYFqfBtvJ8tUm125UPbi2fghBryO9M1gfIWboKUg== + dependencies: + "@sentry/core" "7.6.0" + "@sentry/types" "7.6.0" + "@sentry/utils" "7.6.0" + tslib "^1.9.3" + +"@sentry/core@7.6.0": + version "7.6.0" + resolved "https://registry.yarnpkg.com/@sentry/core/-/core-7.6.0.tgz#5e5efd54af7b63957ac4d446fb5a69af33da3e51" + integrity sha512-vXIuUZbHVSAXh2xZ3NyXYXqVvVQSbGEpgtQxLutwocvD88JFK6aZqO+WQG69GY1b1fKSeE9faEDDS6WGAi46mQ== + dependencies: + "@sentry/hub" "7.6.0" + "@sentry/types" "7.6.0" + "@sentry/utils" "7.6.0" + tslib "^1.9.3" + +"@sentry/hub@7.6.0": + version "7.6.0" + resolved "https://registry.yarnpkg.com/@sentry/hub/-/hub-7.6.0.tgz#69a0d11e50ee61f3f93665948c4acbe56a9ce676" + integrity sha512-TbieNZInpnR5STXykT1zXoKVAsm8ju1RZyzMqYR8nzURbjlMVVEzFRglNY1Ap5MRkbEuYpAc6zUvgLQe8b6Q3w== + dependencies: + "@sentry/types" "7.6.0" + "@sentry/utils" "7.6.0" + tslib "^1.9.3" + +"@sentry/react@^7.6.0": + version "7.6.0" + resolved "https://registry.yarnpkg.com/@sentry/react/-/react-7.6.0.tgz#349596f64da8eb9370c19dde0febfd2dbaeef682" + integrity sha512-R5xBZUxSjNLpeq1dlW22JudX5x1FhzfazSVEQ9TXJEZM2ufC1XP/JkO7bRJFad1JjIzSWqlez8Wm13EnbV9wRg== + dependencies: + "@sentry/browser" "7.6.0" + "@sentry/types" "7.6.0" + "@sentry/utils" "7.6.0" + hoist-non-react-statics "^3.3.2" + tslib "^1.9.3" + +"@sentry/tracing@^7.6.0": + version "7.6.0" + resolved "https://registry.yarnpkg.com/@sentry/tracing/-/tracing-7.6.0.tgz#2b34992e7a003c40393a4aab4b917db2712a1586" + integrity sha512-ydlIk8FpuXiQm3Y0cLwXMOUYv5UtniP8ylWw3ix0sF5sTpJWSaC/g8P8yrzkYV+pm28kde5qfE3nocGhpwxZcA== + dependencies: + "@sentry/hub" "7.6.0" + "@sentry/types" "7.6.0" + "@sentry/utils" "7.6.0" + tslib "^1.9.3" + +"@sentry/types@7.6.0": + version "7.6.0" + resolved "https://registry.yarnpkg.com/@sentry/types/-/types-7.6.0.tgz#7352bcc5621177ceefb18733d0a6b0cdb0307822" + integrity sha512-POimbDwr9tmHSKksJTXe5VQpvjkFO4/UWUptigwqf8684rkS7Ie2BT2uyp5GD2EgYFf0BwUOWi98FTYTvUGT+Q== + +"@sentry/utils@7.6.0": + version "7.6.0" + resolved "https://registry.yarnpkg.com/@sentry/utils/-/utils-7.6.0.tgz#50b44fd9b06686a358ef2c7c0fd3b80970e1f9ee" + integrity sha512-p0Byi6hgawp/sBMY88RY8OmkiAR2jxbjnl8gSo+y3YEu+KeXBUxXMBsI7YeW+1lSb6z8DGhUAOBszTeI4wAr2w== + dependencies: + "@sentry/types" "7.6.0" + tslib "^1.9.3" + "@sinclair/typebox@^0.23.3": version "0.23.5" resolved "https://registry.yarnpkg.com/@sinclair/typebox/-/typebox-0.23.5.tgz#93f7b9f4e3285a7a9ade7557d9a8d36809cbc47d" @@ -16326,7 +16389,7 @@ tsconfig-paths@^3.14.1: minimist "^1.2.6" strip-bom "^3.0.0" -tslib@^1.8.1, tslib@^1.9.0: +tslib@^1.8.1, tslib@^1.9.0, tslib@^1.9.3: version "1.14.1" resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== From ca2cd9a5ec52040b451d651c16e5f5c6db36a788 Mon Sep 17 00:00:00 2001 From: Jan Langheimer Date: Tue, 19 Jul 2022 11:47:43 +0200 Subject: [PATCH 12/36] remove unneeded zod dependency --- package.json | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/package.json b/package.json index 41ef9dded..a31af508e 100644 --- a/package.json +++ b/package.json @@ -53,18 +53,17 @@ "source-map-explorer": "^2.5.2", "swiper": "^7.4.1", "use-async-effect": "^2.2.3", - "web-vitals": "^1.0.1", - "zod": "^3.17.3" + "web-vitals": "^1.0.1" }, "devDependencies": { "@faker-js/faker": "^6.0.0-alpha.5", "@storybook/addon-actions": "6.5.9", "@storybook/addon-essentials": "6.5.9", "@storybook/addon-links": "6.5.9", - "@storybook/builder-webpack5": "6.5.9", - "@storybook/manager-webpack5": "6.5.9", "@storybook/node-logger": "6.5.9", "@storybook/preset-create-react-app": "4.1.2", + "@storybook/builder-webpack5": "6.5.9", + "@storybook/manager-webpack5": "6.5.9", "@storybook/react": "6.5.9", "@typechain/ethers-v5": "^8.0.2", "@types/json-bigint": "^1.0.0", From c8b1573d98cc1c427f5615273f1e47e712721e0b Mon Sep 17 00:00:00 2001 From: Jan Langheimer Date: Tue, 19 Jul 2022 11:47:49 +0200 Subject: [PATCH 13/36] remove unneeded zod dependency --- yarn.lock | 5 ----- 1 file changed, 5 deletions(-) diff --git a/yarn.lock b/yarn.lock index 863421c59..d5f4e533d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -17916,11 +17916,6 @@ yocto-queue@^0.1.0: resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b" integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q== -zod@^3.17.3: - version "3.17.3" - resolved "https://registry.yarnpkg.com/zod/-/zod-3.17.3.tgz#86abbc670ff0063a4588d85a4dcc917d6e4af2ba" - integrity sha512-4oKP5zvG6GGbMlqBkI5FESOAweldEhSOZ6LI6cG+JzUT7ofj1ZOC0PJudpQOpT1iqOFpYYtX5Pw0+o403y4bcg== - zwitch@^1.0.0: version "1.0.5" resolved "https://registry.yarnpkg.com/zwitch/-/zwitch-1.0.5.tgz#d11d7381ffed16b742f6af7b3f223d5cd9fe9920" From f2a73a59c23276e2b6598aaa3884cfeb9709c3a7 Mon Sep 17 00:00:00 2001 From: Jan Langheimer Date: Tue, 19 Jul 2022 11:49:49 +0200 Subject: [PATCH 14/36] remove unneeded error boundry component --- .../ErrorBoundary/ErrorBoundary.tsx | 35 ------------------- 1 file changed, 35 deletions(-) delete mode 100644 src/components/ErrorBoundary/ErrorBoundary.tsx diff --git a/src/components/ErrorBoundary/ErrorBoundary.tsx b/src/components/ErrorBoundary/ErrorBoundary.tsx deleted file mode 100644 index a4647cdef..000000000 --- a/src/components/ErrorBoundary/ErrorBoundary.tsx +++ /dev/null @@ -1,35 +0,0 @@ -import React, { Component, ErrorInfo, ReactNode } from 'react'; - -interface Props { - errorMsg?: string; - children?: ReactNode; -} - -interface State { - hasError: boolean; -} - -class ErrorBoundary extends Component { - public state: State = { - hasError: false, - }; - - public static getDerivedStateFromError(_: Error): State { - // Update state so the next render will show the fallback UI. - return { hasError: true }; - } - - public componentDidCatch(error: Error, errorInfo: ErrorInfo) { - console.error('Uncaught error:', error, errorInfo); - } - - public render() { - if (this.state.hasError) { - return

{this.props.errorMsg || 'Sorry.. there was an error'}

; - } - - return this.props.children; - } -} - -export default ErrorBoundary; From 01ff24da830f28be0cb7b18e63ca49712be36061 Mon Sep 17 00:00:00 2001 From: Jan Langheimer Date: Tue, 19 Jul 2022 11:54:24 +0200 Subject: [PATCH 15/36] remove unneeded debug / test code --- src/elements/admin/AdminQueryTest.tsx | 24 ------------------------ src/pages/Admin.tsx | 3 --- 2 files changed, 27 deletions(-) delete mode 100644 src/elements/admin/AdminQueryTest.tsx diff --git a/src/elements/admin/AdminQueryTest.tsx b/src/elements/admin/AdminQueryTest.tsx deleted file mode 100644 index 2a85dc69e..000000000 --- a/src/elements/admin/AdminQueryTest.tsx +++ /dev/null @@ -1,24 +0,0 @@ -import { useChainPoolIds } from 'queries/chain/useChainPoolIds'; -import { usePoolPick } from 'queries/chain/usePoolPick'; - -export const AdminQueryTest = () => { - const { data: poolIds } = useChainPoolIds(); - - const { getMany } = usePoolPick([ - 'fees', - 'symbol', - 'balance', - 'stakedBalance', - ]); - - const { data: all, isLoading } = getMany(poolIds || []); - - return ( -
- admin query test -
- {isLoading ? 'loading...' :
{JSON.stringify(all, null, 2)}
} -
-
- ); -}; diff --git a/src/pages/Admin.tsx b/src/pages/Admin.tsx index f11a9a44b..612c7d2c8 100644 --- a/src/pages/Admin.tsx +++ b/src/pages/Admin.tsx @@ -2,15 +2,12 @@ import { AdminTknData } from 'elements/admin/AdminTknData'; import { AdminUseMainnet } from 'elements/admin/AdminUseMainnet'; import { AdminUseFork } from 'elements/admin/AdminUseFork'; import { AdminControls } from 'elements/admin/AdminControls'; -import { AdminQueryTest } from 'elements/admin/AdminQueryTest'; export const Admin = () => { return (

Bancor Network Configurator

- -
From d00a8862ffe3c6d14034f4768d4f6d7ac5254d8c Mon Sep 17 00:00:00 2001 From: Jan Langheimer Date: Tue, 19 Jul 2022 11:58:35 +0200 Subject: [PATCH 16/36] remove unneeded debug / test code --- src/pages/Admin.tsx | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/pages/Admin.tsx b/src/pages/Admin.tsx index 612c7d2c8..8954260c4 100644 --- a/src/pages/Admin.tsx +++ b/src/pages/Admin.tsx @@ -8,8 +8,6 @@ export const Admin = () => {

Bancor Network Configurator

-
-
From 4e627b931eb25e7a7f9fe986bfe2fb010c01b505 Mon Sep 17 00:00:00 2001 From: Jan Langheimer Date: Tue, 19 Jul 2022 12:11:05 +0200 Subject: [PATCH 17/36] rename to useChainBalances.ts --- src/elements/vote/VoteStakeModal.tsx | 4 ++-- .../useChainBalances.ts} | 8 ++++---- src/queries/chain/usePoolPick.ts | 4 ++-- src/queries/useTokens.ts | 16 ---------------- 4 files changed, 8 insertions(+), 24 deletions(-) rename src/queries/{useBalances.ts => chain/useChainBalances.ts} (82%) delete mode 100644 src/queries/useTokens.ts diff --git a/src/elements/vote/VoteStakeModal.tsx b/src/elements/vote/VoteStakeModal.tsx index bc283e1fe..109deb70c 100644 --- a/src/elements/vote/VoteStakeModal.tsx +++ b/src/elements/vote/VoteStakeModal.tsx @@ -47,7 +47,7 @@ const useApproval = (id: string, amount: string, spender: string) => { } const amountWei = expandToken(amount, query.data.decimals); - const res = await setApproval( + await setApproval( id, account, spender, @@ -86,7 +86,7 @@ export const VoteStakeModal = ({ isOpen, setIsOpen }: Props) => { const balanceWei = expandToken(balance, decimals); const tx = await ContractsApi.Governance.write.stake(balanceWei); await tx.wait(); - queryClient.invalidateQueries(['chain']); + await queryClient.invalidateQueries(['chain']); console.log('muh'); } catch (e: any) { diff --git a/src/queries/useBalances.ts b/src/queries/chain/useChainBalances.ts similarity index 82% rename from src/queries/useBalances.ts rename to src/queries/chain/useChainBalances.ts index 347efbc3e..ec61e342b 100644 --- a/src/queries/useBalances.ts +++ b/src/queries/chain/useChainBalances.ts @@ -2,16 +2,16 @@ import { useQuery } from 'react-query'; import { fetchTokenBalanceMulticall } from 'services/web3/token/token'; import { useAppSelector } from 'store/index'; import { ethToken } from 'services/web3/config'; -import { useChainPoolIds } from './chain/useChainPoolIds'; -import { useChainPoolTokenIds } from './chain/useChainPoolTokenIds'; -import { useChainTokenDecimals } from './chain/useChainTokenDecimals'; +import { useChainPoolIds } from 'queries/chain/useChainPoolIds'; +import { useChainPoolTokenIds } from 'queries/chain/useChainPoolTokenIds'; +import { useChainTokenDecimals } from 'queries/chain/useChainTokenDecimals'; import { shrinkToken } from 'utils/formulas'; interface Props { enabled?: boolean; } -export const useBalances = ({ enabled = true }: Props = {}) => { +export const useChainBalances = ({ enabled = true }: Props = {}) => { const user = useAppSelector((state) => state.user.account); const { data: poolIds } = useChainPoolIds(); const { data: poolTokenIds } = useChainPoolTokenIds({ enabled }); diff --git a/src/queries/chain/usePoolPick.ts b/src/queries/chain/usePoolPick.ts index 43b35f4c1..6c7765c37 100644 --- a/src/queries/chain/usePoolPick.ts +++ b/src/queries/chain/usePoolPick.ts @@ -10,7 +10,7 @@ import { useApiVolume } from 'queries/api/useApiVolume'; import { useApiStakedBalance } from 'queries/api/useApiStakedBalance'; import { useChainLatestProgram } from 'queries/chain/useChainLatestProgram'; import { PoolV3Chain } from './types'; -import { useBalances } from 'queries/useBalances'; +import { useChainBalances } from 'queries/chain/useChainBalances'; export type PoolNew = Omit< PoolV3Chain, @@ -78,7 +78,7 @@ const useFetchers = (select: PoolKey[]) => { enabled: set.has('stakedBalance'), }); - const balance = useBalances({ + const balance = useChainBalances({ enabled: set.has('balance'), }); diff --git a/src/queries/useTokens.ts b/src/queries/useTokens.ts deleted file mode 100644 index fb0c8d1e2..000000000 --- a/src/queries/useTokens.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { useQuery } from 'react-query'; -import { fetchTokenBalanceMulticall } from 'services/web3/token/token'; -import { useApiPoolsV3 } from 'queries/useApiPoolsV3'; -import { useAppSelector } from 'store'; - -export const useTokens = () => { - const account = useAppSelector((state) => state.user.account); - const { data: pools } = useApiPoolsV3(); - const ids = pools ? pools.map((p) => p.poolDltId) : []; - - return useQuery>( - ['v3', 'tokens'], - () => fetchTokenBalanceMulticall(ids, account!), - { enabled: !!account && !!pools } - ); -}; From 7867fe9c779dc062d11efa4f9ccbf436756b0606 Mon Sep 17 00:00:00 2001 From: Jan Langheimer Date: Tue, 19 Jul 2022 12:28:40 +0200 Subject: [PATCH 18/36] cleanup file/folder structure for queries --- src/elements/earn/pools/Statistics.tsx | 4 ++-- src/elements/earn/pools/TopPools.tsx | 2 +- .../earn/pools/poolsTable/PoolsTable.tsx | 2 +- src/elements/vote/VoteCardStep1.tsx | 2 +- src/elements/vote/VoteStakeModal.tsx | 2 +- src/elements/vote/useVoteStakedBalance.ts | 2 +- .../useApiStatistics.ts} | 21 ++++++++++++---- .../useApiV2Welcome.ts} | 2 +- src/queries/{chain => }/types.ts | 0 src/queries/useApiPoolsV3.ts | 17 ------------- src/queries/useApiTokensV3.ts | 24 ------------------- src/queries/{chain => }/usePoolPick.ts | 2 +- 12 files changed, 26 insertions(+), 54 deletions(-) rename src/queries/{useStatistics.ts => api/useApiStatistics.ts} (81%) rename src/queries/{useApiDataV2.ts => api/useApiV2Welcome.ts} (87%) rename src/queries/{chain => }/types.ts (100%) delete mode 100644 src/queries/useApiPoolsV3.ts delete mode 100644 src/queries/useApiTokensV3.ts rename src/queries/{chain => }/usePoolPick.ts (98%) diff --git a/src/elements/earn/pools/Statistics.tsx b/src/elements/earn/pools/Statistics.tsx index d47f2ec6a..fa8331de5 100644 --- a/src/elements/earn/pools/Statistics.tsx +++ b/src/elements/earn/pools/Statistics.tsx @@ -1,8 +1,8 @@ import './Statistics.css'; -import { useStatistics } from 'queries/useStatistics'; +import { useApiStatistics } from 'queries/api/useApiStatistics'; export const Statistics = () => { - const { data: stats } = useStatistics(); + const { data: stats } = useApiStatistics(); if (!stats) { return ( diff --git a/src/elements/earn/pools/TopPools.tsx b/src/elements/earn/pools/TopPools.tsx index d8ceebfc1..488d7919a 100644 --- a/src/elements/earn/pools/TopPools.tsx +++ b/src/elements/earn/pools/TopPools.tsx @@ -2,7 +2,7 @@ import { Ticker } from 'components/ticker/Ticker'; import { ReactComponent as IconGift } from 'assets/icons/gift.svg'; import { Image } from 'components/image/Image'; import { DepositDisabledModal } from 'elements/earn/pools/poolsTable/v3/DepositDisabledModal'; -import { usePoolPick } from 'queries/chain/usePoolPick'; +import { usePoolPick } from 'queries/usePoolPick'; import { useMemo } from 'react'; import { orderBy } from 'lodash'; import { useChainPoolIds } from 'queries/chain/useChainPoolIds'; diff --git a/src/elements/earn/pools/poolsTable/PoolsTable.tsx b/src/elements/earn/pools/poolsTable/PoolsTable.tsx index 70921c863..d80da7527 100644 --- a/src/elements/earn/pools/poolsTable/PoolsTable.tsx +++ b/src/elements/earn/pools/poolsTable/PoolsTable.tsx @@ -15,7 +15,7 @@ import { Navigate } from 'components/navigate/Navigate'; import { PopoverV3 } from 'components/popover/PopoverV3'; import { Image } from 'components/image/Image'; import { useChainPoolIds } from 'queries/chain/useChainPoolIds'; -import { PoolNew, usePoolPick } from 'queries/chain/usePoolPick'; +import { PoolNew, usePoolPick } from 'queries/usePoolPick'; const poolKeys = [ 'poolDltId', diff --git a/src/elements/vote/VoteCardStep1.tsx b/src/elements/vote/VoteCardStep1.tsx index 3c09ab276..839064aab 100644 --- a/src/elements/vote/VoteCardStep1.tsx +++ b/src/elements/vote/VoteCardStep1.tsx @@ -1,4 +1,4 @@ -import { usePoolPick } from 'queries/chain/usePoolPick'; +import { usePoolPick } from 'queries/usePoolPick'; import { useState } from 'react'; import { vBntToken } from 'services/web3/config'; import { useAppSelector } from 'store'; diff --git a/src/elements/vote/VoteStakeModal.tsx b/src/elements/vote/VoteStakeModal.tsx index 109deb70c..d64783b69 100644 --- a/src/elements/vote/VoteStakeModal.tsx +++ b/src/elements/vote/VoteStakeModal.tsx @@ -1,6 +1,6 @@ import { Button, ButtonSize } from 'components/button/Button'; import { ModalV3 } from 'components/modal/ModalV3'; -import { usePoolPick } from 'queries/chain/usePoolPick'; +import { usePoolPick } from 'queries/usePoolPick'; import { useState } from 'react'; import { useQueryClient } from 'react-query'; import { getApproval, setApproval } from 'services/web3/approval'; diff --git a/src/elements/vote/useVoteStakedBalance.ts b/src/elements/vote/useVoteStakedBalance.ts index d8782218f..7b83d8a3b 100644 --- a/src/elements/vote/useVoteStakedBalance.ts +++ b/src/elements/vote/useVoteStakedBalance.ts @@ -1,4 +1,4 @@ -import { usePoolPick } from 'queries/chain/usePoolPick'; +import { usePoolPick } from 'queries/usePoolPick'; import { useQuery } from 'react-query'; import { vBntToken } from 'services/web3/config'; import { ContractsApi } from 'services/web3/v3/contractsApi'; diff --git a/src/queries/useStatistics.ts b/src/queries/api/useApiStatistics.ts similarity index 81% rename from src/queries/useStatistics.ts rename to src/queries/api/useApiStatistics.ts index 4a55f1dd3..45d164537 100644 --- a/src/queries/useStatistics.ts +++ b/src/queries/api/useApiStatistics.ts @@ -4,8 +4,10 @@ import BigNumber from 'bignumber.js'; import { bntToken } from 'services/web3/config'; import { toBigNumber } from 'utils/helperFunctions'; import numbro from 'numbro'; -import { useApiDataV2 } from 'queries/useApiDataV2'; +import { useApiV2Welcome } from 'queries/api/useApiV2Welcome'; import { WelcomeData } from 'services/api/bancorApi/bancorApi.types'; +import { genericFailedNotification } from 'services/notifications/notifications'; +import { useDispatch } from 'react-redux'; export interface Statistic { label: string; @@ -93,12 +95,23 @@ const fetchStatistics = async ( ]; }; -export const useStatistics = () => { - const { data: apiDataV2 } = useApiDataV2(); +export const useApiStatistics = () => { + const dispatch = useDispatch(); + const { data: apiDataV2 } = useApiV2Welcome(); return useQuery( ['api', 'v3', 'statistics'], () => fetchStatistics(apiDataV2!), - { enabled: !!apiDataV2 } + { + enabled: !!apiDataV2, + useErrorBoundary: false, + onError: (err: any) => { + genericFailedNotification( + dispatch, + `${err.message}`, + `Server Error: ${['api', 'v3', 'tokens'].join('->')}` + ); + }, + } ); }; diff --git a/src/queries/useApiDataV2.ts b/src/queries/api/useApiV2Welcome.ts similarity index 87% rename from src/queries/useApiDataV2.ts rename to src/queries/api/useApiV2Welcome.ts index e90468000..21e20d865 100644 --- a/src/queries/useApiDataV2.ts +++ b/src/queries/api/useApiV2Welcome.ts @@ -2,7 +2,7 @@ import { useQuery } from 'react-query'; import { BancorApi } from 'services/api/bancorApi/bancorApi'; import { WelcomeData } from 'services/api/bancorApi/bancorApi.types'; -export const useApiDataV2 = () => { +export const useApiV2Welcome = () => { return useQuery( ['api', 'v2', 'welcome'], BancorApi.v2.getWelcome diff --git a/src/queries/chain/types.ts b/src/queries/types.ts similarity index 100% rename from src/queries/chain/types.ts rename to src/queries/types.ts diff --git a/src/queries/useApiPoolsV3.ts b/src/queries/useApiPoolsV3.ts deleted file mode 100644 index f998f840f..000000000 --- a/src/queries/useApiPoolsV3.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { useQuery } from 'react-query'; -import { BancorApi } from 'services/api/bancorApi/bancorApi'; -import { APIPoolV3 } from 'services/api/bancorApi/bancorApi.types'; -import { QueryKey } from 'queries/queryKeyFactory'; - -interface Props { - enabled?: boolean; -} - -export const useApiPoolsV3 = ({ enabled = true }: Props = {}) => { - const queryKey = QueryKey.apiPools(); - return useQuery(queryKey, BancorApi.v3.getPools, { - enabled, - useErrorBoundary: true, - onError: (err) => console.error('query failed', queryKey, err), - }); -}; diff --git a/src/queries/useApiTokensV3.ts b/src/queries/useApiTokensV3.ts deleted file mode 100644 index 1d4370e47..000000000 --- a/src/queries/useApiTokensV3.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { useQuery } from 'react-query'; -import { BancorApi } from 'services/api/bancorApi/bancorApi'; -import { APITokenV3 } from 'services/api/bancorApi/bancorApi.types'; -import { useDispatch } from 'react-redux'; -import { genericFailedNotification } from 'services/notifications/notifications'; - -export const useApiTokensV3 = () => { - const dispatch = useDispatch(); - - return useQuery( - ['api', 'v3', 'tokens'], - BancorApi.v3.getTokens, - { - useErrorBoundary: false, - onError: (err) => { - genericFailedNotification( - dispatch, - `${err.message}`, - `Server Error: ${['api', 'v3', 'tokens'].join('->')}` - ); - }, - } - ); -}; diff --git a/src/queries/chain/usePoolPick.ts b/src/queries/usePoolPick.ts similarity index 98% rename from src/queries/chain/usePoolPick.ts rename to src/queries/usePoolPick.ts index 6c7765c37..e28e74184 100644 --- a/src/queries/chain/usePoolPick.ts +++ b/src/queries/usePoolPick.ts @@ -9,7 +9,7 @@ import { useApiFees } from 'queries/api/useApiFees'; import { useApiVolume } from 'queries/api/useApiVolume'; import { useApiStakedBalance } from 'queries/api/useApiStakedBalance'; import { useChainLatestProgram } from 'queries/chain/useChainLatestProgram'; -import { PoolV3Chain } from './types'; +import { PoolV3Chain } from 'queries/types'; import { useChainBalances } from 'queries/chain/useChainBalances'; export type PoolNew = Omit< From 0f5894180558d36a806e87d1f82c198ce8cce9d6 Mon Sep 17 00:00:00 2001 From: Jan Langheimer Date: Tue, 19 Jul 2022 15:37:31 +0200 Subject: [PATCH 19/36] change usePoolPick getMany to not require ids to be passed --- src/elements/earn/pools/TopPools.tsx | 4 +-- .../earn/pools/poolsTable/PoolsTable.tsx | 27 +++++++++---------- src/queries/api/useApiApr.ts | 1 + src/queries/usePoolPick.ts | 11 +++++--- 4 files changed, 22 insertions(+), 21 deletions(-) diff --git a/src/elements/earn/pools/TopPools.tsx b/src/elements/earn/pools/TopPools.tsx index 488d7919a..f62dcc87b 100644 --- a/src/elements/earn/pools/TopPools.tsx +++ b/src/elements/earn/pools/TopPools.tsx @@ -5,11 +5,9 @@ import { DepositDisabledModal } from 'elements/earn/pools/poolsTable/v3/DepositD import { usePoolPick } from 'queries/usePoolPick'; import { useMemo } from 'react'; import { orderBy } from 'lodash'; -import { useChainPoolIds } from 'queries/chain/useChainPoolIds'; // import { DepositV3Modal } from './poolsTable/v3/DepositV3Modal'; export const TopPools = () => { - const { data: poolIds } = useChainPoolIds(); const { getMany } = usePoolPick([ 'poolDltId', 'symbol', @@ -17,7 +15,7 @@ export const TopPools = () => { 'latestProgram', ]); - const { data, isLoading } = getMany(poolIds || []); + const { data, isLoading } = getMany(); const pools = useMemo(() => { return orderBy( diff --git a/src/elements/earn/pools/poolsTable/PoolsTable.tsx b/src/elements/earn/pools/poolsTable/PoolsTable.tsx index d80da7527..386342908 100644 --- a/src/elements/earn/pools/poolsTable/PoolsTable.tsx +++ b/src/elements/earn/pools/poolsTable/PoolsTable.tsx @@ -14,7 +14,6 @@ import { sortNumbersByKey } from 'utils/pureFunctions'; import { Navigate } from 'components/navigate/Navigate'; import { PopoverV3 } from 'components/popover/PopoverV3'; import { Image } from 'components/image/Image'; -import { useChainPoolIds } from 'queries/chain/useChainPoolIds'; import { PoolNew, usePoolPick } from 'queries/usePoolPick'; const poolKeys = [ @@ -31,16 +30,7 @@ const poolKeys = [ type Pool = Pick; -export const PoolsTable = ({ - rewards, - setRewards, - lowVolume, - setLowVolume, - lowLiquidity, - setLowLiquidity, - lowEarnRate, - setLowEarnRate, -}: { +interface Props { rewards: boolean; setRewards: Function; lowVolume: boolean; @@ -49,12 +39,21 @@ export const PoolsTable = ({ setLowLiquidity: Function; lowEarnRate: boolean; setLowEarnRate: Function; -}) => { - const { data: poolIds } = useChainPoolIds(); +} +export const PoolsTable = ({ + rewards, + setRewards, + lowVolume, + setLowVolume, + lowLiquidity, + setLowLiquidity, + lowEarnRate, + setLowEarnRate, +}: Props) => { const { getMany } = usePoolPick([...poolKeys]); - const { data: pools, isLoading } = getMany(poolIds || []); + const { data: pools, isLoading } = getMany(); const [search, setSearch] = useState(''); diff --git a/src/queries/api/useApiApr.ts b/src/queries/api/useApiApr.ts index 7c8f1b1b9..4ce09ffc1 100644 --- a/src/queries/api/useApiApr.ts +++ b/src/queries/api/useApiApr.ts @@ -58,6 +58,7 @@ export const useApiApr = ({ enabled = true }: Props = {}) => { .plus(autoCompoundingApr7d) .plus(standardRewardsApr7d) .toNumber(); + const apr = { apr24h: { tradingFees: tradingFeesApr24h, diff --git a/src/queries/usePoolPick.ts b/src/queries/usePoolPick.ts index e28e74184..0cae1ffa5 100644 --- a/src/queries/usePoolPick.ts +++ b/src/queries/usePoolPick.ts @@ -11,6 +11,7 @@ import { useApiStakedBalance } from 'queries/api/useApiStakedBalance'; import { useChainLatestProgram } from 'queries/chain/useChainLatestProgram'; import { PoolV3Chain } from 'queries/types'; import { useChainBalances } from 'queries/chain/useChainBalances'; +import { useChainPoolIds } from 'queries/chain/useChainPoolIds'; export type PoolNew = Omit< PoolV3Chain, @@ -122,6 +123,7 @@ const selectReduce = ( }, {} as PoolReturn); export const usePoolPick = (select: T) => { + const idsQuery = useChainPoolIds(); const { fetchers, isLoading, isFetching, isError } = useFetchers(select); const isUndefined = isLoading || isError; @@ -133,10 +135,11 @@ export const usePoolPick = (select: T) => { isError, }); - const getMany = (ids: string[]) => ({ - data: !isUndefined - ? ids.map((id) => selectReduce(id, select, fetchers)) - : undefined, + const getMany = (ids = idsQuery.data) => ({ + data: + !isUndefined && ids + ? ids.map((id) => selectReduce(id, select, fetchers)) + : undefined, isLoading, isFetching, isError, From bcaa638ae1abe8d28cb224aa5861306c4e7cf104 Mon Sep 17 00:00:00 2001 From: Jan Langheimer Date: Wed, 20 Jul 2022 16:02:06 +0200 Subject: [PATCH 20/36] update react-query to v4 --- package.json | 5 +- src/App.tsx | 38 ++-- .../earn/pools/poolsTable/PoolsTable.tsx | 3 +- src/elements/layoutHeader/LayoutHeader.tsx | 2 +- src/elements/vote/VoteCardStep2.tsx | 14 +- src/elements/vote/VoteStakeModal.tsx | 2 +- src/elements/vote/useVoteStakedBalance.ts | 2 +- src/index.tsx | 26 +-- src/queries/api/useApiBnt.ts | 2 +- src/queries/api/useApiPools.ts | 2 +- src/queries/api/useApiStatistics.ts | 2 +- src/queries/api/useApiV2Welcome.ts | 2 +- src/queries/chain/useChainBalances.ts | 2 +- .../chain/useChainDepositingEnabled.ts | 2 +- src/queries/chain/useChainLatestProgram.ts | 2 +- src/queries/chain/useChainPoolIds.ts | 2 +- src/queries/chain/useChainPoolTokenIds.ts | 2 +- src/queries/chain/useChainPrograms.ts | 2 +- src/queries/chain/useChainStakedBalance.ts | 2 +- src/queries/chain/useChainTokenDecimals.ts | 2 +- src/queries/chain/useChainTokenName.ts | 2 +- src/queries/chain/useChainTokenSymbol.ts | 2 +- src/queries/chain/useChainTradingEnabled.ts | 2 +- src/queries/chain/useChainTradingFee.ts | 2 +- src/queries/chain/useChainTradingLiquidity.ts | 2 +- yarn.lock | 175 +++++------------- 26 files changed, 86 insertions(+), 215 deletions(-) diff --git a/package.json b/package.json index a31af508e..461d395be 100644 --- a/package.json +++ b/package.json @@ -8,8 +8,8 @@ "@headlessui/react": "^1.3.0", "@popperjs/core": "^2.9.3", "@reduxjs/toolkit": "^1.6.2", - "@sentry/react": "^7.6.0", - "@sentry/tracing": "^7.6.0", + "@tanstack/react-query": "^4.0.5", + "@tanstack/react-query-devtools": "^4.0.5", "@types/jest": "^26.0.15", "@types/lodash": "^4.14.170", "@types/node": "^12.0.0", @@ -45,7 +45,6 @@ "react-error-boundary": "^3.1.4", "react-intl": "^5.17.6", "react-popper": "^2.2.5", - "react-query": "^4.0.0-beta.23", "react-router-dom": "6", "react-scripts": "5.0.1", "react-table": "^7.7.0", diff --git a/src/App.tsx b/src/App.tsx index 9fead7eff..2dee1f197 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -27,17 +27,6 @@ import { useWeb3React } from '@web3-react/core'; import { useAutoConnect } from 'services/web3/wallet/hooks'; import { setUser } from 'services/observables/user'; import { BancorRouter } from 'router/BancorRouter'; -import { FallbackProps } from 'react-error-boundary'; -import * as Sentry from '@sentry/react'; - -function ErrorFallback({ error }: FallbackProps) { - return ( -
-

Something went wrong:

-
{error.message}
-
- ); -} const handleModeChange = (_: MediaQueryListEvent) => { const darkMode = store.getState().user.darkMode; @@ -103,20 +92,17 @@ export const App = () => { }, [account, dispatch]); return ( - // @ts-ignore - - - - {unsupportedNetwork ? ( - - ) : ( -
- -
- )} - - -
-
+ + + {unsupportedNetwork ? ( + + ) : ( +
+ +
+ )} + + +
); }; diff --git a/src/elements/earn/pools/poolsTable/PoolsTable.tsx b/src/elements/earn/pools/poolsTable/PoolsTable.tsx index 386342908..550c7bc32 100644 --- a/src/elements/earn/pools/poolsTable/PoolsTable.tsx +++ b/src/elements/earn/pools/poolsTable/PoolsTable.tsx @@ -52,7 +52,6 @@ export const PoolsTable = ({ setLowEarnRate, }: Props) => { const { getMany } = usePoolPick([...poolKeys]); - const { data: pools, isLoading } = getMany(); const [search, setSearch] = useState(''); @@ -197,7 +196,7 @@ export const PoolsTable = ({ ); const defaultSort: SortingRule = { - id: 'apr.apr7d.total', + id: 'apr', desc: true, }; diff --git a/src/elements/layoutHeader/LayoutHeader.tsx b/src/elements/layoutHeader/LayoutHeader.tsx index fa9bbe9b7..176594dd9 100644 --- a/src/elements/layoutHeader/LayoutHeader.tsx +++ b/src/elements/layoutHeader/LayoutHeader.tsx @@ -13,7 +13,7 @@ import { getIsAppBusy } from 'store/bancor/bancor'; import { BancorURL } from 'router/bancorURL.service'; import { Navigate } from 'components/navigate/Navigate'; import { PopoverV3 } from 'components/popover/PopoverV3'; -import { useIsFetching } from 'react-query'; +import { useIsFetching } from '@tanstack/react-query'; export const LayoutHeader = () => { const wallet = useWalletConnect(); diff --git a/src/elements/vote/VoteCardStep2.tsx b/src/elements/vote/VoteCardStep2.tsx index d11d9433c..e89cf41ab 100644 --- a/src/elements/vote/VoteCardStep2.tsx +++ b/src/elements/vote/VoteCardStep2.tsx @@ -1,13 +1,13 @@ import { VoteCard } from './VoteCard'; -export const VoteCardStep2 = () => { - const step = 2; - const title = 'Make a Difference'; - const buttonText = 'Vote on Snapshot'; - const onButtonClick = () => {}; - const description = - 'Voting on Bancor DAO is free as it is using the Snapshot off-chain infrastructure. Every user can vote on every available proposal and help shape the future of the Bancor Protocol.'; +const step = 2; +const title = 'Make a Difference'; +const buttonText = 'Vote on Snapshot'; +const onButtonClick = () => {}; +const description = + 'Voting on Bancor DAO is free as it is using the Snapshot off-chain infrastructure. Every user can vote on every available proposal and help shape the future of the Bancor Protocol.'; +export const VoteCardStep2 = () => { return ( diff --git a/src/queries/api/useApiBnt.ts b/src/queries/api/useApiBnt.ts index 2591a94a6..21a6e88b7 100644 --- a/src/queries/api/useApiBnt.ts +++ b/src/queries/api/useApiBnt.ts @@ -1,4 +1,4 @@ -import { useQuery } from 'react-query'; +import { useQuery } from '@tanstack/react-query'; import { BancorApi } from 'services/api/bancorApi/bancorApi'; import { QueryKey } from 'queries/queryKeyFactory'; diff --git a/src/queries/api/useApiPools.ts b/src/queries/api/useApiPools.ts index eeaa56be6..e05269ce0 100644 --- a/src/queries/api/useApiPools.ts +++ b/src/queries/api/useApiPools.ts @@ -1,4 +1,4 @@ -import { useQuery } from 'react-query'; +import { useQuery } from '@tanstack/react-query'; import { BancorApi } from 'services/api/bancorApi/bancorApi'; import { QueryKey } from 'queries/queryKeyFactory'; diff --git a/src/queries/api/useApiStatistics.ts b/src/queries/api/useApiStatistics.ts index 45d164537..5bfc768a9 100644 --- a/src/queries/api/useApiStatistics.ts +++ b/src/queries/api/useApiStatistics.ts @@ -1,4 +1,4 @@ -import { useQuery } from 'react-query'; +import { useQuery } from '@tanstack/react-query'; import { BancorApi } from 'services/api/bancorApi/bancorApi'; import BigNumber from 'bignumber.js'; import { bntToken } from 'services/web3/config'; diff --git a/src/queries/api/useApiV2Welcome.ts b/src/queries/api/useApiV2Welcome.ts index 21e20d865..97335c53f 100644 --- a/src/queries/api/useApiV2Welcome.ts +++ b/src/queries/api/useApiV2Welcome.ts @@ -1,4 +1,4 @@ -import { useQuery } from 'react-query'; +import { useQuery } from '@tanstack/react-query'; import { BancorApi } from 'services/api/bancorApi/bancorApi'; import { WelcomeData } from 'services/api/bancorApi/bancorApi.types'; diff --git a/src/queries/chain/useChainBalances.ts b/src/queries/chain/useChainBalances.ts index ec61e342b..e041ef407 100644 --- a/src/queries/chain/useChainBalances.ts +++ b/src/queries/chain/useChainBalances.ts @@ -1,4 +1,4 @@ -import { useQuery } from 'react-query'; +import { useQuery } from '@tanstack/react-query'; import { fetchTokenBalanceMulticall } from 'services/web3/token/token'; import { useAppSelector } from 'store/index'; import { ethToken } from 'services/web3/config'; diff --git a/src/queries/chain/useChainDepositingEnabled.ts b/src/queries/chain/useChainDepositingEnabled.ts index 3f8b42ce2..4239e112e 100644 --- a/src/queries/chain/useChainDepositingEnabled.ts +++ b/src/queries/chain/useChainDepositingEnabled.ts @@ -1,4 +1,4 @@ -import { useQuery } from 'react-query'; +import { useQuery } from '@tanstack/react-query'; import { QueryKey } from 'queries/queryKeyFactory'; import { useChainPoolIds } from 'queries/chain/useChainPoolIds'; import { queryOptionsNoInterval } from 'queries/queryOptions'; diff --git a/src/queries/chain/useChainLatestProgram.ts b/src/queries/chain/useChainLatestProgram.ts index 2677238d3..8ffb628fe 100644 --- a/src/queries/chain/useChainLatestProgram.ts +++ b/src/queries/chain/useChainLatestProgram.ts @@ -1,4 +1,4 @@ -import { useQuery } from 'react-query'; +import { useQuery } from '@tanstack/react-query'; import { QueryKey } from 'queries/queryKeyFactory'; import { useChainPoolIds } from 'queries/chain/useChainPoolIds'; import { queryOptionsNoInterval } from 'queries/queryOptions'; diff --git a/src/queries/chain/useChainPoolIds.ts b/src/queries/chain/useChainPoolIds.ts index 37659ef43..9094009d6 100644 --- a/src/queries/chain/useChainPoolIds.ts +++ b/src/queries/chain/useChainPoolIds.ts @@ -1,4 +1,4 @@ -import { useQuery } from 'react-query'; +import { useQuery } from '@tanstack/react-query'; import { ContractsApi } from 'services/web3/v3/contractsApi'; import { QueryKey } from 'queries/queryKeyFactory'; // import { ethToken } from 'services/web3/config'; diff --git a/src/queries/chain/useChainPoolTokenIds.ts b/src/queries/chain/useChainPoolTokenIds.ts index 65e1478d5..15be09954 100644 --- a/src/queries/chain/useChainPoolTokenIds.ts +++ b/src/queries/chain/useChainPoolTokenIds.ts @@ -1,4 +1,4 @@ -import { useQuery } from 'react-query'; +import { useQuery } from '@tanstack/react-query'; import { QueryKey } from 'queries/queryKeyFactory'; import { useChainPoolIds } from 'queries/chain/useChainPoolIds'; import { queryOptionsNoInterval } from 'queries/queryOptions'; diff --git a/src/queries/chain/useChainPrograms.ts b/src/queries/chain/useChainPrograms.ts index 3a9965df1..6f39ada1d 100644 --- a/src/queries/chain/useChainPrograms.ts +++ b/src/queries/chain/useChainPrograms.ts @@ -1,4 +1,4 @@ -import { useQuery } from 'react-query'; +import { useQuery } from '@tanstack/react-query'; import { QueryKey } from 'queries/queryKeyFactory'; import { useChainPoolIds } from 'queries/chain/useChainPoolIds'; import { queryOptionsNoInterval } from 'queries/queryOptions'; diff --git a/src/queries/chain/useChainStakedBalance.ts b/src/queries/chain/useChainStakedBalance.ts index a57da3e48..be99be957 100644 --- a/src/queries/chain/useChainStakedBalance.ts +++ b/src/queries/chain/useChainStakedBalance.ts @@ -1,4 +1,4 @@ -import { useQuery } from 'react-query'; +import { useQuery } from '@tanstack/react-query'; import { QueryKey } from 'queries/queryKeyFactory'; import { useChainPoolIds } from 'queries/chain/useChainPoolIds'; import { queryOptionsStaleTimeLow } from 'queries/queryOptions'; diff --git a/src/queries/chain/useChainTokenDecimals.ts b/src/queries/chain/useChainTokenDecimals.ts index 2fd00a2a7..03c1ac110 100644 --- a/src/queries/chain/useChainTokenDecimals.ts +++ b/src/queries/chain/useChainTokenDecimals.ts @@ -1,4 +1,4 @@ -import { useQuery } from 'react-query'; +import { useQuery } from '@tanstack/react-query'; import { QueryKey } from 'queries/queryKeyFactory'; import { useChainPoolIds } from 'queries/chain/useChainPoolIds'; import { diff --git a/src/queries/chain/useChainTokenName.ts b/src/queries/chain/useChainTokenName.ts index a3be23dd9..37e86362f 100644 --- a/src/queries/chain/useChainTokenName.ts +++ b/src/queries/chain/useChainTokenName.ts @@ -1,4 +1,4 @@ -import { useQuery } from 'react-query'; +import { useQuery } from '@tanstack/react-query'; import { QueryKey } from 'queries/queryKeyFactory'; import { useChainPoolIds } from 'queries/chain/useChainPoolIds'; import { queryOptionsNoInterval } from 'queries/queryOptions'; diff --git a/src/queries/chain/useChainTokenSymbol.ts b/src/queries/chain/useChainTokenSymbol.ts index 22cd36f39..fe12c8a79 100644 --- a/src/queries/chain/useChainTokenSymbol.ts +++ b/src/queries/chain/useChainTokenSymbol.ts @@ -1,4 +1,4 @@ -import { useQuery } from 'react-query'; +import { useQuery } from '@tanstack/react-query'; import { QueryKey } from 'queries/queryKeyFactory'; import { useChainPoolIds } from 'queries/chain/useChainPoolIds'; import { queryOptionsNoInterval } from 'queries/queryOptions'; diff --git a/src/queries/chain/useChainTradingEnabled.ts b/src/queries/chain/useChainTradingEnabled.ts index a699fa4ca..254851289 100644 --- a/src/queries/chain/useChainTradingEnabled.ts +++ b/src/queries/chain/useChainTradingEnabled.ts @@ -1,4 +1,4 @@ -import { useQuery } from 'react-query'; +import { useQuery } from '@tanstack/react-query'; import { QueryKey } from 'queries/queryKeyFactory'; import { useChainPoolIds } from 'queries/chain/useChainPoolIds'; import { queryOptionsStaleTimeLow } from 'queries/queryOptions'; diff --git a/src/queries/chain/useChainTradingFee.ts b/src/queries/chain/useChainTradingFee.ts index c2bee95e0..c6941b0be 100644 --- a/src/queries/chain/useChainTradingFee.ts +++ b/src/queries/chain/useChainTradingFee.ts @@ -1,4 +1,4 @@ -import { useQuery } from 'react-query'; +import { useQuery } from '@tanstack/react-query'; import { QueryKey } from 'queries/queryKeyFactory'; import { useChainPoolIds } from 'queries/chain/useChainPoolIds'; import { queryOptionsStaleTimeLow } from 'queries/queryOptions'; diff --git a/src/queries/chain/useChainTradingLiquidity.ts b/src/queries/chain/useChainTradingLiquidity.ts index bb45eee57..b359c9ec5 100644 --- a/src/queries/chain/useChainTradingLiquidity.ts +++ b/src/queries/chain/useChainTradingLiquidity.ts @@ -1,4 +1,4 @@ -import { useQuery } from 'react-query'; +import { useQuery } from '@tanstack/react-query'; import { QueryKey } from 'queries/queryKeyFactory'; import { useChainPoolIds } from 'queries/chain/useChainPoolIds'; import { queryOptionsStaleTimeLow } from 'queries/queryOptions'; diff --git a/yarn.lock b/yarn.lock index d5f4e533d..059d39a0d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1131,7 +1131,7 @@ dependencies: regenerator-runtime "^0.12.0" -"@babel/runtime@^7.0.0", "@babel/runtime@^7.10.2", "@babel/runtime@^7.11.2", "@babel/runtime@^7.12.5", "@babel/runtime@^7.15.4", "@babel/runtime@^7.16.3", "@babel/runtime@^7.17.8", "@babel/runtime@^7.17.9", "@babel/runtime@^7.18.3", "@babel/runtime@^7.3.1", "@babel/runtime@^7.5.0", "@babel/runtime@^7.5.5", "@babel/runtime@^7.6.2", "@babel/runtime@^7.7.2", "@babel/runtime@^7.7.6", "@babel/runtime@^7.8.4", "@babel/runtime@^7.9.2": +"@babel/runtime@^7.0.0", "@babel/runtime@^7.10.2", "@babel/runtime@^7.11.2", "@babel/runtime@^7.12.5", "@babel/runtime@^7.15.4", "@babel/runtime@^7.16.3", "@babel/runtime@^7.17.8", "@babel/runtime@^7.18.3", "@babel/runtime@^7.3.1", "@babel/runtime@^7.5.0", "@babel/runtime@^7.5.5", "@babel/runtime@^7.7.6", "@babel/runtime@^7.8.4", "@babel/runtime@^7.9.2": version "7.18.6" resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.18.6.tgz#6a1ef59f838debd670421f8c7f2cbb8da9751580" integrity sha512-t9wi7/AW6XtKahAe20Yw0/mMljKq0B1r2fPdvaAdV/KPDZewFXdaaa6K7lxmZBZ8FBNpCiAT6iHPmd6QO9bKfQ== @@ -2351,69 +2351,6 @@ resolved "https://registry.yarnpkg.com/@rushstack/eslint-patch/-/eslint-patch-1.1.4.tgz#0c8b74c50f29ee44f423f7416829c0bf8bb5eb27" integrity sha512-LwzQKA4vzIct1zNZzBmRKI9QuNpLgTQMEjsQLf3BXuGYb3QPTP4Yjf6mkdX+X1mYttZ808QpOwAzZjv28kq7DA== -"@sentry/browser@7.6.0": - version "7.6.0" - resolved "https://registry.yarnpkg.com/@sentry/browser/-/browser-7.6.0.tgz#54bcd52747c40b2656d62d53541037a5724f3296" - integrity sha512-1gdvV8RtTnNFyc790t49MAgFuHAP43NEZvdQOMw5KFnDwSGYFqfBtvJ8tUm125UPbi2fghBryO9M1gfIWboKUg== - dependencies: - "@sentry/core" "7.6.0" - "@sentry/types" "7.6.0" - "@sentry/utils" "7.6.0" - tslib "^1.9.3" - -"@sentry/core@7.6.0": - version "7.6.0" - resolved "https://registry.yarnpkg.com/@sentry/core/-/core-7.6.0.tgz#5e5efd54af7b63957ac4d446fb5a69af33da3e51" - integrity sha512-vXIuUZbHVSAXh2xZ3NyXYXqVvVQSbGEpgtQxLutwocvD88JFK6aZqO+WQG69GY1b1fKSeE9faEDDS6WGAi46mQ== - dependencies: - "@sentry/hub" "7.6.0" - "@sentry/types" "7.6.0" - "@sentry/utils" "7.6.0" - tslib "^1.9.3" - -"@sentry/hub@7.6.0": - version "7.6.0" - resolved "https://registry.yarnpkg.com/@sentry/hub/-/hub-7.6.0.tgz#69a0d11e50ee61f3f93665948c4acbe56a9ce676" - integrity sha512-TbieNZInpnR5STXykT1zXoKVAsm8ju1RZyzMqYR8nzURbjlMVVEzFRglNY1Ap5MRkbEuYpAc6zUvgLQe8b6Q3w== - dependencies: - "@sentry/types" "7.6.0" - "@sentry/utils" "7.6.0" - tslib "^1.9.3" - -"@sentry/react@^7.6.0": - version "7.6.0" - resolved "https://registry.yarnpkg.com/@sentry/react/-/react-7.6.0.tgz#349596f64da8eb9370c19dde0febfd2dbaeef682" - integrity sha512-R5xBZUxSjNLpeq1dlW22JudX5x1FhzfazSVEQ9TXJEZM2ufC1XP/JkO7bRJFad1JjIzSWqlez8Wm13EnbV9wRg== - dependencies: - "@sentry/browser" "7.6.0" - "@sentry/types" "7.6.0" - "@sentry/utils" "7.6.0" - hoist-non-react-statics "^3.3.2" - tslib "^1.9.3" - -"@sentry/tracing@^7.6.0": - version "7.6.0" - resolved "https://registry.yarnpkg.com/@sentry/tracing/-/tracing-7.6.0.tgz#2b34992e7a003c40393a4aab4b917db2712a1586" - integrity sha512-ydlIk8FpuXiQm3Y0cLwXMOUYv5UtniP8ylWw3ix0sF5sTpJWSaC/g8P8yrzkYV+pm28kde5qfE3nocGhpwxZcA== - dependencies: - "@sentry/hub" "7.6.0" - "@sentry/types" "7.6.0" - "@sentry/utils" "7.6.0" - tslib "^1.9.3" - -"@sentry/types@7.6.0": - version "7.6.0" - resolved "https://registry.yarnpkg.com/@sentry/types/-/types-7.6.0.tgz#7352bcc5621177ceefb18733d0a6b0cdb0307822" - integrity sha512-POimbDwr9tmHSKksJTXe5VQpvjkFO4/UWUptigwqf8684rkS7Ie2BT2uyp5GD2EgYFf0BwUOWi98FTYTvUGT+Q== - -"@sentry/utils@7.6.0": - version "7.6.0" - resolved "https://registry.yarnpkg.com/@sentry/utils/-/utils-7.6.0.tgz#50b44fd9b06686a358ef2c7c0fd3b80970e1f9ee" - integrity sha512-p0Byi6hgawp/sBMY88RY8OmkiAR2jxbjnl8gSo+y3YEu+KeXBUxXMBsI7YeW+1lSb6z8DGhUAOBszTeI4wAr2w== - dependencies: - "@sentry/types" "7.6.0" - tslib "^1.9.3" - "@sinclair/typebox@^0.23.3": version "0.23.5" resolved "https://registry.yarnpkg.com/@sinclair/typebox/-/typebox-0.23.5.tgz#93f7b9f4e3285a7a9ade7557d9a8d36809cbc47d" @@ -3455,6 +3392,36 @@ "@svgr/plugin-svgo" "^5.5.0" loader-utils "^2.0.0" +"@tanstack/match-sorter-utils@^8.0.0-alpha.82": + version "8.1.1" + resolved "https://registry.yarnpkg.com/@tanstack/match-sorter-utils/-/match-sorter-utils-8.1.1.tgz#895f407813254a46082a6bbafad9b39b943dc834" + integrity sha512-IdmEekEYxQsoLOR0XQyw3jD1GujBpRRYaGJYQUw1eOT1eUugWxdc7jomh1VQ1EKHcdwDLpLaCz/8y4KraU4T9A== + dependencies: + remove-accents "0.4.2" + +"@tanstack/query-core@^4.0.0-beta.1": + version "4.0.5" + resolved "https://registry.yarnpkg.com/@tanstack/query-core/-/query-core-4.0.5.tgz#70c7275a9f1fbc8e6520d895991f9bace0fd5bb8" + integrity sha512-QOJ2gLbwlf8p0487pMey6vv8EF5X2ib1zINayaD7mb9/LibUtXmZ12uJgTqcnjgNY/4tWZn5qJnEk2ePG5AVGA== + +"@tanstack/react-query-devtools@^4.0.5": + version "4.0.5" + resolved "https://registry.yarnpkg.com/@tanstack/react-query-devtools/-/react-query-devtools-4.0.5.tgz#6ee95d7e4367fde0e3a7bd1b778e3b393ff1b757" + integrity sha512-OTRDYDBGFuW1S+oFDvPTso0mdo13/TWq79S42bsGbZ+leSHr9l3yB4UXzZsJvwLG8pEQpN/RigZOmXCOuMeSlw== + dependencies: + "@tanstack/match-sorter-utils" "^8.0.0-alpha.82" + "@types/use-sync-external-store" "^0.0.3" + use-sync-external-store "^1.2.0" + +"@tanstack/react-query@^4.0.5": + version "4.0.5" + resolved "https://registry.yarnpkg.com/@tanstack/react-query/-/react-query-4.0.5.tgz#4597ac03394ddfa6ad8b5e1beb6282468623d398" + integrity sha512-tIggVlhoFevVpY/LkZroPmrERFHN8tw4aZLtgwSArzHmMJ03WQcaNvbbHy6GERidXtaMdUz+IeQryrE7cO7WPQ== + dependencies: + "@tanstack/query-core" "^4.0.0-beta.1" + "@types/use-sync-external-store" "^0.0.3" + use-sync-external-store "^1.2.0" + "@tootallnate/once@1": version "1.1.2" resolved "https://registry.yarnpkg.com/@tootallnate/once/-/once-1.1.2.tgz#ccb91445360179a04e7fe6aff78c00ffc1eeaf82" @@ -5621,7 +5588,7 @@ bfj@^7.0.2: hoopy "^0.1.4" tryer "^1.0.1" -big-integer@^1.6.16, big-integer@^1.6.7: +big-integer@^1.6.7: version "1.6.51" resolved "https://registry.yarnpkg.com/big-integer/-/big-integer-1.6.51.tgz#0df92a5d9880560d3ff2d5fd20245c889d130686" integrity sha512-GPEid2Y9QU1Exl1rpO9B2IPJGHPSupF5GnVIP0blYvNOMer2bTvSWs1jGOUg04hTmu67nmLsQ9TBo1puaotBHg== @@ -5792,20 +5759,6 @@ braces@^3.0.2, braces@~3.0.2: dependencies: fill-range "^7.0.1" -broadcast-channel@^3.4.1: - version "3.7.0" - resolved "https://registry.yarnpkg.com/broadcast-channel/-/broadcast-channel-3.7.0.tgz#2dfa5c7b4289547ac3f6705f9c00af8723889937" - integrity sha512-cIAKJXAxGJceNZGTZSBzMxzyOn72cVgPnKx4dc6LRjQgbaJUQqhy5rzL3zbMxkMWsGKkv2hSFkPRMEXfoMZ2Mg== - dependencies: - "@babel/runtime" "^7.7.2" - detect-node "^2.1.0" - js-sha3 "0.8.0" - microseconds "0.2.0" - nano-time "1.0.0" - oblivious-set "1.0.0" - rimraf "3.0.2" - unload "2.2.0" - brorand@^1.0.1, brorand@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/brorand/-/brorand-1.1.0.tgz#12c25efe40a45e3c323eb8675a0a0ce57b22371f" @@ -7306,7 +7259,7 @@ detect-newline@^3.0.0: resolved "https://registry.yarnpkg.com/detect-newline/-/detect-newline-3.1.0.tgz#576f5dfc63ae1a192ff192d8ad3af6308991b651" integrity sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA== -detect-node@^2.0.4, detect-node@^2.1.0: +detect-node@^2.0.4: version "2.1.0" resolved "https://registry.yarnpkg.com/detect-node/-/detect-node-2.1.0.tgz#c9c70775a49c3d03bc2c06d9a73be550f978f8b1" integrity sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g== @@ -11731,14 +11684,6 @@ markdown-escapes@^1.0.0: resolved "https://registry.yarnpkg.com/markdown-escapes/-/markdown-escapes-1.0.4.tgz#c95415ef451499d7602b91095f3c8e8975f78535" integrity sha512-8z4efJYk43E0upd0NbVXwgSTQs6cT3T06etieCMEg7dRbzCbxUCK/GHlX8mhHRDcp+OLlHkPKsvqQTCvsRl2cg== -match-sorter@^6.0.2: - version "6.3.1" - resolved "https://registry.yarnpkg.com/match-sorter/-/match-sorter-6.3.1.tgz#98cc37fda756093424ddf3cbc62bfe9c75b92bda" - integrity sha512-mxybbo3pPNuA+ZuCUhm5bwNkXrJTbsk5VWbR5wiwz/GC6LIiegBGn2w3O08UG/jdbYLinw51fSQ5xNU1U3MgBw== - dependencies: - "@babel/runtime" "^7.12.5" - remove-accents "0.4.2" - md5.js@^1.3.4: version "1.3.5" resolved "https://registry.yarnpkg.com/md5.js/-/md5.js-1.3.5.tgz#b5d07b8e3216e3e27cd728d72f70d1e6a342005f" @@ -11944,11 +11889,6 @@ micromatch@^4.0.2, micromatch@^4.0.4, micromatch@^4.0.5: braces "^3.0.2" picomatch "^2.3.1" -microseconds@0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/microseconds/-/microseconds-0.2.0.tgz#233b25f50c62a65d861f978a4a4f8ec18797dc39" - integrity sha512-n7DHHMjR1avBbSpsTBj6fmMGh2AGrifVV4e+WYc3Q9lO+xnSZ3NyhcBND3vzzatt05LFhoKFRxrIyklmLlUtyA== - miller-rabin@^4.0.0: version "4.0.1" resolved "https://registry.yarnpkg.com/miller-rabin/-/miller-rabin-4.0.1.tgz#f080351c865b0dc562a8462966daa53543c78a4d" @@ -12161,13 +12101,6 @@ nan@^2.12.1, nan@^2.14.0, nan@^2.14.2, nan@^2.2.1: resolved "https://registry.yarnpkg.com/nan/-/nan-2.16.0.tgz#664f43e45460fb98faf00edca0bb0d7b8dce7916" integrity sha512-UdAqHyFngu7TfQKsCBgAA6pWDkT8MAO7d0jyOecVhN5354xbLqdn8mV9Tat9gepAupm0bt2DbeaSC8vS52MuFA== -nano-time@1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/nano-time/-/nano-time-1.0.0.tgz#b0554f69ad89e22d0907f7a12b0993a5d96137ef" - integrity sha512-flnngywOoQ0lLQOTRNexn2gGSNuM9bKj9RZAWSzhQ+UJYaAFG9bac4DW9VHjUAzrOaIcajHybCTHe/bkvozQqA== - dependencies: - big-integer "^1.6.16" - nanoid@^3.3.1, nanoid@^3.3.4: version "3.3.4" resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.4.tgz#730b67e3cd09e2deacf03c027c81c9d9dbc5e8ab" @@ -12509,11 +12442,6 @@ objectorarray@^1.0.5: resolved "https://registry.yarnpkg.com/objectorarray/-/objectorarray-1.0.5.tgz#2c05248bbefabd8f43ad13b41085951aac5e68a5" integrity sha512-eJJDYkhJFFbBBAxeh8xW+weHlkI28n2ZdQV/J/DNfWfSKlGEf2xcfAbZTv3riEXHAhL9SVOTs2pRmXiSTf78xg== -oblivious-set@1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/oblivious-set/-/oblivious-set-1.0.0.tgz#c8316f2c2fb6ff7b11b6158db3234c49f733c566" - integrity sha512-z+pI07qxo4c2CulUHCDf9lcqDlMSo72N/4rLUpRXf6fu+q8vjt8y0xS+Tlf8NTJDdTXHbdeO1n3MlbctwEoXZw== - oboe@2.1.4: version "2.1.4" resolved "https://registry.yarnpkg.com/oboe/-/oboe-2.1.4.tgz#20c88cdb0c15371bb04119257d4fdd34b0aa49f6" @@ -14211,17 +14139,6 @@ react-popper@^2.2.5: react-fast-compare "^3.0.1" warning "^4.0.2" -react-query@^4.0.0-beta.23: - version "4.0.0-beta.23" - resolved "https://registry.yarnpkg.com/react-query/-/react-query-4.0.0-beta.23.tgz#76713547670ef1f991ae828b3d51df63ec6e035c" - integrity sha512-e6mNBVAYGy0M1OwX0mhRB/lCkOedKeqTUrbPjNCqvm8hQGUsJJobqfHVvTv8o6JJaOO2MFcxKF4vZM+PEKbHZA== - dependencies: - "@babel/runtime" "^7.17.9" - "@types/use-sync-external-store" "^0.0.3" - broadcast-channel "^3.4.1" - match-sorter "^6.0.2" - use-sync-external-store "^1.1.0" - react-redux@^7.2.6: version "7.2.8" resolved "https://registry.yarnpkg.com/react-redux/-/react-redux-7.2.8.tgz#a894068315e65de5b1b68899f9c6ee0923dd28de" @@ -14812,13 +14729,6 @@ rfdc@^1.3.0: resolved "https://registry.yarnpkg.com/rfdc/-/rfdc-1.3.0.tgz#d0b7c441ab2720d05dc4cf26e01c89631d9da08b" integrity sha512-V2hovdzFbOi77/WajaSMXk2OLm+xNIeQdMMuB7icj7bk6zi2F8GGAxigcnDFpJHbNyNcgyJDiP+8nOrY5cZGrA== -rimraf@3.0.2, rimraf@^3.0.0, rimraf@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" - integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA== - dependencies: - glob "^7.1.3" - rimraf@^2.5.4, rimraf@^2.6.3: version "2.7.1" resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.7.1.tgz#35797f13a7fdadc566142c29d4f07ccad483e3ec" @@ -14826,6 +14736,13 @@ rimraf@^2.5.4, rimraf@^2.6.3: dependencies: glob "^7.1.3" +rimraf@^3.0.0, rimraf@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" + integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA== + dependencies: + glob "^7.1.3" + rimraf@~2.6.2: version "2.6.3" resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.3.tgz#b2d104fe0d8fb27cf9e0a1cda8262dd3833c6cab" @@ -16389,7 +16306,7 @@ tsconfig-paths@^3.14.1: minimist "^1.2.6" strip-bom "^3.0.0" -tslib@^1.8.1, tslib@^1.9.0, tslib@^1.9.3: +tslib@^1.8.1, tslib@^1.9.0: version "1.14.1" resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== @@ -16695,14 +16612,6 @@ universalify@^2.0.0: resolved "https://registry.yarnpkg.com/universalify/-/universalify-2.0.0.tgz#75a4984efedc4b08975c5aeb73f530d02df25717" integrity sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ== -unload@2.2.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/unload/-/unload-2.2.0.tgz#ccc88fdcad345faa06a92039ec0f80b488880ef7" - integrity sha512-B60uB5TNBLtN6/LsgAf3udH9saB5p7gqJwcFfbOEZ8BcBHnGwCf6G/TGiEqkRAxX7zAFIUtzdrXQSdL3Q/wqNA== - dependencies: - "@babel/runtime" "^7.6.2" - detect-node "^2.0.4" - unpipe@1.0.0, unpipe@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" @@ -16775,7 +16684,7 @@ use-async-effect@^2.2.3: resolved "https://registry.yarnpkg.com/use-async-effect/-/use-async-effect-2.2.6.tgz#00f2dee71e2f6188c5daf6a067e2bc151f7566b7" integrity sha512-wKUpaHkuF4rzBHawP87o1KzoK2IxJ6De8fUyQ3GN2114zb4zqT87+SEbCHS+F+0inZ2Y+k6Tm1LOCQgYTSD9ww== -use-sync-external-store@^1.1.0: +use-sync-external-store@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz#7dbefd6ef3fe4e767a0cf5d7287aacfb5846928a" integrity sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA== From e8da64800a119ffe2197ba77f1b6c798e1bae71a Mon Sep 17 00:00:00 2001 From: Jan Langheimer Date: Wed, 20 Jul 2022 16:12:46 +0200 Subject: [PATCH 21/36] add index file and default exports for queries folder --- src/elements/earn/pools/TopPools.tsx | 2 +- src/elements/earn/pools/poolsTable/PoolsTable.tsx | 4 ++-- src/elements/vote/VoteCardStep1.tsx | 2 +- src/elements/vote/VoteStakeModal.tsx | 2 +- src/elements/vote/useVoteStakedBalance.ts | 2 +- src/index.tsx | 14 ++------------ src/queries/index.ts | 3 +++ src/queries/queryClient.ts | 11 +++++++++++ src/queries/usePoolPick.ts | 5 +++-- 9 files changed, 25 insertions(+), 20 deletions(-) create mode 100644 src/queries/index.ts create mode 100644 src/queries/queryClient.ts diff --git a/src/elements/earn/pools/TopPools.tsx b/src/elements/earn/pools/TopPools.tsx index f62dcc87b..b855624be 100644 --- a/src/elements/earn/pools/TopPools.tsx +++ b/src/elements/earn/pools/TopPools.tsx @@ -2,7 +2,7 @@ import { Ticker } from 'components/ticker/Ticker'; import { ReactComponent as IconGift } from 'assets/icons/gift.svg'; import { Image } from 'components/image/Image'; import { DepositDisabledModal } from 'elements/earn/pools/poolsTable/v3/DepositDisabledModal'; -import { usePoolPick } from 'queries/usePoolPick'; +import { usePoolPick } from 'queries'; import { useMemo } from 'react'; import { orderBy } from 'lodash'; // import { DepositV3Modal } from './poolsTable/v3/DepositV3Modal'; diff --git a/src/elements/earn/pools/poolsTable/PoolsTable.tsx b/src/elements/earn/pools/poolsTable/PoolsTable.tsx index 550c7bc32..10f83505f 100644 --- a/src/elements/earn/pools/poolsTable/PoolsTable.tsx +++ b/src/elements/earn/pools/poolsTable/PoolsTable.tsx @@ -14,7 +14,7 @@ import { sortNumbersByKey } from 'utils/pureFunctions'; import { Navigate } from 'components/navigate/Navigate'; import { PopoverV3 } from 'components/popover/PopoverV3'; import { Image } from 'components/image/Image'; -import { PoolNew, usePoolPick } from 'queries/usePoolPick'; +import { PoolV3Chain, usePoolPick } from 'queries'; const poolKeys = [ 'poolDltId', @@ -28,7 +28,7 @@ const poolKeys = [ 'latestProgram', ] as const; -type Pool = Pick; +type Pool = Pick; interface Props { rewards: boolean; diff --git a/src/elements/vote/VoteCardStep1.tsx b/src/elements/vote/VoteCardStep1.tsx index 839064aab..ee8b72394 100644 --- a/src/elements/vote/VoteCardStep1.tsx +++ b/src/elements/vote/VoteCardStep1.tsx @@ -1,4 +1,4 @@ -import { usePoolPick } from 'queries/usePoolPick'; +import { usePoolPick } from 'queries'; import { useState } from 'react'; import { vBntToken } from 'services/web3/config'; import { useAppSelector } from 'store'; diff --git a/src/elements/vote/VoteStakeModal.tsx b/src/elements/vote/VoteStakeModal.tsx index a910eca3b..409c6b7da 100644 --- a/src/elements/vote/VoteStakeModal.tsx +++ b/src/elements/vote/VoteStakeModal.tsx @@ -1,6 +1,6 @@ import { Button, ButtonSize } from 'components/button/Button'; import { ModalV3 } from 'components/modal/ModalV3'; -import { usePoolPick } from 'queries/usePoolPick'; +import { usePoolPick } from 'queries'; import { useState } from 'react'; import { useQueryClient } from '@tanstack/react-query'; import { getApproval, setApproval } from 'services/web3/approval'; diff --git a/src/elements/vote/useVoteStakedBalance.ts b/src/elements/vote/useVoteStakedBalance.ts index a3987609c..f344f5339 100644 --- a/src/elements/vote/useVoteStakedBalance.ts +++ b/src/elements/vote/useVoteStakedBalance.ts @@ -1,4 +1,4 @@ -import { usePoolPick } from 'queries/usePoolPick'; +import { usePoolPick } from 'queries'; import { useQuery } from '@tanstack/react-query'; import { vBntToken } from 'services/web3/config'; import { ContractsApi } from 'services/web3/v3/contractsApi'; diff --git a/src/index.tsx b/src/index.tsx index 97e341e54..17f06a4aa 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -8,19 +8,9 @@ import { I18nProvider } from 'i18n/i18nProvider'; import { getLibrary } from 'services/web3/wallet/utils'; import { Web3ReactProvider } from '@web3-react/core'; import 'styles/index.css'; -import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; +import { QueryClientProvider } from '@tanstack/react-query'; import { ReactQueryDevtools } from '@tanstack/react-query-devtools'; - -export const queryClient = new QueryClient({ - defaultOptions: { - queries: { - refetchInterval: 60000, - staleTime: 30000, - useErrorBoundary: true, - // cacheTime: 1000 * 60 * 60 * 24, // 24 hours - }, - }, -}); +import { queryClient } from 'queries'; ReactDOM.render( diff --git a/src/queries/index.ts b/src/queries/index.ts new file mode 100644 index 000000000..41a2a65cb --- /dev/null +++ b/src/queries/index.ts @@ -0,0 +1,3 @@ +export { queryClient } from './queryClient'; +export { usePoolPick } from './usePoolPick'; +export type { PoolV3Chain } from './types'; diff --git a/src/queries/queryClient.ts b/src/queries/queryClient.ts new file mode 100644 index 000000000..52f702f54 --- /dev/null +++ b/src/queries/queryClient.ts @@ -0,0 +1,11 @@ +import { QueryClient } from '@tanstack/react-query'; + +export const queryClient = new QueryClient({ + defaultOptions: { + queries: { + refetchInterval: 60000, + staleTime: 30000, + useErrorBoundary: true, + }, + }, +}); diff --git a/src/queries/usePoolPick.ts b/src/queries/usePoolPick.ts index 0cae1ffa5..34a3609aa 100644 --- a/src/queries/usePoolPick.ts +++ b/src/queries/usePoolPick.ts @@ -13,12 +13,13 @@ import { PoolV3Chain } from 'queries/types'; import { useChainBalances } from 'queries/chain/useChainBalances'; import { useChainPoolIds } from 'queries/chain/useChainPoolIds'; -export type PoolNew = Omit< +type PoolNew = Omit< PoolV3Chain, 'name' | 'logoURI' | 'standardRewards' | 'tradingFeePPM' | 'depositingEnabled' >; -export type PoolKey = keyof PoolNew; +type PoolKey = keyof PoolNew; + type Fetchers = { [key in PoolKey]: { getByID: (id: string) => PoolNew[key] | undefined; From a385971d8977ee8c7eb189223f5298258c7ce4f3 Mon Sep 17 00:00:00 2001 From: Jan Langheimer Date: Wed, 20 Jul 2022 17:11:33 +0200 Subject: [PATCH 22/36] extract query client provider in separate file --- src/index.tsx | 5 ++--- src/queries/index.ts | 2 +- src/queries/queryClient.ts | 11 ----------- src/queries/queryClient.tsx | 19 +++++++++++++++++++ 4 files changed, 22 insertions(+), 15 deletions(-) delete mode 100644 src/queries/queryClient.ts create mode 100644 src/queries/queryClient.tsx diff --git a/src/index.tsx b/src/index.tsx index 17f06a4aa..8fb226d97 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -8,12 +8,11 @@ import { I18nProvider } from 'i18n/i18nProvider'; import { getLibrary } from 'services/web3/wallet/utils'; import { Web3ReactProvider } from '@web3-react/core'; import 'styles/index.css'; -import { QueryClientProvider } from '@tanstack/react-query'; +import { QueryClientProvider } from 'queries'; import { ReactQueryDevtools } from '@tanstack/react-query-devtools'; -import { queryClient } from 'queries'; ReactDOM.render( - + diff --git a/src/queries/index.ts b/src/queries/index.ts index 41a2a65cb..be4f6b656 100644 --- a/src/queries/index.ts +++ b/src/queries/index.ts @@ -1,3 +1,3 @@ -export { queryClient } from './queryClient'; +export { QueryClientProvider } from './queryClient'; export { usePoolPick } from './usePoolPick'; export type { PoolV3Chain } from './types'; diff --git a/src/queries/queryClient.ts b/src/queries/queryClient.ts deleted file mode 100644 index 52f702f54..000000000 --- a/src/queries/queryClient.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { QueryClient } from '@tanstack/react-query'; - -export const queryClient = new QueryClient({ - defaultOptions: { - queries: { - refetchInterval: 60000, - staleTime: 30000, - useErrorBoundary: true, - }, - }, -}); diff --git a/src/queries/queryClient.tsx b/src/queries/queryClient.tsx new file mode 100644 index 000000000..0187dd5bd --- /dev/null +++ b/src/queries/queryClient.tsx @@ -0,0 +1,19 @@ +import { + QueryClient, + QueryClientProvider as QueryClientP, +} from '@tanstack/react-query'; +import { ReactNode } from 'react'; + +const queryClient = new QueryClient({ + defaultOptions: { + queries: { + refetchInterval: 60000, + staleTime: 30000, + useErrorBoundary: true, + }, + }, +}); + +export const QueryClientProvider = ({ children }: { children: ReactNode }) => { + return {children}; +}; From 009ba72e4b6708b90fc99370398ea99e566f841b Mon Sep 17 00:00:00 2001 From: Jan Langheimer Date: Thu, 21 Jul 2022 10:44:18 +0200 Subject: [PATCH 23/36] add depositingEnabled to usePoolPick --- src/queries/chain/useChainDepositingEnabled.ts | 15 ++++++++++++--- src/queries/usePoolPick.ts | 7 ++++++- 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/src/queries/chain/useChainDepositingEnabled.ts b/src/queries/chain/useChainDepositingEnabled.ts index 4239e112e..1d50ccde5 100644 --- a/src/queries/chain/useChainDepositingEnabled.ts +++ b/src/queries/chain/useChainDepositingEnabled.ts @@ -7,12 +7,21 @@ import { fetchMulticallHelper, } from 'services/web3/multicall/multicallFunctions'; -export const useChainDepositingEnabled = () => { +interface Props { + enabled?: boolean; +} + +export const useChainDepositingEnabled = ({ enabled = true }: Props = {}) => { const { data: poolIds } = useChainPoolIds(); - return useQuery( + + const query = useQuery( QueryKey.chainCoreDepositingEnabled(poolIds?.length), () => fetchMulticallHelper(poolIds!, buildMulticallDepositingEnabled), - queryOptionsNoInterval(!!poolIds) + queryOptionsNoInterval(!!poolIds && enabled) ); + + const getByID = (id: string) => query.data?.get(id); + + return { ...query, getByID }; }; diff --git a/src/queries/usePoolPick.ts b/src/queries/usePoolPick.ts index 34a3609aa..23781b56c 100644 --- a/src/queries/usePoolPick.ts +++ b/src/queries/usePoolPick.ts @@ -15,7 +15,7 @@ import { useChainPoolIds } from 'queries/chain/useChainPoolIds'; type PoolNew = Omit< PoolV3Chain, - 'name' | 'logoURI' | 'standardRewards' | 'tradingFeePPM' | 'depositingEnabled' + 'name' | 'logoURI' | 'standardRewards' | 'tradingFeePPM' >; type PoolKey = keyof PoolNew; @@ -56,6 +56,10 @@ const useFetchers = (select: PoolKey[]) => { enabled: set.has('tradingEnabled'), }); + const depositingEnabled = useChainTradingEnabled({ + enabled: set.has('depositingEnabled'), + }); + const tradingLiquidity = useChainTradingLiquidity({ enabled: set.has('tradingLiquidity'), }); @@ -96,6 +100,7 @@ const useFetchers = (select: PoolKey[]) => { poolTokenDltId, programs, tradingEnabled, + depositingEnabled, apr, tradingLiquidity, fees, From 8b837a9619f2e087bca46060ed74ecd408c8bfb8 Mon Sep 17 00:00:00 2001 From: Jan Langheimer Date: Thu, 21 Jul 2022 10:44:47 +0200 Subject: [PATCH 24/36] cleanup --- src/index.tsx | 2 -- src/queries/chain/useChainPoolIds.ts | 2 -- src/queries/chain/useChainStakedBalance.ts | 19 ------------------- src/queries/queryClient.tsx | 8 +++++++- 4 files changed, 7 insertions(+), 24 deletions(-) delete mode 100644 src/queries/chain/useChainStakedBalance.ts diff --git a/src/index.tsx b/src/index.tsx index 8fb226d97..b0e38339b 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -9,7 +9,6 @@ import { getLibrary } from 'services/web3/wallet/utils'; import { Web3ReactProvider } from '@web3-react/core'; import 'styles/index.css'; import { QueryClientProvider } from 'queries'; -import { ReactQueryDevtools } from '@tanstack/react-query-devtools'; ReactDOM.render( @@ -22,7 +21,6 @@ ReactDOM.render( - , document.getElementById('root') ); diff --git a/src/queries/chain/useChainPoolIds.ts b/src/queries/chain/useChainPoolIds.ts index 9094009d6..4bf56c748 100644 --- a/src/queries/chain/useChainPoolIds.ts +++ b/src/queries/chain/useChainPoolIds.ts @@ -1,7 +1,6 @@ import { useQuery } from '@tanstack/react-query'; import { ContractsApi } from 'services/web3/v3/contractsApi'; import { QueryKey } from 'queries/queryKeyFactory'; -// import { ethToken } from 'services/web3/config'; import { queryOptionsStaleTimeLow } from 'queries/queryOptions'; import { bntToken } from 'services/web3/config'; @@ -10,7 +9,6 @@ export const useChainPoolIds = () => { QueryKey.chainCorePoolIds(), async () => { const pools = await ContractsApi.BancorNetwork.read.liquidityPools(); - //return pools.filter((id) => id !== ethToken); return [bntToken, ...pools]; }, queryOptionsStaleTimeLow() diff --git a/src/queries/chain/useChainStakedBalance.ts b/src/queries/chain/useChainStakedBalance.ts deleted file mode 100644 index be99be957..000000000 --- a/src/queries/chain/useChainStakedBalance.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { useQuery } from '@tanstack/react-query'; -import { QueryKey } from 'queries/queryKeyFactory'; -import { useChainPoolIds } from 'queries/chain/useChainPoolIds'; -import { queryOptionsStaleTimeLow } from 'queries/queryOptions'; -import { - buildMulticallStakedBalance, - fetchMulticallHelper, -} from 'services/web3/multicall/multicallFunctions'; -import { BigNumberish } from 'ethers'; - -export const useChainStakedBalance = () => { - const { data: poolIds } = useChainPoolIds(); - return useQuery( - QueryKey.chainCoreStakedBalance(poolIds?.length), - () => - fetchMulticallHelper(poolIds!, buildMulticallStakedBalance), - queryOptionsStaleTimeLow(!!poolIds) - ); -}; diff --git a/src/queries/queryClient.tsx b/src/queries/queryClient.tsx index 0187dd5bd..bd1c73aae 100644 --- a/src/queries/queryClient.tsx +++ b/src/queries/queryClient.tsx @@ -3,6 +3,7 @@ import { QueryClientProvider as QueryClientP, } from '@tanstack/react-query'; import { ReactNode } from 'react'; +import { ReactQueryDevtools } from '@tanstack/react-query-devtools'; const queryClient = new QueryClient({ defaultOptions: { @@ -15,5 +16,10 @@ const queryClient = new QueryClient({ }); export const QueryClientProvider = ({ children }: { children: ReactNode }) => { - return {children}; + return ( + + {children} + + + ); }; From 675fc8af4c8ac75e5d163c29767fd4635eff271d Mon Sep 17 00:00:00 2001 From: Jan Langheimer Date: Thu, 21 Jul 2022 10:58:49 +0200 Subject: [PATCH 25/36] add rate to usePoolPick --- src/queries/api/useApiApr.ts | 2 +- src/queries/api/useApiFees.ts | 2 +- src/queries/api/useApiPools.ts | 4 ++-- src/queries/api/useApiRate.ts | 32 +++++++++++++++++++++++++ src/queries/api/useApiStakedBalance.ts | 2 +- src/queries/api/useApiTokens.ts | 33 ++++++++++++++++++++++++++ src/queries/api/useApiVolume.ts | 2 +- src/queries/types.ts | 3 +++ src/queries/usePoolPick.ts | 8 ++++++- 9 files changed, 81 insertions(+), 7 deletions(-) create mode 100644 src/queries/api/useApiRate.ts create mode 100644 src/queries/api/useApiTokens.ts diff --git a/src/queries/api/useApiApr.ts b/src/queries/api/useApiApr.ts index 4ce09ffc1..f11720415 100644 --- a/src/queries/api/useApiApr.ts +++ b/src/queries/api/useApiApr.ts @@ -16,7 +16,7 @@ export const useApiApr = ({ enabled = true }: Props = {}) => { const data = new Map( poolIds.data?.map((id) => { - const apiPool = apiPools.getApiPoolByID(id); + const apiPool = apiPools.getByID(id); const programs = programsMap.data?.get(id); if (!apiPool) { diff --git a/src/queries/api/useApiFees.ts b/src/queries/api/useApiFees.ts index c09d7c3c4..45f8b4a4e 100644 --- a/src/queries/api/useApiFees.ts +++ b/src/queries/api/useApiFees.ts @@ -11,7 +11,7 @@ export const useApiFees = ({ enabled = true }: Props = {}) => { const data = new Map( poolIds.data?.map((id) => { - const apiPool = apiPools.getApiPoolByID(id); + const apiPool = apiPools.getByID(id); if (!apiPool) { return [id, undefined]; diff --git a/src/queries/api/useApiPools.ts b/src/queries/api/useApiPools.ts index e05269ce0..c33a87126 100644 --- a/src/queries/api/useApiPools.ts +++ b/src/queries/api/useApiPools.ts @@ -27,7 +27,7 @@ export const useApiPools = ({ enabled = true }: Props = {}) => { } ); - const getApiPoolByID = (id: string) => query.data?.get(id); + const getByID = (id: string) => query.data?.get(id); - return { ...query, getApiPoolByID }; + return { ...query, getByID }; }; diff --git a/src/queries/api/useApiRate.ts b/src/queries/api/useApiRate.ts new file mode 100644 index 000000000..1031aa4b4 --- /dev/null +++ b/src/queries/api/useApiRate.ts @@ -0,0 +1,32 @@ +import { useChainPoolIds } from 'queries/chain/useChainPoolIds'; +import { useApiTokens } from 'queries/api/useApiTokens'; + +interface Props { + enabled?: boolean; +} + +export const useApiRate = ({ enabled = true }: Props = {}) => { + const poolIds = useChainPoolIds(); + const apiTokens = useApiTokens({ enabled }); + + const data = new Map( + poolIds.data?.map((id) => { + const apiToken = apiTokens.getApiPoolByID(id); + + if (!apiToken) { + return [id, undefined]; + } + return [id, apiToken.rate]; + }) + ); + + const getByID = (id: string) => data.get(id); + + return { + data, + getByID, + isLoading: apiTokens.isLoading || poolIds.isLoading, + isFetching: apiTokens.isFetching || poolIds.isFetching, + isError: apiTokens.isError || poolIds.isError, + }; +}; diff --git a/src/queries/api/useApiStakedBalance.ts b/src/queries/api/useApiStakedBalance.ts index 72070d09a..5d9132758 100644 --- a/src/queries/api/useApiStakedBalance.ts +++ b/src/queries/api/useApiStakedBalance.ts @@ -11,7 +11,7 @@ export const useApiStakedBalance = ({ enabled = true }: Props = {}) => { const data = new Map( poolIds.data?.map((id) => { - const apiPool = apiPools.getApiPoolByID(id); + const apiPool = apiPools.getByID(id); if (!apiPool) { return [id, undefined]; diff --git a/src/queries/api/useApiTokens.ts b/src/queries/api/useApiTokens.ts new file mode 100644 index 000000000..4a286353f --- /dev/null +++ b/src/queries/api/useApiTokens.ts @@ -0,0 +1,33 @@ +import { useQuery } from '@tanstack/react-query'; +import { BancorApi } from 'services/api/bancorApi/bancorApi'; +import { QueryKey } from 'queries/queryKeyFactory'; + +interface Props { + enabled?: boolean; +} + +export const useApiTokens = ({ enabled = true }: Props = {}) => { + const queryKey = QueryKey.apiPools(); + + const query = useQuery( + queryKey, + async () => { + try { + const pools = await BancorApi.v3.getTokens(); + return new Map(pools.map((t) => [t.dltId, t])); + } catch (e: any) { + throw new Error( + 'useQuery failed: ' + queryKey.join('-') + ' MSG: ' + e.message + ); + } + }, + { + enabled, + useErrorBoundary: true, + } + ); + + const getApiPoolByID = (id: string) => query.data?.get(id); + + return { ...query, getApiPoolByID }; +}; diff --git a/src/queries/api/useApiVolume.ts b/src/queries/api/useApiVolume.ts index ae9a7f7a9..31f40e0c8 100644 --- a/src/queries/api/useApiVolume.ts +++ b/src/queries/api/useApiVolume.ts @@ -11,7 +11,7 @@ export const useApiVolume = ({ enabled = true }: Props = {}) => { const data = new Map( poolIds.data?.map((id) => { - const apiPool = apiPools.getApiPoolByID(id); + const apiPool = apiPools.getByID(id); if (!apiPool) { return [id, undefined]; diff --git a/src/queries/types.ts b/src/queries/types.ts index 5c28dd790..49760cfc9 100644 --- a/src/queries/types.ts +++ b/src/queries/types.ts @@ -1,4 +1,5 @@ import { RewardsProgramRaw } from 'services/web3/v3/portfolio/standardStaking'; +import { PriceDictionary } from 'services/api/bancorApi/bancorApi.types'; export interface PriceDictionaryV3 { bnt?: string; @@ -31,6 +32,8 @@ export interface PoolV3Chain { depositingEnabled: boolean; programs: RewardsProgramRaw[]; logoURI: string; + rate?: PriceDictionary; + rate24hAgo?: PriceDictionary; latestProgram?: RewardsProgramRaw; balance?: { tkn: string; diff --git a/src/queries/usePoolPick.ts b/src/queries/usePoolPick.ts index 23781b56c..6f673b04b 100644 --- a/src/queries/usePoolPick.ts +++ b/src/queries/usePoolPick.ts @@ -12,10 +12,11 @@ import { useChainLatestProgram } from 'queries/chain/useChainLatestProgram'; import { PoolV3Chain } from 'queries/types'; import { useChainBalances } from 'queries/chain/useChainBalances'; import { useChainPoolIds } from 'queries/chain/useChainPoolIds'; +import { useApiRate } from 'queries/api/useApiRate'; type PoolNew = Omit< PoolV3Chain, - 'name' | 'logoURI' | 'standardRewards' | 'tradingFeePPM' + 'name' | 'logoURI' | 'standardRewards' | 'tradingFeePPM' | 'rate24hAgo' >; type PoolKey = keyof PoolNew; @@ -80,6 +81,10 @@ const useFetchers = (select: PoolKey[]) => { enabled: set.has('volume'), }); + const rate = useApiRate({ + enabled: set.has('rate'), + }); + const stakedBalance = useApiStakedBalance({ enabled: set.has('stakedBalance'), }); @@ -108,6 +113,7 @@ const useFetchers = (select: PoolKey[]) => { stakedBalance, latestProgram, balance, + rate, }; const isLoading = select.some((res) => fetchers[res].isLoading); From 7ca6b80d724a7295cc89a1f6e31b8990f937d773 Mon Sep 17 00:00:00 2001 From: Jan Langheimer Date: Thu, 21 Jul 2022 11:00:09 +0200 Subject: [PATCH 26/36] remove unused code --- src/store/bancor/pool.ts | 58 ---------------------------------------- 1 file changed, 58 deletions(-) diff --git a/src/store/bancor/pool.ts b/src/store/bancor/pool.ts index 2cb874502..4fa975445 100644 --- a/src/store/bancor/pool.ts +++ b/src/store/bancor/pool.ts @@ -4,7 +4,6 @@ import { RootState } from 'store'; import { isEqual, orderBy } from 'lodash'; import { createSelectorCreator, defaultMemoize } from 'reselect'; import { Pool, PoolV3 } from 'services/observables/pools'; -import { bntToken } from 'services/web3/config'; interface PoolState { v2Pools: Pool[]; @@ -32,13 +31,6 @@ const poolSlice = createSlice({ }, }); -export interface TopPool { - tknSymbol: string; - tknLogoURI: string; - apr: number; - poolName: string; -} - export const getPools = createSelector( (state: RootState) => state.pool.v2Pools, (state: RootState) => state.bancor.tokensV2, @@ -78,51 +70,6 @@ export const getProtectedPools = createSelector(getPools, (pools: Pool[]) => pools.filter((p) => p.isProtected) ); -export const getTopPools = createSelector(getPools, (pools: Pool[]) => { - const filteredPools = pools - .filter((p) => p.isProtected && p.liquidity > 100000) - .map((p) => { - return { - tknSymbol: p.reserves[0].symbol, - tknLogoURI: p.reserves[0].logoURI, - tknApr: p.apr_24h + (p.reserves[0].rewardApr || 0), - bntSymbol: p.reserves[1].symbol, - bntLogoURI: p.reserves[1].logoURI, - bntApr: p.apr_24h + (p.reserves[1].rewardApr || 0), - poolName: p.name, - }; - }); - const winningBntPool = orderBy(filteredPools, 'bntApr', 'desc').slice(0, 1); - const topPools: TopPool[] = filteredPools.map((p) => { - return { - tknSymbol: p.tknSymbol, - tknLogoURI: p.tknLogoURI, - poolName: p.poolName, - apr: p.tknApr, - }; - }); - if (winningBntPool.length === 1) { - topPools.push({ - tknSymbol: winningBntPool[0].bntSymbol, - tknLogoURI: winningBntPool[0].bntLogoURI, - apr: winningBntPool[0].bntApr, - poolName: winningBntPool[0].poolName, - }); - } - return orderBy(topPools, 'apr', 'desc').slice(0, 20); -}); - -export const getTopPoolsV3 = createSelector( - (state: RootState) => state.pool.v3Pools, - (pools: PoolV3[]) => { - return orderBy( - pools.filter((p) => p.apr7d.total > 0), - 'apr7d.total', - 'desc' - ).slice(0, 20); - } -); - export const getIsV3Exist = createSelector( [(state: RootState) => getPoolsV3Map(state), (_: any, id: string) => id], (pools: Map, id): boolean => { @@ -130,11 +77,6 @@ export const getIsV3Exist = createSelector( } ); -export const getBNTPoolV3 = createSelector( - (state: RootState) => getPoolsV3Map(state), - (pools: Map): PoolV3 | undefined => pools.get(bntToken) -); - export interface SelectedPool { status: 'loading' | 'ready'; pool?: Pool; From 77d702bb8949c10070d096cc5718c0398e33760f Mon Sep 17 00:00:00 2001 From: Jan Langheimer Date: Thu, 21 Jul 2022 11:46:58 +0200 Subject: [PATCH 27/36] add sentry error reporting --- .env.sample | 2 + package.json | 7 +-- src/index.tsx | 25 +++++----- src/queries/api/useApiTokens.ts | 2 +- src/queries/queryKeyFactory.ts | 1 + src/queries/usePoolPick.ts | 3 +- src/react-app-env.d.ts | 1 + src/sentry/ErrorBoundary.tsx | 22 +++++++++ src/sentry/ErrorBoundaryFallback.tsx | 22 +++++++++ yarn.lock | 72 ++++++++++++++++++++++++---- 10 files changed, 133 insertions(+), 24 deletions(-) create mode 100644 src/sentry/ErrorBoundary.tsx create mode 100644 src/sentry/ErrorBoundaryFallback.tsx diff --git a/.env.sample b/.env.sample index dc1decd5c..636b129d9 100644 --- a/.env.sample +++ b/.env.sample @@ -1,7 +1,9 @@ +REACT_APP_DEBUG_MODE= REACT_APP_ALCHEMY_MAINNET= REACT_APP_ALCHEMY_ROPSTEN= REACT_APP_PORTIS_DAPP_ID= REACT_APP_FORTMATIC_API_KEY= REACT_APP_APY_VISION_TOKEN= REACT_APP_INTOTHEBLOCK_KEY= +REACT_APP_SENTRY_DSN= GENERATE_SOURCEMAP=false diff --git a/package.json b/package.json index 461d395be..2346f38c4 100644 --- a/package.json +++ b/package.json @@ -8,6 +8,8 @@ "@headlessui/react": "^1.3.0", "@popperjs/core": "^2.9.3", "@reduxjs/toolkit": "^1.6.2", + "@sentry/react": "^7.7.0", + "@sentry/tracing": "^7.7.0", "@tanstack/react-query": "^4.0.5", "@tanstack/react-query-devtools": "^4.0.5", "@types/jest": "^26.0.15", @@ -42,7 +44,6 @@ "react-chartjs-2": "^4.0.1", "react-device-detect": "^2.1.2", "react-dom": "^17.0.2", - "react-error-boundary": "^3.1.4", "react-intl": "^5.17.6", "react-popper": "^2.2.5", "react-router-dom": "6", @@ -59,10 +60,10 @@ "@storybook/addon-actions": "6.5.9", "@storybook/addon-essentials": "6.5.9", "@storybook/addon-links": "6.5.9", - "@storybook/node-logger": "6.5.9", - "@storybook/preset-create-react-app": "4.1.2", "@storybook/builder-webpack5": "6.5.9", "@storybook/manager-webpack5": "6.5.9", + "@storybook/node-logger": "6.5.9", + "@storybook/preset-create-react-app": "4.1.2", "@storybook/react": "6.5.9", "@typechain/ethers-v5": "^8.0.2", "@types/json-bigint": "^1.0.0", diff --git a/src/index.tsx b/src/index.tsx index b0e38339b..8a6e1ba73 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -9,19 +9,22 @@ import { getLibrary } from 'services/web3/wallet/utils'; import { Web3ReactProvider } from '@web3-react/core'; import 'styles/index.css'; import { QueryClientProvider } from 'queries'; +import { SentryErrorBoundary } from 'sentry/ErrorBoundary'; ReactDOM.render( - - - - - - - - - - - , + + + + + + + + + + + + + , document.getElementById('root') ); diff --git a/src/queries/api/useApiTokens.ts b/src/queries/api/useApiTokens.ts index 4a286353f..f59a4cb3c 100644 --- a/src/queries/api/useApiTokens.ts +++ b/src/queries/api/useApiTokens.ts @@ -7,7 +7,7 @@ interface Props { } export const useApiTokens = ({ enabled = true }: Props = {}) => { - const queryKey = QueryKey.apiPools(); + const queryKey = QueryKey.apiTokens(); const query = useQuery( queryKey, diff --git a/src/queries/queryKeyFactory.ts b/src/queries/queryKeyFactory.ts index bad4af192..b4a7a1fb7 100644 --- a/src/queries/queryKeyFactory.ts +++ b/src/queries/queryKeyFactory.ts @@ -54,6 +54,7 @@ export abstract class QueryKey { static api = () => [...this.v3(), 'api']; static apiPools = () => [...this.api(), 'pools']; + static apiTokens = () => [...this.api(), 'tokens']; static apiBnt = () => [...this.api(), 'bnt']; static apiFees = () => [...this.api(), 'fees']; } diff --git a/src/queries/usePoolPick.ts b/src/queries/usePoolPick.ts index 6f673b04b..74789396f 100644 --- a/src/queries/usePoolPick.ts +++ b/src/queries/usePoolPick.ts @@ -13,6 +13,7 @@ import { PoolV3Chain } from 'queries/types'; import { useChainBalances } from 'queries/chain/useChainBalances'; import { useChainPoolIds } from 'queries/chain/useChainPoolIds'; import { useApiRate } from 'queries/api/useApiRate'; +import { useChainDepositingEnabled } from 'queries/chain/useChainDepositingEnabled'; type PoolNew = Omit< PoolV3Chain, @@ -57,7 +58,7 @@ const useFetchers = (select: PoolKey[]) => { enabled: set.has('tradingEnabled'), }); - const depositingEnabled = useChainTradingEnabled({ + const depositingEnabled = useChainDepositingEnabled({ enabled: set.has('depositingEnabled'), }); diff --git a/src/react-app-env.d.ts b/src/react-app-env.d.ts index 2771604c9..36da1c035 100644 --- a/src/react-app-env.d.ts +++ b/src/react-app-env.d.ts @@ -9,5 +9,6 @@ declare namespace NodeJS { REACT_APP_PORTIS_DAPP_ID: string; REACT_APP_APY_VISION_TOKEN: string; REACT_APP_INTOTHEBLOCK_KEY: string; + REACT_APP_SENTRY_DSN: string; } } diff --git a/src/sentry/ErrorBoundary.tsx b/src/sentry/ErrorBoundary.tsx new file mode 100644 index 000000000..bbdfe169e --- /dev/null +++ b/src/sentry/ErrorBoundary.tsx @@ -0,0 +1,22 @@ +import * as Sentry from '@sentry/react'; +import { BrowserTracing } from '@sentry/tracing'; +import { ReactNode } from 'react'; +import { ErrorBoundaryFallback } from 'sentry/ErrorBoundaryFallback'; + +Sentry.init({ + dsn: process.env.REACT_APP_SENTRY_DSN, + integrations: [new BrowserTracing()], + + // We recommend adjusting this value in production, or using tracesSampler + // for finer control + tracesSampleRate: 1.0, +}); + +export const SentryErrorBoundary = ({ children }: { children: ReactNode }) => { + return ( + // @ts-ignore + + {children} + + ); +}; diff --git a/src/sentry/ErrorBoundaryFallback.tsx b/src/sentry/ErrorBoundaryFallback.tsx new file mode 100644 index 000000000..9b79f60d9 --- /dev/null +++ b/src/sentry/ErrorBoundaryFallback.tsx @@ -0,0 +1,22 @@ +import { JSXElementConstructor, ReactElement } from 'react'; +import * as Sentry from '@sentry/react'; + +type FallbackComponent = + | ReactElement> + | Sentry.FallbackRender + | undefined; + +export const ErrorBoundaryFallback: FallbackComponent = ({ + error, + componentStack, +}) => { + return ( +
+

Internal Error

+

Name: {error.name && error.name}

+

Message: {error.message && error.message}

+
Component Stack: {componentStack}
+
{JSON.stringify(error, null, 2)}
+
+ ); +}; diff --git a/yarn.lock b/yarn.lock index 059d39a0d..09171555b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2351,6 +2351,69 @@ resolved "https://registry.yarnpkg.com/@rushstack/eslint-patch/-/eslint-patch-1.1.4.tgz#0c8b74c50f29ee44f423f7416829c0bf8bb5eb27" integrity sha512-LwzQKA4vzIct1zNZzBmRKI9QuNpLgTQMEjsQLf3BXuGYb3QPTP4Yjf6mkdX+X1mYttZ808QpOwAzZjv28kq7DA== +"@sentry/browser@7.7.0": + version "7.7.0" + resolved "https://registry.yarnpkg.com/@sentry/browser/-/browser-7.7.0.tgz#7810ee98d4969bd0367e29ac0af6c5779db7e6c4" + integrity sha512-oyzpWcsjVZTaf14zAL89Ng1DUHlbjN+V8pl8dR9Y9anphbzL5BK9p0fSK4kPIrO4GukK+XrKnLJDPuE/o7WR3g== + dependencies: + "@sentry/core" "7.7.0" + "@sentry/types" "7.7.0" + "@sentry/utils" "7.7.0" + tslib "^1.9.3" + +"@sentry/core@7.7.0": + version "7.7.0" + resolved "https://registry.yarnpkg.com/@sentry/core/-/core-7.7.0.tgz#1a2d477897552d179380f7c54c7d81a4e98ea29a" + integrity sha512-Z15ACiuiFINFcK4gbMrnejLn4AVjKBPJOWKrrmpIe8mh+Y9diOuswt5mMUABs+jhpZvqht3PBLLGBL0WMsYMYA== + dependencies: + "@sentry/hub" "7.7.0" + "@sentry/types" "7.7.0" + "@sentry/utils" "7.7.0" + tslib "^1.9.3" + +"@sentry/hub@7.7.0": + version "7.7.0" + resolved "https://registry.yarnpkg.com/@sentry/hub/-/hub-7.7.0.tgz#9ad3471cf5ecaf1a9d3a3a04ca2515ffec9e2c09" + integrity sha512-6gydK234+a0nKhBRDdIJ7Dp42CaiW2juTiHegUVDq+482balVzbZyEAmESCmuzKJhx5BhlCElVxs/cci1NjMpg== + dependencies: + "@sentry/types" "7.7.0" + "@sentry/utils" "7.7.0" + tslib "^1.9.3" + +"@sentry/react@^7.7.0": + version "7.7.0" + resolved "https://registry.yarnpkg.com/@sentry/react/-/react-7.7.0.tgz#a519dd727f863c1abf1a77beac01a3336c856828" + integrity sha512-93Khad3YAln6mKU9E15QH09XC1ARIOpNTRpnBl6AGl3bVhSdLExsbKDLa7Rx0mW2j4z/prOC6VEHf5mBvg4mPg== + dependencies: + "@sentry/browser" "7.7.0" + "@sentry/types" "7.7.0" + "@sentry/utils" "7.7.0" + hoist-non-react-statics "^3.3.2" + tslib "^1.9.3" + +"@sentry/tracing@^7.7.0": + version "7.7.0" + resolved "https://registry.yarnpkg.com/@sentry/tracing/-/tracing-7.7.0.tgz#67324b755a28e115289755e44a0b8b467a63d0b2" + integrity sha512-HNmvTwemuc21q/K6HXsSp9njkne6N1JQ71TB+QGqYU5VtxsVgYSUhhYqV6WcHz7LK4Hj6TvNFoeu69/rO0ysgw== + dependencies: + "@sentry/hub" "7.7.0" + "@sentry/types" "7.7.0" + "@sentry/utils" "7.7.0" + tslib "^1.9.3" + +"@sentry/types@7.7.0": + version "7.7.0" + resolved "https://registry.yarnpkg.com/@sentry/types/-/types-7.7.0.tgz#dd6bd3d119d7efea0e85dbaa4b17de1c22b63c7a" + integrity sha512-4x8O7uerSGLnYC10krHl9t8h7xXHn5FextqKYbTCXCnx2hC8D+9lz8wcbQAFo0d97wiUYqI8opmEgFVGx7c5hQ== + +"@sentry/utils@7.7.0": + version "7.7.0" + resolved "https://registry.yarnpkg.com/@sentry/utils/-/utils-7.7.0.tgz#013e3097c4268a76de578494c7df999635fb0ad4" + integrity sha512-fD+ROSFpeJlK7bEvUT2LOW7QqgjBpXJwVISKZ0P2fuzclRC3KoB2pbZgBM4PXMMTiSzRGWhvfRRjBiBvQJBBJQ== + dependencies: + "@sentry/types" "7.7.0" + tslib "^1.9.3" + "@sinclair/typebox@^0.23.3": version "0.23.5" resolved "https://registry.yarnpkg.com/@sinclair/typebox/-/typebox-0.23.5.tgz#93f7b9f4e3285a7a9ade7557d9a8d36809cbc47d" @@ -14074,13 +14137,6 @@ react-element-to-jsx-string@^14.3.4: is-plain-object "5.0.0" react-is "17.0.2" -react-error-boundary@^3.1.4: - version "3.1.4" - resolved "https://registry.yarnpkg.com/react-error-boundary/-/react-error-boundary-3.1.4.tgz#255db92b23197108757a888b01e5b729919abde0" - integrity sha512-uM9uPzZJTF6wRQORmSrvOIgt4lJ9MC1sNgEOj2XGsDTRE4kmpWxg7ENK9EWNKJRMAOY9z0MuF4yIfl6gp4sotA== - dependencies: - "@babel/runtime" "^7.12.5" - react-error-overlay@6.0.9, react-error-overlay@^6.0.11: version "6.0.9" resolved "https://registry.yarnpkg.com/react-error-overlay/-/react-error-overlay-6.0.9.tgz#3c743010c9359608c375ecd6bc76f35d93995b0a" @@ -16306,7 +16362,7 @@ tsconfig-paths@^3.14.1: minimist "^1.2.6" strip-bom "^3.0.0" -tslib@^1.8.1, tslib@^1.9.0: +tslib@^1.8.1, tslib@^1.9.0, tslib@^1.9.3: version "1.14.1" resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== From d8a9c86fcad1f5c7897a934dae453f80aee69599 Mon Sep 17 00:00:00 2001 From: Jan Langheimer Date: Thu, 21 Jul 2022 13:00:46 +0200 Subject: [PATCH 28/36] polish and small bug fixes --- src/queries/api/useApiBnt.ts | 11 +++++----- src/queries/api/useApiPools.ts | 14 ++++++------ src/queries/api/useApiStatistics.ts | 3 ++- src/queries/api/useApiTokens.ts | 6 ++---- src/queries/api/useApiV2Welcome.ts | 4 +++- src/queries/chain/useChainBalances.ts | 31 +++++++++++++++++++-------- src/queries/queryClient.tsx | 14 ++++++------ src/queries/queryOptions.ts | 13 +++++++++++ src/queries/types.ts | 1 - src/queries/usePoolPick.ts | 2 +- src/sentry/ErrorBoundaryFallback.tsx | 31 +++++++++++++++++++++------ 11 files changed, 87 insertions(+), 43 deletions(-) diff --git a/src/queries/api/useApiBnt.ts b/src/queries/api/useApiBnt.ts index 21a6e88b7..1bf6d1018 100644 --- a/src/queries/api/useApiBnt.ts +++ b/src/queries/api/useApiBnt.ts @@ -1,6 +1,7 @@ import { useQuery } from '@tanstack/react-query'; import { BancorApi } from 'services/api/bancorApi/bancorApi'; import { QueryKey } from 'queries/queryKeyFactory'; +import { queryOptionsStaleTimeHigh } from 'queries/queryOptions'; interface Props { enabled?: boolean; @@ -8,9 +9,9 @@ interface Props { export const useApiBnt = ({ enabled = true }: Props = {}) => { const queryKey = QueryKey.apiBnt(); - return useQuery(queryKey, BancorApi.v3.getBnt, { - enabled, - useErrorBoundary: true, - onError: (err) => console.error('query failed', queryKey, err), - }); + return useQuery( + queryKey, + BancorApi.v3.getBnt, + queryOptionsStaleTimeHigh(enabled) + ); }; diff --git a/src/queries/api/useApiPools.ts b/src/queries/api/useApiPools.ts index c33a87126..b9dab5afa 100644 --- a/src/queries/api/useApiPools.ts +++ b/src/queries/api/useApiPools.ts @@ -1,6 +1,7 @@ import { useQuery } from '@tanstack/react-query'; import { BancorApi } from 'services/api/bancorApi/bancorApi'; import { QueryKey } from 'queries/queryKeyFactory'; +import { queryOptionsStaleTimeHigh } from 'queries/queryOptions'; interface Props { enabled?: boolean; @@ -16,15 +17,14 @@ export const useApiPools = ({ enabled = true }: Props = {}) => { const pools = await BancorApi.v3.getPoolsWithBNT(); return new Map(pools.map((p) => [p.poolDltId, p])); } catch (e: any) { - throw new Error( - 'useQuery failed: ' + queryKey.join('-') + ' MSG: ' + e.message - ); + throw { + ...e, + message: + 'useQuery failed: ' + queryKey.join('-') + ' MSG: ' + e.message, + }; } }, - { - enabled, - useErrorBoundary: true, - } + queryOptionsStaleTimeHigh(enabled) ); const getByID = (id: string) => query.data?.get(id); diff --git a/src/queries/api/useApiStatistics.ts b/src/queries/api/useApiStatistics.ts index 5bfc768a9..32e7af42e 100644 --- a/src/queries/api/useApiStatistics.ts +++ b/src/queries/api/useApiStatistics.ts @@ -8,6 +8,7 @@ import { useApiV2Welcome } from 'queries/api/useApiV2Welcome'; import { WelcomeData } from 'services/api/bancorApi/bancorApi.types'; import { genericFailedNotification } from 'services/notifications/notifications'; import { useDispatch } from 'react-redux'; +import { queryOptionsStaleTimeHigh } from 'queries/queryOptions'; export interface Statistic { label: string; @@ -103,7 +104,7 @@ export const useApiStatistics = () => { ['api', 'v3', 'statistics'], () => fetchStatistics(apiDataV2!), { - enabled: !!apiDataV2, + ...queryOptionsStaleTimeHigh(!!apiDataV2), useErrorBoundary: false, onError: (err: any) => { genericFailedNotification( diff --git a/src/queries/api/useApiTokens.ts b/src/queries/api/useApiTokens.ts index f59a4cb3c..501029499 100644 --- a/src/queries/api/useApiTokens.ts +++ b/src/queries/api/useApiTokens.ts @@ -1,6 +1,7 @@ import { useQuery } from '@tanstack/react-query'; import { BancorApi } from 'services/api/bancorApi/bancorApi'; import { QueryKey } from 'queries/queryKeyFactory'; +import { queryOptionsStaleTimeHigh } from 'queries/queryOptions'; interface Props { enabled?: boolean; @@ -21,10 +22,7 @@ export const useApiTokens = ({ enabled = true }: Props = {}) => { ); } }, - { - enabled, - useErrorBoundary: true, - } + queryOptionsStaleTimeHigh(enabled) ); const getApiPoolByID = (id: string) => query.data?.get(id); diff --git a/src/queries/api/useApiV2Welcome.ts b/src/queries/api/useApiV2Welcome.ts index 97335c53f..94d25e4c0 100644 --- a/src/queries/api/useApiV2Welcome.ts +++ b/src/queries/api/useApiV2Welcome.ts @@ -1,10 +1,12 @@ import { useQuery } from '@tanstack/react-query'; import { BancorApi } from 'services/api/bancorApi/bancorApi'; import { WelcomeData } from 'services/api/bancorApi/bancorApi.types'; +import { queryOptionsStaleTimeHigh } from 'queries/queryOptions'; export const useApiV2Welcome = () => { return useQuery( ['api', 'v2', 'welcome'], - BancorApi.v2.getWelcome + BancorApi.v2.getWelcome, + queryOptionsStaleTimeHigh() ); }; diff --git a/src/queries/chain/useChainBalances.ts b/src/queries/chain/useChainBalances.ts index e041ef407..c0516adac 100644 --- a/src/queries/chain/useChainBalances.ts +++ b/src/queries/chain/useChainBalances.ts @@ -13,12 +13,14 @@ interface Props { export const useChainBalances = ({ enabled = true }: Props = {}) => { const user = useAppSelector((state) => state.user.account); - const { data: poolIds } = useChainPoolIds(); - const { data: poolTokenIds } = useChainPoolTokenIds({ enabled }); - const { data: decimals } = useChainTokenDecimals({ enabled }); + const poolIds = useChainPoolIds(); + const poolTokenIds = useChainPoolTokenIds({ enabled }); + const decimals = useChainTokenDecimals({ enabled }); - const tknIds = poolIds ?? []; - const bnTknIds = poolTokenIds ? Array.from(poolTokenIds.values()) : []; + const tknIds = poolIds.data ?? []; + const bnTknIds = poolTokenIds.data + ? Array.from(poolTokenIds.data.values()) + : []; const query = useQuery( ['chain', 'balances', user], @@ -28,20 +30,31 @@ export const useChainBalances = ({ enabled = true }: Props = {}) => { user! ), { - enabled: !!user && !!poolIds && !!poolTokenIds && !!decimals && enabled, + enabled: + !!user && + !!poolIds.data && + !!poolTokenIds.data && + !!decimals.data && + enabled, useErrorBoundary: false, } ); const getByID = (id: string) => { if (!user) return undefined; - const poolTokenId = poolTokenIds?.get(id) ?? ''; - const dec = decimals?.get(id) ?? 0; + const poolTokenId = poolTokenIds.data?.get(id) ?? ''; + const dec = decimals.data?.get(id) ?? 0; return { tkn: shrinkToken(query.data?.get(id) ?? '0', dec), bnTkn: shrinkToken(query.data?.get(poolTokenId) ?? '0', dec), }; }; - return { ...query, getByID, isLoading: query.isLoading && query.isFetching }; + const queries = [poolIds, poolTokenIds, decimals, query]; + + const isLoading = queries.some((q) => q.isLoading); + const isFetching = queries.some((q) => q.isFetching); + const isError = queries.some((q) => q.isError); + + return { ...query, getByID, isLoading, isFetching, isError }; }; diff --git a/src/queries/queryClient.tsx b/src/queries/queryClient.tsx index bd1c73aae..a054b70c1 100644 --- a/src/queries/queryClient.tsx +++ b/src/queries/queryClient.tsx @@ -1,19 +1,19 @@ import { QueryClient, QueryClientProvider as QueryClientP, + QueryClientConfig, } from '@tanstack/react-query'; import { ReactNode } from 'react'; import { ReactQueryDevtools } from '@tanstack/react-query-devtools'; +import { queryOptionsDefaults } from 'queries/queryOptions'; -const queryClient = new QueryClient({ +const config: QueryClientConfig = { defaultOptions: { - queries: { - refetchInterval: 60000, - staleTime: 30000, - useErrorBoundary: true, - }, + queries: queryOptionsDefaults(), }, -}); +}; + +const queryClient = new QueryClient(config); export const QueryClientProvider = ({ children }: { children: ReactNode }) => { return ( diff --git a/src/queries/queryOptions.ts b/src/queries/queryOptions.ts index 0a7622731..0b987f321 100644 --- a/src/queries/queryOptions.ts +++ b/src/queries/queryOptions.ts @@ -1,3 +1,10 @@ +export const queryOptionsDefaults = (enabled?: boolean) => ({ + enabled, + refetchInterval: 60000, + staleTime: 30000, + useErrorBoundary: true, +}); + export const queryOptionsNoInterval = (enabled?: boolean) => ({ enabled, refetchInterval: 0, @@ -9,3 +16,9 @@ export const queryOptionsStaleTimeLow = (enabled?: boolean) => ({ refetchInterval: 5 * 60 * 1000, staleTime: 5 * 60 * 1000, }); + +export const queryOptionsStaleTimeHigh = (enabled?: boolean) => ({ + enabled, + refetchInterval: 15 * 1000, + staleTime: 15 * 1000, +}); diff --git a/src/queries/types.ts b/src/queries/types.ts index 49760cfc9..ca913603c 100644 --- a/src/queries/types.ts +++ b/src/queries/types.ts @@ -31,7 +31,6 @@ export interface PoolV3Chain { tradingEnabled: boolean; depositingEnabled: boolean; programs: RewardsProgramRaw[]; - logoURI: string; rate?: PriceDictionary; rate24hAgo?: PriceDictionary; latestProgram?: RewardsProgramRaw; diff --git a/src/queries/usePoolPick.ts b/src/queries/usePoolPick.ts index 74789396f..b21286ff3 100644 --- a/src/queries/usePoolPick.ts +++ b/src/queries/usePoolPick.ts @@ -17,7 +17,7 @@ import { useChainDepositingEnabled } from 'queries/chain/useChainDepositingEnabl type PoolNew = Omit< PoolV3Chain, - 'name' | 'logoURI' | 'standardRewards' | 'tradingFeePPM' | 'rate24hAgo' + 'name' | 'standardRewards' | 'tradingFeePPM' | 'rate24hAgo' >; type PoolKey = keyof PoolNew; diff --git a/src/sentry/ErrorBoundaryFallback.tsx b/src/sentry/ErrorBoundaryFallback.tsx index 9b79f60d9..57be9ef98 100644 --- a/src/sentry/ErrorBoundaryFallback.tsx +++ b/src/sentry/ErrorBoundaryFallback.tsx @@ -1,5 +1,6 @@ import { JSXElementConstructor, ReactElement } from 'react'; import * as Sentry from '@sentry/react'; +import { Page } from 'components/Page'; type FallbackComponent = | ReactElement> @@ -11,12 +12,28 @@ export const ErrorBoundaryFallback: FallbackComponent = ({ componentStack, }) => { return ( -
-

Internal Error

-

Name: {error.name && error.name}

-

Message: {error.message && error.message}

-
Component Stack: {componentStack}
-
{JSON.stringify(error, null, 2)}
-
+ +

Description

+

+ {error.name && `${error.name} - `} {error.message && error.message} +

+ +
+ +

Component Stack

+
{componentStack}
+ +
+ +

Error JSON

+
+
{JSON.stringify(error, null, 2)}
+
+ ); }; From ddfed89b3e7e1701cd45989eeab3c4abde2710bf Mon Sep 17 00:00:00 2001 From: Jan Langheimer Date: Thu, 21 Jul 2022 13:06:40 +0200 Subject: [PATCH 29/36] fix vote approval tmp --- src/elements/vote/VoteStakeModal.tsx | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/elements/vote/VoteStakeModal.tsx b/src/elements/vote/VoteStakeModal.tsx index 409c6b7da..5d34f62f1 100644 --- a/src/elements/vote/VoteStakeModal.tsx +++ b/src/elements/vote/VoteStakeModal.tsx @@ -26,7 +26,7 @@ const useApproval = (id: string, amount: string, spender: string) => { const getAllowance = async () => { if (!account || !query.data || query.isLoading) { - throw new Error('Error muhhh'); + throw new Error('Error getAllowance'); } setIsLoadingAllowance(true); const amountWei = expandToken(amount, query.data.decimals); @@ -58,8 +58,10 @@ const useApproval = (id: string, amount: string, spender: string) => { }; useAsyncEffect(async () => { - await getAllowance(); - }, [id, amount]); + if (account && query.data && !query.isLoading) { + await getAllowance(); + } + }, [id, amount, account]); return { approvalRequired, isLoading, setAllowance }; }; From cc424a0fb4c5c71b139385503aa573cf2ea47dcf Mon Sep 17 00:00:00 2001 From: Jan Langheimer Date: Tue, 26 Jul 2022 17:07:44 +0200 Subject: [PATCH 30/36] fix subscribeToObservables based on pathname --- src/App.tsx | 9 +-------- src/router/BancorRouter.tsx | 13 ++++++++++++- 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/src/App.tsx b/src/App.tsx index 2dee1f197..9b0d3b2dd 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -20,7 +20,6 @@ import { getUsdToggleLS, setNotificationsLS, } from 'utils/localStorage'; -import { subscribeToObservables } from 'services/observables/triggers'; import { isUnsupportedNetwork } from 'utils/helperFunctions'; import { MobileBottomNav } from 'elements/layoutHeader/MobileBottomNav'; import { useWeb3React } from '@web3-react/core'; @@ -36,7 +35,6 @@ const handleModeChange = (_: MediaQueryListEvent) => { export const App = () => { const dispatch = useDispatch(); const { chainId, account } = useWeb3React(); - const pathname = window.location.pathname; useAutoConnect(); const unsupportedNetwork = isUnsupportedNetwork(chainId); const notifications = useAppSelector( @@ -73,14 +71,9 @@ export const App = () => { const slippage = getSlippageToleranceLS(); if (slippage) dispatch(setSlippageTolerance(slippage)); - if (pathname !== '/vote' && pathname !== '/earn') { - subscribeToObservables(dispatch); - } - console.log(pathname); - const dark = getDarkModeLS(); dispatch(setDarkMode(dark)); - }, [dispatch, pathname]); + }, [dispatch]); useEffect(() => { setNotificationsLS(notifications); diff --git a/src/router/BancorRouter.tsx b/src/router/BancorRouter.tsx index 1a5e54aa3..8d17e2249 100644 --- a/src/router/BancorRouter.tsx +++ b/src/router/BancorRouter.tsx @@ -1,11 +1,22 @@ -import { RouteObject, useRoutes } from 'react-router-dom'; +import { RouteObject, useLocation, useRoutes } from 'react-router-dom'; import { useRoutesTrade } from 'router/useRoutesTrade'; import { useRoutesPortfolio } from 'router/useRoutesPortfolio'; import { useRoutesMain } from 'router/useRoutesMain'; import { useRoutesEarn } from 'router/useRoutesEarn'; import { useRoutesRedirect } from 'router/useRoutesRedirect'; +import { useEffect } from 'react'; +import { subscribeToObservables } from 'services/observables/triggers'; +import { useDispatch } from 'react-redux'; export const BancorRouter = () => { + const dispatch = useDispatch(); + const { pathname } = useLocation(); + useEffect(() => { + if (pathname !== '/earn') { + subscribeToObservables(dispatch); + } + }, [dispatch, pathname]); + const routes: RouteObject[] = [ ...useRoutesTrade(), ...useRoutesEarn(), From cc9c57129af4ad809f5d43e54f2cb4c20bee46b5 Mon Sep 17 00:00:00 2001 From: Jan Langheimer Date: Mon, 1 Aug 2022 11:06:38 +0200 Subject: [PATCH 31/36] align with main and resolve conflicts --- src/components/tokenInput/TokenInputV3.tsx | 10 +- src/components/tokenInput/useTokenInputV3.tsx | 18 ++- ...geV3.tsx => TokenInputPercentageV3New.tsx} | 38 +++--- .../earn/pools/poolsTable/PoolsTable.tsx | 4 +- .../pools/poolsTable/v3/DepositV3Modal.tsx | 12 +- .../v3/initWithdraw/step1/V3WithdrawStep1.tsx | 2 +- src/elements/vote/VoteCardStep3.tsx | 26 ++++ src/elements/vote/VoteStakeModal.tsx | 117 +++++++++++------- src/pages/Vote2.tsx | 13 +- src/pages/earn/portfolio/MigrateProtect.tsx | 2 +- src/utils/pureFunctions.ts | 3 + 11 files changed, 158 insertions(+), 87 deletions(-) rename src/components/tokenInputPercentage/{TokenInputPercentageV3.tsx => TokenInputPercentageV3New.tsx} (73%) create mode 100644 src/elements/vote/VoteCardStep3.tsx diff --git a/src/components/tokenInput/TokenInputV3.tsx b/src/components/tokenInput/TokenInputV3.tsx index 51a3c0d72..4f5fa198a 100644 --- a/src/components/tokenInput/TokenInputV3.tsx +++ b/src/components/tokenInput/TokenInputV3.tsx @@ -2,12 +2,12 @@ import { memo, useMemo } from 'react'; import { prettifyNumber } from 'utils/helperFunctions'; import { useResizeTokenInput } from 'components/tokenInput/useResizeTokenInput'; import { useTokenInputV3 } from 'components/tokenInput/useTokenInputV3'; -import { Token } from 'services/observables/tokens'; import useDimensions from 'hooks/useDimensions'; import { Image } from 'components/image/Image'; +import { getBancorLogoUrl } from 'utils/pureFunctions'; export interface TokenInputV3Props { - token: Token; + dltId: string; inputTkn: string; setInputTkn: (amount: string) => void; inputFiat: string; @@ -17,7 +17,7 @@ export interface TokenInputV3Props { } const TokenInputV3 = ({ - token, + dltId, inputTkn, setInputTkn, inputFiat, @@ -27,7 +27,7 @@ const TokenInputV3 = ({ }: TokenInputV3Props) => { const { handleChange, inputUnit, oppositeUnit, isFocused, setIsFocused } = useTokenInputV3({ - token, + dltId, setInputTkn, setInputFiat, isFiat, @@ -55,7 +55,7 @@ const TokenInputV3 = ({ } ${isError ? 'border-error text-error' : ''}`} > {'Token diff --git a/src/components/tokenInput/useTokenInputV3.tsx b/src/components/tokenInput/useTokenInputV3.tsx index e467865a7..14a725499 100644 --- a/src/components/tokenInput/useTokenInputV3.tsx +++ b/src/components/tokenInput/useTokenInputV3.tsx @@ -1,7 +1,7 @@ -import { ChangeEvent, useCallback, useMemo, useState } from 'react'; +import { ChangeEvent, useCallback, useState } from 'react'; import { calcFiatValue, calcTknValue } from 'utils/helperFunctions'; -import { Token } from 'services/observables/tokens'; import { sanitizeNumberInput } from 'utils/pureFunctions'; +import { usePoolPick } from 'queries/index'; export const calcOppositeValue = ( isFiat: boolean, @@ -17,20 +17,24 @@ export const calcOppositeValue = ( }; export interface useTokenInputV3Props { - token: Token; + dltId: string; setInputTkn: (amount: string) => void; setInputFiat: (amount: string) => void; isFiat: boolean; } export const useTokenInputV3 = ({ - token, + dltId, setInputTkn, setInputFiat, isFiat, }: useTokenInputV3Props) => { + const { getOne } = usePoolPick(['symbol', 'decimals', 'rate']); + const { data } = getOne(dltId); + const symbol = data?.symbol; + const usdPrice = data?.rate?.usd; + const decimals = data?.decimals; const [isFocused, setIsFocused] = useState(false); - const { symbol, usdPrice, decimals } = useMemo(() => token, [token]); const inputUnit = isFiat ? 'USD' : symbol; const oppositeUnit = isFiat ? symbol : 'USD'; @@ -38,6 +42,10 @@ export const useTokenInputV3 = ({ const handleChange = useCallback( (e: ChangeEvent) => { const value = sanitizeNumberInput(e.target.value); + if (!usdPrice || !decimals) { + console.error('Missing or still loading data for calculation'); + return; + } if (isFiat) { const oppositeValue = value diff --git a/src/components/tokenInputPercentage/TokenInputPercentageV3.tsx b/src/components/tokenInputPercentage/TokenInputPercentageV3New.tsx similarity index 73% rename from src/components/tokenInputPercentage/TokenInputPercentageV3.tsx rename to src/components/tokenInputPercentage/TokenInputPercentageV3New.tsx index d80fc0b70..d061d3758 100644 --- a/src/components/tokenInputPercentage/TokenInputPercentageV3.tsx +++ b/src/components/tokenInputPercentage/TokenInputPercentageV3New.tsx @@ -5,15 +5,19 @@ import TokenInputV3, { } from 'components/tokenInput/TokenInputV3'; import { useEffect, useState } from 'react'; import { calcFiatValue, prettifyNumber } from 'utils/helperFunctions'; +import { usePoolPick } from 'queries/index'; -interface TokenInputPercentageV3Props extends TokenInputV3Props { +interface TokenInputPercentageV3Props extends Omit { + dltId: string; label: string; + balance?: string; balanceLabel?: string; } const percentages = [25, 50, 75, 100]; -export const TokenInputPercentageV3 = ({ - token, +export const TokenInputPercentageV3New = ({ + dltId, + balance, inputTkn, setInputTkn, inputFiat, @@ -23,27 +27,23 @@ export const TokenInputPercentageV3 = ({ label, balanceLabel = 'Balance', }: TokenInputPercentageV3Props) => { - const fieldBalance = token.balance - ? token.balance - : token && token.balance - ? token.balance - : undefined; - + const { getOne } = usePoolPick(['decimals', 'rate']); + const { data: token } = getOne(dltId); const [selPercentage, setSelPercentage] = useState(-1); const handleSetPercentage = (percent: number) => { setSelPercentage(percentages.indexOf(percent)); - if (fieldBalance !== undefined) { - const amount = new BigNumber(fieldBalance).times(percent / 100); + if (balance !== undefined && !!token) { + const amount = new BigNumber(balance).times(percent / 100); setInputTkn(amount.toString()); - setInputFiat(calcFiatValue(amount, token.usdPrice)); + setInputFiat(calcFiatValue(amount, token.rate?.usd ?? 0)); } }; useEffect(() => { - if (fieldBalance !== undefined) { + if (balance !== undefined) { const percentage = new BigNumber(inputTkn) - .div(fieldBalance) + .div(balance) .times(100) .toNumber() .toFixed(10); @@ -51,22 +51,22 @@ export const TokenInputPercentageV3 = ({ percentages.findIndex((x) => percentage === x.toFixed(10)) ); } - }, [fieldBalance, inputTkn]); + }, [balance, inputTkn]); return (
{label} - {fieldBalance && ( + {balance && (
{token && ( (
Pool Logo diff --git a/src/elements/earn/pools/poolsTable/v3/DepositV3Modal.tsx b/src/elements/earn/pools/poolsTable/v3/DepositV3Modal.tsx index 1586d1ae1..e72cd4c2e 100644 --- a/src/elements/earn/pools/poolsTable/v3/DepositV3Modal.tsx +++ b/src/elements/earn/pools/poolsTable/v3/DepositV3Modal.tsx @@ -1,6 +1,6 @@ import { Button, ButtonSize } from 'components/button/Button'; import { PoolV3 } from 'services/observables/pools'; -import { useCallback, useMemo, useState } from 'react'; +import { ReactNode, useCallback, useMemo, useState } from 'react'; import { ContractsApi } from 'services/web3/v3/contractsApi'; import { useDispatch } from 'react-redux'; import { updatePortfolioData } from 'services/web3/v3/portfolio/helpers'; @@ -8,7 +8,6 @@ import { useAppSelector } from 'store'; import { useApproveModal } from 'hooks/useApproveModal'; import { ModalV3 } from 'components/modal/ModalV3'; import { SwapSwitch } from 'elements/swapSwitch/SwapSwitch'; -import { TokenInputPercentageV3 } from 'components/tokenInputPercentage/TokenInputPercentageV3'; import { ethToken } from 'services/web3/config'; import { Switch } from 'components/switch/Switch'; import { getTokenById } from 'store/bancor/bancor'; @@ -30,6 +29,7 @@ import { ExpandableSection } from 'components/expandableSection/ExpandableSectio import { ReactComponent as IconChevron } from 'assets/icons/chevronDown.svg'; import { getPoolsV3Map } from 'store/bancor/pool'; import { useWalletConnect } from 'elements/walletConnect/useWalletConnect'; +import { TokenInputPercentageV3New } from 'components/tokenInputPercentage/TokenInputPercentageV3New'; import { DepositEvent, sendDepositEvent, @@ -46,9 +46,7 @@ import { DepositDisabledModal } from './DepositDisabledModal'; interface Props { pool: PoolV3; - renderButton: ( - onClick: (pool_click_location?: string) => void - ) => React.ReactNode; + renderButton: (onClick: (pool_click_location?: string) => void) => ReactNode; } const REWARDS_EXTRA_GAS = 130_000; @@ -275,10 +273,10 @@ export const DepositV3Modal = ({ pool, renderButton }: Props) => { large >
- { + const [isOpen, setIsOpen] = useState(false); + const onButtonClick = () => setIsOpen(true); + + return ( + <> +
+

{title}

+

{description}

+ +
+ + + ); +}; diff --git a/src/elements/vote/VoteStakeModal.tsx b/src/elements/vote/VoteStakeModal.tsx index 5d34f62f1..c8c942370 100644 --- a/src/elements/vote/VoteStakeModal.tsx +++ b/src/elements/vote/VoteStakeModal.tsx @@ -1,4 +1,4 @@ -import { Button, ButtonSize } from 'components/button/Button'; +import { Button, ButtonSize, ButtonVariant } from 'components/button/Button'; import { ModalV3 } from 'components/modal/ModalV3'; import { usePoolPick } from 'queries'; import { useState } from 'react'; @@ -9,6 +9,8 @@ import { ContractsApi } from 'services/web3/v3/contractsApi'; import { useAppSelector } from 'store'; import useAsyncEffect from 'use-async-effect'; import { expandToken } from 'utils/formulas'; +import { TokenInputPercentageV3New } from 'components/tokenInputPercentage/TokenInputPercentageV3New'; +import { toBigNumber } from 'utils/helperFunctions'; interface Props { isOpen: boolean; @@ -74,21 +76,17 @@ export const VoteStakeModal = ({ isOpen, setIsOpen }: Props) => { const decimals = vBntQuery.data?.decimals; const account = useAppSelector((state) => state.user.account); - const { isLoading, approvalRequired, setAllowance } = useApproval( - vBntToken, - balance, - ContractsApi.Governance.contractAddress - ); - const handleStake = async () => { try { if (!decimals) { throw new Error('No decimals found'); } - const balanceWei = expandToken(balance, decimals); - const tx = await ContractsApi.Governance.write.stake(balanceWei); + const inputWei = expandToken(input, decimals); + const tx = await ContractsApi.Governance.write.stake(inputWei); await tx.wait(); await queryClient.invalidateQueries(['chain']); + setInput(''); + setIsOpen(false); console.log('muh'); } catch (e: any) { @@ -96,45 +94,80 @@ export const VoteStakeModal = ({ isOpen, setIsOpen }: Props) => { } }; - const sendMoney = async () => { - if (!account) { - throw new Error('No decimals found'); - } - try { - const tx = await ContractsApi.Token(vBntToken).write.transfer( - '0xC030109bE8960f938Cf141F2E752D69960C785E4', - expandToken(1, 18) - ); - await tx.wait(); - queryClient.invalidateQueries(['chain', 'balances']); - console.log('muh'); - } catch (e: any) { - console.error(e.message); - } - }; + const [input, setInput] = useState(''); + const [inputFiat, setInputFiat] = useState(''); + + const isInsufficientBalance = toBigNumber(balance).lt(input); + + const { isLoading, approvalRequired, setAllowance } = useApproval( + vBntToken, + input, + ContractsApi.Governance.contractAddress + ); return ( - +
- Unstaked balance: {balance} - {!isLoading && approvalRequired && ( -
-
isLoading: {isLoading ? 'true' : 'false'}
-
approvalRequired: {approvalRequired ? 'true' : 'false'}
- - +
- )} - - +
+ +
+ +
); diff --git a/src/pages/Vote2.tsx b/src/pages/Vote2.tsx index 361df1a8b..1f46bec60 100644 --- a/src/pages/Vote2.tsx +++ b/src/pages/Vote2.tsx @@ -1,17 +1,20 @@ import { Page } from 'components/Page'; import { VoteCardStep1 } from 'elements/vote/VoteCardStep1'; import { VoteCardStep2 } from 'elements/vote/VoteCardStep2'; +import { VoteCardStep3 } from 'elements/vote/VoteCardStep3'; -export const Vote2 = () => { - const title = 'Vote'; - const subtitle = - 'Bancor is a DAO managed by vBNT stakers who determine the future of the protocol with their proposals.'; +const title = 'Vote'; +const subtitle = + 'Bancor is a DAO managed by vBNT stakers who determine the future of the protocol with their proposals.'; +export const Vote2 = () => { return ( -
+
+ +
); diff --git a/src/pages/earn/portfolio/MigrateProtect.tsx b/src/pages/earn/portfolio/MigrateProtect.tsx index f713800d5..b2f369280 100644 --- a/src/pages/earn/portfolio/MigrateProtect.tsx +++ b/src/pages/earn/portfolio/MigrateProtect.tsx @@ -274,7 +274,7 @@ const Protect = () => {
$??,??? balance
(a: T, b: T, key: string[]) => { export const openNewTab = (url: string) => window.open(url, '_blank', 'noopener'); + +export const getBancorLogoUrl = (id: string) => + `https://d1wmp5nysbq9xl.cloudfront.net/ethereum/tokens/${id.toLowerCase()}.svg`; From da9ab92ec331eb2c8b7668c13a104720abc3d92f Mon Sep 17 00:00:00 2001 From: Jan Langheimer Date: Mon, 1 Aug 2022 11:48:13 +0200 Subject: [PATCH 32/36] fix react query keys and key factory --- src/queries/api/useApiStatistics.ts | 5 +- src/queries/api/useApiV2Welcome.ts | 3 +- src/queries/chain/useChainBalances.ts | 7 +- ...inTokenDecimals.ts => useChainDecimals.ts} | 4 +- .../chain/useChainDepositingEnabled.ts | 2 +- src/queries/chain/useChainLatestProgram.ts | 2 +- src/queries/chain/useChainPoolIds.ts | 2 +- src/queries/chain/useChainPoolTokenIds.ts | 2 +- src/queries/chain/useChainPrograms.ts | 2 +- ...eChainTokenSymbol.ts => useChainSymbol.ts} | 4 +- src/queries/chain/useChainTokenName.ts | 2 +- src/queries/chain/useChainTradingEnabled.ts | 2 +- src/queries/chain/useChainTradingFee.ts | 2 +- src/queries/chain/useChainTradingLiquidity.ts | 6 +- src/queries/queryKeyFactory.ts | 78 ++++++++++--------- src/queries/usePoolPick.ts | 8 +- 16 files changed, 69 insertions(+), 62 deletions(-) rename src/queries/chain/{useChainTokenDecimals.ts => useChainDecimals.ts} (87%) rename src/queries/chain/{useChainTokenSymbol.ts => useChainSymbol.ts} (87%) diff --git a/src/queries/api/useApiStatistics.ts b/src/queries/api/useApiStatistics.ts index 32e7af42e..86265ed8b 100644 --- a/src/queries/api/useApiStatistics.ts +++ b/src/queries/api/useApiStatistics.ts @@ -9,6 +9,7 @@ import { WelcomeData } from 'services/api/bancorApi/bancorApi.types'; import { genericFailedNotification } from 'services/notifications/notifications'; import { useDispatch } from 'react-redux'; import { queryOptionsStaleTimeHigh } from 'queries/queryOptions'; +import { QueryKey } from 'queries/queryKeyFactory'; export interface Statistic { label: string; @@ -101,7 +102,7 @@ export const useApiStatistics = () => { const { data: apiDataV2 } = useApiV2Welcome(); return useQuery( - ['api', 'v3', 'statistics'], + QueryKey.apiStatistics(), () => fetchStatistics(apiDataV2!), { ...queryOptionsStaleTimeHigh(!!apiDataV2), @@ -110,7 +111,7 @@ export const useApiStatistics = () => { genericFailedNotification( dispatch, `${err.message}`, - `Server Error: ${['api', 'v3', 'tokens'].join('->')}` + `Server Error: ${QueryKey.apiStatistics().join('->')}` ); }, } diff --git a/src/queries/api/useApiV2Welcome.ts b/src/queries/api/useApiV2Welcome.ts index 94d25e4c0..07cf4f3bd 100644 --- a/src/queries/api/useApiV2Welcome.ts +++ b/src/queries/api/useApiV2Welcome.ts @@ -2,10 +2,11 @@ import { useQuery } from '@tanstack/react-query'; import { BancorApi } from 'services/api/bancorApi/bancorApi'; import { WelcomeData } from 'services/api/bancorApi/bancorApi.types'; import { queryOptionsStaleTimeHigh } from 'queries/queryOptions'; +import { QueryKey } from 'queries/queryKeyFactory'; export const useApiV2Welcome = () => { return useQuery( - ['api', 'v2', 'welcome'], + QueryKey.v2ApiWelcome(), BancorApi.v2.getWelcome, queryOptionsStaleTimeHigh() ); diff --git a/src/queries/chain/useChainBalances.ts b/src/queries/chain/useChainBalances.ts index c0516adac..15b875835 100644 --- a/src/queries/chain/useChainBalances.ts +++ b/src/queries/chain/useChainBalances.ts @@ -4,8 +4,9 @@ import { useAppSelector } from 'store/index'; import { ethToken } from 'services/web3/config'; import { useChainPoolIds } from 'queries/chain/useChainPoolIds'; import { useChainPoolTokenIds } from 'queries/chain/useChainPoolTokenIds'; -import { useChainTokenDecimals } from 'queries/chain/useChainTokenDecimals'; +import { useChainDecimals } from 'queries/chain/useChainDecimals'; import { shrinkToken } from 'utils/formulas'; +import { QueryKey } from 'queries/queryKeyFactory'; interface Props { enabled?: boolean; @@ -15,7 +16,7 @@ export const useChainBalances = ({ enabled = true }: Props = {}) => { const user = useAppSelector((state) => state.user.account); const poolIds = useChainPoolIds(); const poolTokenIds = useChainPoolTokenIds({ enabled }); - const decimals = useChainTokenDecimals({ enabled }); + const decimals = useChainDecimals({ enabled }); const tknIds = poolIds.data ?? []; const bnTknIds = poolTokenIds.data @@ -23,7 +24,7 @@ export const useChainBalances = ({ enabled = true }: Props = {}) => { : []; const query = useQuery( - ['chain', 'balances', user], + QueryKey.chainBalances(user), () => fetchTokenBalanceMulticall( [...tknIds, ...bnTknIds].filter((id) => id !== ethToken), diff --git a/src/queries/chain/useChainTokenDecimals.ts b/src/queries/chain/useChainDecimals.ts similarity index 87% rename from src/queries/chain/useChainTokenDecimals.ts rename to src/queries/chain/useChainDecimals.ts index 03c1ac110..43f8370a0 100644 --- a/src/queries/chain/useChainTokenDecimals.ts +++ b/src/queries/chain/useChainDecimals.ts @@ -12,10 +12,10 @@ interface Props { enabled?: boolean; } -export const useChainTokenDecimals = ({ enabled = true }: Props = {}) => { +export const useChainDecimals = ({ enabled = true }: Props = {}) => { const { data: poolIds } = useChainPoolIds(); const query = useQuery( - QueryKey.chainCoreDecimals(poolIds?.length), + QueryKey.chainDecimals(poolIds?.length), async () => { const decimals = await fetchMulticallHelper( poolIds!.filter((id) => id !== ethToken), diff --git a/src/queries/chain/useChainDepositingEnabled.ts b/src/queries/chain/useChainDepositingEnabled.ts index 1d50ccde5..97624f73e 100644 --- a/src/queries/chain/useChainDepositingEnabled.ts +++ b/src/queries/chain/useChainDepositingEnabled.ts @@ -15,7 +15,7 @@ export const useChainDepositingEnabled = ({ enabled = true }: Props = {}) => { const { data: poolIds } = useChainPoolIds(); const query = useQuery( - QueryKey.chainCoreDepositingEnabled(poolIds?.length), + QueryKey.chainDepositingEnabled(poolIds?.length), () => fetchMulticallHelper(poolIds!, buildMulticallDepositingEnabled), queryOptionsNoInterval(!!poolIds && enabled) diff --git a/src/queries/chain/useChainLatestProgram.ts b/src/queries/chain/useChainLatestProgram.ts index 8ffb628fe..910ac3345 100644 --- a/src/queries/chain/useChainLatestProgram.ts +++ b/src/queries/chain/useChainLatestProgram.ts @@ -18,7 +18,7 @@ export const useChainLatestProgram = ({ enabled = true }: Props = {}) => { const { data: programsMap } = useChainPrograms({ enabled }); const query = useQuery( - QueryKey.chainCoreLatestProgram(poolIds?.length), + QueryKey.chainLatestProgram(poolIds?.length), async () => { const ids = await fetchMulticallHelper( poolIds!, diff --git a/src/queries/chain/useChainPoolIds.ts b/src/queries/chain/useChainPoolIds.ts index 4bf56c748..c9a89934a 100644 --- a/src/queries/chain/useChainPoolIds.ts +++ b/src/queries/chain/useChainPoolIds.ts @@ -6,7 +6,7 @@ import { bntToken } from 'services/web3/config'; export const useChainPoolIds = () => { return useQuery( - QueryKey.chainCorePoolIds(), + QueryKey.chainPoolIds(), async () => { const pools = await ContractsApi.BancorNetwork.read.liquidityPools(); return [bntToken, ...pools]; diff --git a/src/queries/chain/useChainPoolTokenIds.ts b/src/queries/chain/useChainPoolTokenIds.ts index 15be09954..d72a30846 100644 --- a/src/queries/chain/useChainPoolTokenIds.ts +++ b/src/queries/chain/useChainPoolTokenIds.ts @@ -14,7 +14,7 @@ interface Props { export const useChainPoolTokenIds = ({ enabled = true }: Props = {}) => { const { data: poolIds } = useChainPoolIds(); const query = useQuery( - QueryKey.chainCorePoolTokenIds(poolIds?.length), + QueryKey.chainPoolTokenIds(poolIds?.length), () => fetchMulticallHelper(poolIds!, buildMulticallPoolToken), queryOptionsNoInterval(!!poolIds && enabled) ); diff --git a/src/queries/chain/useChainPrograms.ts b/src/queries/chain/useChainPrograms.ts index 6f39ada1d..09c15b93e 100644 --- a/src/queries/chain/useChainPrograms.ts +++ b/src/queries/chain/useChainPrograms.ts @@ -11,7 +11,7 @@ interface Props { export const useChainPrograms = ({ enabled = true }: Props = {}) => { const { data: poolIds } = useChainPoolIds(); const query = useQuery( - QueryKey.chainCorePrograms(poolIds?.length), + QueryKey.chainPrograms(poolIds?.length), async () => { const programs = await fetchAllStandardRewards(); return new Map( diff --git a/src/queries/chain/useChainTokenSymbol.ts b/src/queries/chain/useChainSymbol.ts similarity index 87% rename from src/queries/chain/useChainTokenSymbol.ts rename to src/queries/chain/useChainSymbol.ts index fe12c8a79..fe9761619 100644 --- a/src/queries/chain/useChainTokenSymbol.ts +++ b/src/queries/chain/useChainSymbol.ts @@ -12,10 +12,10 @@ interface Props { enabled?: boolean; } -export const useChainTokenSymbol = ({ enabled = true }: Props = {}) => { +export const useChainSymbol = ({ enabled = true }: Props = {}) => { const { data: poolIds } = useChainPoolIds(); const query = useQuery( - QueryKey.chainCoreSymbols(poolIds?.length), + QueryKey.chainSymbols(poolIds?.length), async () => { const symbols = await fetchMulticallHelper( poolIds!, diff --git a/src/queries/chain/useChainTokenName.ts b/src/queries/chain/useChainTokenName.ts index 37e86362f..de36a78c9 100644 --- a/src/queries/chain/useChainTokenName.ts +++ b/src/queries/chain/useChainTokenName.ts @@ -10,7 +10,7 @@ import { export const useChainTokenName = () => { const { data: poolIds } = useChainPoolIds(); return useQuery( - QueryKey.chainCoreName(poolIds?.length), + QueryKey.chainName(poolIds?.length), () => fetchMulticallHelper(poolIds!, buildMulticallName, true), queryOptionsNoInterval(!!poolIds) ); diff --git a/src/queries/chain/useChainTradingEnabled.ts b/src/queries/chain/useChainTradingEnabled.ts index 254851289..ae1acc287 100644 --- a/src/queries/chain/useChainTradingEnabled.ts +++ b/src/queries/chain/useChainTradingEnabled.ts @@ -14,7 +14,7 @@ interface Props { export const useChainTradingEnabled = ({ enabled = true }: Props = {}) => { const { data: poolIds } = useChainPoolIds(); const query = useQuery( - QueryKey.chainCoreTradingEnabled(poolIds?.length), + QueryKey.chainTradingEnabled(poolIds?.length), () => fetchMulticallHelper(poolIds!, buildMulticallTradingEnabled), queryOptionsStaleTimeLow(!!poolIds && enabled) ); diff --git a/src/queries/chain/useChainTradingFee.ts b/src/queries/chain/useChainTradingFee.ts index c6941b0be..66702e460 100644 --- a/src/queries/chain/useChainTradingFee.ts +++ b/src/queries/chain/useChainTradingFee.ts @@ -10,7 +10,7 @@ import { export const useChainTradingFee = () => { const { data: poolIds } = useChainPoolIds(); return useQuery( - QueryKey.chainCoreTradingFee(poolIds?.length), + QueryKey.chainTradingFee(poolIds?.length), () => fetchMulticallHelper(poolIds!, buildMulticallTradingFee), { ...queryOptionsStaleTimeLow(!!poolIds), diff --git a/src/queries/chain/useChainTradingLiquidity.ts b/src/queries/chain/useChainTradingLiquidity.ts index b359c9ec5..d40bf1af0 100644 --- a/src/queries/chain/useChainTradingLiquidity.ts +++ b/src/queries/chain/useChainTradingLiquidity.ts @@ -7,7 +7,7 @@ import { fetchMulticallHelper, } from 'services/web3/multicall/multicallFunctions'; import { TradingLiquidityStructOutput } from 'services/web3/abis/types/BancorNetworkInfo'; -import { useChainTokenDecimals } from 'queries/chain/useChainTokenDecimals'; +import { useChainDecimals } from 'queries/chain/useChainDecimals'; import { utils } from 'ethers'; import { bntToken } from 'services/web3/config'; import { useApiBnt } from 'queries/api/useApiBnt'; @@ -18,11 +18,11 @@ interface Props { export const useChainTradingLiquidity = ({ enabled = true }: Props = {}) => { const { data: poolIds } = useChainPoolIds(); - const { data: decimals } = useChainTokenDecimals({ enabled }); + const { data: decimals } = useChainDecimals({ enabled }); const { data: bnt } = useApiBnt({ enabled }); const query = useQuery( - QueryKey.chainCoreTradingLiquidity(poolIds?.length), + QueryKey.chainTradingLiquidity(poolIds?.length), () => fetchMulticallHelper( poolIds!.filter((id) => id !== bntToken), diff --git a/src/queries/queryKeyFactory.ts b/src/queries/queryKeyFactory.ts index b4a7a1fb7..ce70def55 100644 --- a/src/queries/queryKeyFactory.ts +++ b/src/queries/queryKeyFactory.ts @@ -1,60 +1,64 @@ export abstract class QueryKey { - static v3 = () => ['v3']; - static chain = () => [...this.v3(), 'chain']; - static chainCore = (key?: number | string) => [...this.chain(), 'pools', key]; - static chainCorePoolIds = () => [...this.chainCore('poolIds')]; - static chainCorePoolTokenIds = (key?: number) => [ - ...this.chainCore(key), - 'poolTokenIds', + private static _v2 = () => ['v2']; + private static _v3 = () => ['v3']; + private static _chain = () => [...this._v3(), 'chain']; + private static _chainPools = (key?: number | string) => [ + ...this._chain(), + 'pools', + key, ]; - static chainCoreSymbols = (key?: number) => [ - ...this.chainCore(key), - 'symbols', + + static chainPoolIds = () => [...this._chainPools('poolIds')]; + static chainPoolTokenIds = (key?: number) => [ + ...this._chainPools(key), + 'poolTokenIds', ]; - static chainCoreDecimals = (key?: number) => [ - ...this.chainCore(key), + static chainSymbols = (key?: number) => [...this._chainPools(key), 'symbols']; + static chainDecimals = (key?: number) => [ + ...this._chainPools(key), 'decimals', ]; - static chainCoreName = (key?: number) => [...this.chainCore(key), 'name']; - static chainCoreTradingEnabled = (key?: number) => [ - ...this.chainCore(key), + static chainName = (key?: number) => [...this._chainPools(key), 'name']; + static chainTradingEnabled = (key?: number) => [ + ...this._chainPools(key), 'tradingEnabled', ]; - static chainCoreTradingLiquidity = (key?: number) => [ - ...this.chainCore(key), + static chainTradingLiquidity = (key?: number) => [ + ...this._chainPools(key), 'tradingLiquidity', ]; - static chainCoreDepositingEnabled = (key?: number) => [ - ...this.chainCore(key), + static chainDepositingEnabled = (key?: number) => [ + ...this._chainPools(key), 'depositingEnabled', ]; - static chainCoreStakedBalance = (key?: number) => [ - ...this.chainCore(key), + static chainStakedBalance = (key?: number) => [ + ...this._chainPools(key), 'stakedBalance', ]; - static chainCoreTradingFee = (key?: number) => [ - ...this.chainCore(key), + static chainTradingFee = (key?: number) => [ + ...this._chainPools(key), 'tradingFee', ]; - static chainCoreLatestProgram = (key?: number) => [ - ...this.chainCore(key), + static chainLatestProgram = (key?: number) => [ + ...this._chainPools(key), 'latestProgramId', ]; - static chainCorePrograms = (key?: number) => [ - ...this.chainCore(key), + static chainPrograms = (key?: number) => [ + ...this._chainPools(key), 'programs', ]; - static chainVoteBalance = (user?: string) => [ - ...this.chainCore(), - 'vote', + static chainBalances = (user?: string | null) => [ + ...this._chain(), + 'balances', user, ]; - static chainPools = () => [...this.chain(), 'pools']; - static chainPoolsByID = (key?: string) => [...this.chainPools(), key]; + static chainVoteBalance = (user?: string) => [...this._chain(), 'vote', user]; + + static v2ApiWelcome = () => [...this._v2(), 'api', 'welcome']; - static api = () => [...this.v3(), 'api']; - static apiPools = () => [...this.api(), 'pools']; - static apiTokens = () => [...this.api(), 'tokens']; - static apiBnt = () => [...this.api(), 'bnt']; - static apiFees = () => [...this.api(), 'fees']; + private static _v3Api = () => [...this._v3(), 'api']; + static apiPools = () => [...this._v3Api(), 'pools']; + static apiTokens = () => [...this._v3Api(), 'tokens']; + static apiBnt = () => [...this._v3Api(), 'bnt']; + static apiStatistics = () => [...this._v3Api(), 'statistics']; } diff --git a/src/queries/usePoolPick.ts b/src/queries/usePoolPick.ts index b21286ff3..ca71c7ab4 100644 --- a/src/queries/usePoolPick.ts +++ b/src/queries/usePoolPick.ts @@ -1,5 +1,5 @@ -import { useChainTokenSymbol } from 'queries/chain/useChainTokenSymbol'; -import { useChainTokenDecimals } from 'queries/chain/useChainTokenDecimals'; +import { useChainSymbol } from 'queries/chain/useChainSymbol'; +import { useChainDecimals } from 'queries/chain/useChainDecimals'; import { useChainPoolTokenIds } from 'queries/chain/useChainPoolTokenIds'; import { useChainPrograms } from 'queries/chain/useChainPrograms'; import { useChainTradingEnabled } from 'queries/chain/useChainTradingEnabled'; @@ -38,11 +38,11 @@ type PoolReturn = Pick extends infer R const useFetchers = (select: PoolKey[]) => { const set = new Set(select.map((key) => key)); - const symbol = useChainTokenSymbol({ + const symbol = useChainSymbol({ enabled: set.has('symbol'), }); - const decimals = useChainTokenDecimals({ + const decimals = useChainDecimals({ enabled: set.has('decimals'), }); From 81061eaa32a6dfb90bf27bfb3bf1250727e1c512 Mon Sep 17 00:00:00 2001 From: Jan Langheimer Date: Mon, 1 Aug 2022 12:39:04 +0200 Subject: [PATCH 33/36] use trading liquidity from api and fix react query error boundary --- .../earn/pools/poolsTable/PoolsTable.tsx | 2 +- src/queries/api/useApiBnt.ts | 17 ----- src/queries/api/useApiPools.ts | 4 +- src/queries/api/useApiStatistics.ts | 4 +- src/queries/api/useApiTokens.ts | 4 +- src/queries/api/useApiTradingLiquidity.ts | 34 +++++++++ src/queries/api/useApiV2Welcome.ts | 4 +- src/queries/chain/useChainBalances.ts | 2 +- src/queries/chain/useChainDecimals.ts | 5 +- .../chain/useChainDepositingEnabled.ts | 5 +- src/queries/chain/useChainLatestProgram.ts | 5 +- src/queries/chain/useChainPoolIds.ts | 7 +- src/queries/chain/useChainPoolTokenIds.ts | 5 +- src/queries/chain/useChainPrograms.ts | 5 +- src/queries/chain/useChainSymbol.ts | 5 +- src/queries/chain/useChainTokenName.ts | 17 ----- src/queries/chain/useChainTradingEnabled.ts | 7 +- src/queries/chain/useChainTradingFee.ts | 5 +- src/queries/chain/useChainTradingLiquidity.ts | 73 ------------------- src/queries/queryOptions.ts | 14 ++-- src/queries/types.ts | 6 +- src/queries/usePoolPick.ts | 4 +- 22 files changed, 93 insertions(+), 141 deletions(-) delete mode 100644 src/queries/api/useApiBnt.ts create mode 100644 src/queries/api/useApiTradingLiquidity.ts delete mode 100644 src/queries/chain/useChainTokenName.ts delete mode 100644 src/queries/chain/useChainTradingLiquidity.ts diff --git a/src/elements/earn/pools/poolsTable/PoolsTable.tsx b/src/elements/earn/pools/poolsTable/PoolsTable.tsx index d79ba2696..c4cd2cc9f 100644 --- a/src/elements/earn/pools/poolsTable/PoolsTable.tsx +++ b/src/elements/earn/pools/poolsTable/PoolsTable.tsx @@ -61,7 +61,7 @@ export const PoolsTable = ({ (p) => p.symbol.toLowerCase().includes(search.toLowerCase()) && (lowVolume || Number(p.volume?.volume24h?.usd) > 5000) && - (lowLiquidity || Number(p.tradingLiquidity.TKN.usd) > 50000) && + (lowLiquidity || Number(p.tradingLiquidity?.TKN.usd) > 50000) && (lowEarnRate || (p.apr?.apr7d?.total ?? 0) > 0.15) ) : []; diff --git a/src/queries/api/useApiBnt.ts b/src/queries/api/useApiBnt.ts deleted file mode 100644 index 1bf6d1018..000000000 --- a/src/queries/api/useApiBnt.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { useQuery } from '@tanstack/react-query'; -import { BancorApi } from 'services/api/bancorApi/bancorApi'; -import { QueryKey } from 'queries/queryKeyFactory'; -import { queryOptionsStaleTimeHigh } from 'queries/queryOptions'; - -interface Props { - enabled?: boolean; -} - -export const useApiBnt = ({ enabled = true }: Props = {}) => { - const queryKey = QueryKey.apiBnt(); - return useQuery( - queryKey, - BancorApi.v3.getBnt, - queryOptionsStaleTimeHigh(enabled) - ); -}; diff --git a/src/queries/api/useApiPools.ts b/src/queries/api/useApiPools.ts index b9dab5afa..845c7fa74 100644 --- a/src/queries/api/useApiPools.ts +++ b/src/queries/api/useApiPools.ts @@ -1,7 +1,7 @@ import { useQuery } from '@tanstack/react-query'; import { BancorApi } from 'services/api/bancorApi/bancorApi'; import { QueryKey } from 'queries/queryKeyFactory'; -import { queryOptionsStaleTimeHigh } from 'queries/queryOptions'; +import { queryOptionsStaleTime15s } from 'queries/queryOptions'; interface Props { enabled?: boolean; @@ -24,7 +24,7 @@ export const useApiPools = ({ enabled = true }: Props = {}) => { }; } }, - queryOptionsStaleTimeHigh(enabled) + queryOptionsStaleTime15s(enabled) ); const getByID = (id: string) => query.data?.get(id); diff --git a/src/queries/api/useApiStatistics.ts b/src/queries/api/useApiStatistics.ts index 86265ed8b..194dbdb35 100644 --- a/src/queries/api/useApiStatistics.ts +++ b/src/queries/api/useApiStatistics.ts @@ -8,7 +8,7 @@ import { useApiV2Welcome } from 'queries/api/useApiV2Welcome'; import { WelcomeData } from 'services/api/bancorApi/bancorApi.types'; import { genericFailedNotification } from 'services/notifications/notifications'; import { useDispatch } from 'react-redux'; -import { queryOptionsStaleTimeHigh } from 'queries/queryOptions'; +import { queryOptionsStaleTime15s } from 'queries/queryOptions'; import { QueryKey } from 'queries/queryKeyFactory'; export interface Statistic { @@ -105,7 +105,7 @@ export const useApiStatistics = () => { QueryKey.apiStatistics(), () => fetchStatistics(apiDataV2!), { - ...queryOptionsStaleTimeHigh(!!apiDataV2), + ...queryOptionsStaleTime15s(!!apiDataV2), useErrorBoundary: false, onError: (err: any) => { genericFailedNotification( diff --git a/src/queries/api/useApiTokens.ts b/src/queries/api/useApiTokens.ts index 501029499..e6e6e9a98 100644 --- a/src/queries/api/useApiTokens.ts +++ b/src/queries/api/useApiTokens.ts @@ -1,7 +1,7 @@ import { useQuery } from '@tanstack/react-query'; import { BancorApi } from 'services/api/bancorApi/bancorApi'; import { QueryKey } from 'queries/queryKeyFactory'; -import { queryOptionsStaleTimeHigh } from 'queries/queryOptions'; +import { queryOptionsStaleTime15s } from 'queries/queryOptions'; interface Props { enabled?: boolean; @@ -22,7 +22,7 @@ export const useApiTokens = ({ enabled = true }: Props = {}) => { ); } }, - queryOptionsStaleTimeHigh(enabled) + queryOptionsStaleTime15s(enabled) ); const getApiPoolByID = (id: string) => query.data?.get(id); diff --git a/src/queries/api/useApiTradingLiquidity.ts b/src/queries/api/useApiTradingLiquidity.ts new file mode 100644 index 000000000..e0814dc34 --- /dev/null +++ b/src/queries/api/useApiTradingLiquidity.ts @@ -0,0 +1,34 @@ +import { useChainPoolIds } from 'queries/chain/useChainPoolIds'; + +import { useApiPools } from 'queries/api/useApiPools'; + +interface Props { + enabled?: boolean; +} + +export const useApiTradingLiquidity = ({ enabled = true }: Props = {}) => { + const poolIds = useChainPoolIds(); + const apiPools = useApiPools({ enabled }); + + const data = new Map( + poolIds?.data?.map((id) => [ + id, + apiPools.getByID(id) + ? { + BNT: apiPools.getByID(id)!.tradingLiquidityBNT, + TKN: apiPools.getByID(id)!.tradingLiquidityTKN, + } + : undefined, + ]) + ); + + const getByID = (id: string) => data.get(id); + + return { + data, + getByID, + isLoading: poolIds.isLoading || apiPools.isLoading, + isError: poolIds.isError || apiPools.isError, + isFetching: poolIds.isFetching || apiPools.isFetching, + }; +}; diff --git a/src/queries/api/useApiV2Welcome.ts b/src/queries/api/useApiV2Welcome.ts index 07cf4f3bd..b8172c413 100644 --- a/src/queries/api/useApiV2Welcome.ts +++ b/src/queries/api/useApiV2Welcome.ts @@ -1,13 +1,13 @@ import { useQuery } from '@tanstack/react-query'; import { BancorApi } from 'services/api/bancorApi/bancorApi'; import { WelcomeData } from 'services/api/bancorApi/bancorApi.types'; -import { queryOptionsStaleTimeHigh } from 'queries/queryOptions'; +import { queryOptionsStaleTime15s } from 'queries/queryOptions'; import { QueryKey } from 'queries/queryKeyFactory'; export const useApiV2Welcome = () => { return useQuery( QueryKey.v2ApiWelcome(), BancorApi.v2.getWelcome, - queryOptionsStaleTimeHigh() + queryOptionsStaleTime15s() ); }; diff --git a/src/queries/chain/useChainBalances.ts b/src/queries/chain/useChainBalances.ts index 15b875835..d9e7e4044 100644 --- a/src/queries/chain/useChainBalances.ts +++ b/src/queries/chain/useChainBalances.ts @@ -37,7 +37,7 @@ export const useChainBalances = ({ enabled = true }: Props = {}) => { !!poolTokenIds.data && !!decimals.data && enabled, - useErrorBoundary: false, + useErrorBoundary: true, } ); diff --git a/src/queries/chain/useChainDecimals.ts b/src/queries/chain/useChainDecimals.ts index 43f8370a0..59b195f59 100644 --- a/src/queries/chain/useChainDecimals.ts +++ b/src/queries/chain/useChainDecimals.ts @@ -24,7 +24,10 @@ export const useChainDecimals = ({ enabled = true }: Props = {}) => { decimals.set(ethToken, 18); return decimals; }, - queryOptionsNoInterval(!!poolIds && enabled) + { + ...queryOptionsNoInterval(!!poolIds && enabled), + useErrorBoundary: true, + } ); const getByID = (id: string) => query.data?.get(id); diff --git a/src/queries/chain/useChainDepositingEnabled.ts b/src/queries/chain/useChainDepositingEnabled.ts index 97624f73e..ebcbf14b7 100644 --- a/src/queries/chain/useChainDepositingEnabled.ts +++ b/src/queries/chain/useChainDepositingEnabled.ts @@ -18,7 +18,10 @@ export const useChainDepositingEnabled = ({ enabled = true }: Props = {}) => { QueryKey.chainDepositingEnabled(poolIds?.length), () => fetchMulticallHelper(poolIds!, buildMulticallDepositingEnabled), - queryOptionsNoInterval(!!poolIds && enabled) + { + ...queryOptionsNoInterval(!!poolIds && enabled), + useErrorBoundary: true, + } ); const getByID = (id: string) => query.data?.get(id); diff --git a/src/queries/chain/useChainLatestProgram.ts b/src/queries/chain/useChainLatestProgram.ts index 910ac3345..191e577cf 100644 --- a/src/queries/chain/useChainLatestProgram.ts +++ b/src/queries/chain/useChainLatestProgram.ts @@ -33,7 +33,10 @@ export const useChainLatestProgram = ({ enabled = true }: Props = {}) => { }) ); }, - queryOptionsNoInterval(!!poolIds && !!programsMap && enabled) + { + ...queryOptionsNoInterval(!!poolIds && !!programsMap && enabled), + useErrorBoundary: true, + } ); const getByID = (id: string) => query.data?.get(id); diff --git a/src/queries/chain/useChainPoolIds.ts b/src/queries/chain/useChainPoolIds.ts index c9a89934a..96879eaa1 100644 --- a/src/queries/chain/useChainPoolIds.ts +++ b/src/queries/chain/useChainPoolIds.ts @@ -1,7 +1,7 @@ import { useQuery } from '@tanstack/react-query'; import { ContractsApi } from 'services/web3/v3/contractsApi'; import { QueryKey } from 'queries/queryKeyFactory'; -import { queryOptionsStaleTimeLow } from 'queries/queryOptions'; +import { queryOptionsStaleTime2m } from 'queries/queryOptions'; import { bntToken } from 'services/web3/config'; export const useChainPoolIds = () => { @@ -11,6 +11,9 @@ export const useChainPoolIds = () => { const pools = await ContractsApi.BancorNetwork.read.liquidityPools(); return [bntToken, ...pools]; }, - queryOptionsStaleTimeLow() + { + ...queryOptionsStaleTime2m(), + useErrorBoundary: true, + } ); }; diff --git a/src/queries/chain/useChainPoolTokenIds.ts b/src/queries/chain/useChainPoolTokenIds.ts index d72a30846..4bfc08089 100644 --- a/src/queries/chain/useChainPoolTokenIds.ts +++ b/src/queries/chain/useChainPoolTokenIds.ts @@ -16,7 +16,10 @@ export const useChainPoolTokenIds = ({ enabled = true }: Props = {}) => { const query = useQuery( QueryKey.chainPoolTokenIds(poolIds?.length), () => fetchMulticallHelper(poolIds!, buildMulticallPoolToken), - queryOptionsNoInterval(!!poolIds && enabled) + { + ...queryOptionsNoInterval(!!poolIds && enabled), + useErrorBoundary: true, + } ); const getByID = (id: string) => query.data?.get(id); diff --git a/src/queries/chain/useChainPrograms.ts b/src/queries/chain/useChainPrograms.ts index 09c15b93e..4a174f485 100644 --- a/src/queries/chain/useChainPrograms.ts +++ b/src/queries/chain/useChainPrograms.ts @@ -18,7 +18,10 @@ export const useChainPrograms = ({ enabled = true }: Props = {}) => { poolIds?.map((id) => [id, programs.filter((p) => p.pool === id)]) ); }, - queryOptionsNoInterval(!!poolIds && enabled) + { + ...queryOptionsNoInterval(!!poolIds && enabled), + useErrorBoundary: true, + } ); const getByID = (id: string) => query.data?.get(id); diff --git a/src/queries/chain/useChainSymbol.ts b/src/queries/chain/useChainSymbol.ts index fe9761619..6ff75e3ba 100644 --- a/src/queries/chain/useChainSymbol.ts +++ b/src/queries/chain/useChainSymbol.ts @@ -25,7 +25,10 @@ export const useChainSymbol = ({ enabled = true }: Props = {}) => { symbols.set(ethToken, 'ETH'); return symbols; }, - queryOptionsNoInterval(!!poolIds && enabled) + { + ...queryOptionsNoInterval(!!poolIds && enabled), + useErrorBoundary: true, + } ); const getByID = (id: string) => query.data?.get(id); diff --git a/src/queries/chain/useChainTokenName.ts b/src/queries/chain/useChainTokenName.ts deleted file mode 100644 index de36a78c9..000000000 --- a/src/queries/chain/useChainTokenName.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { useQuery } from '@tanstack/react-query'; -import { QueryKey } from 'queries/queryKeyFactory'; -import { useChainPoolIds } from 'queries/chain/useChainPoolIds'; -import { queryOptionsNoInterval } from 'queries/queryOptions'; -import { - buildMulticallName, - fetchMulticallHelper, -} from 'services/web3/multicall/multicallFunctions'; - -export const useChainTokenName = () => { - const { data: poolIds } = useChainPoolIds(); - return useQuery( - QueryKey.chainName(poolIds?.length), - () => fetchMulticallHelper(poolIds!, buildMulticallName, true), - queryOptionsNoInterval(!!poolIds) - ); -}; diff --git a/src/queries/chain/useChainTradingEnabled.ts b/src/queries/chain/useChainTradingEnabled.ts index ae1acc287..8bb8fa113 100644 --- a/src/queries/chain/useChainTradingEnabled.ts +++ b/src/queries/chain/useChainTradingEnabled.ts @@ -1,7 +1,7 @@ import { useQuery } from '@tanstack/react-query'; import { QueryKey } from 'queries/queryKeyFactory'; import { useChainPoolIds } from 'queries/chain/useChainPoolIds'; -import { queryOptionsStaleTimeLow } from 'queries/queryOptions'; +import { queryOptionsStaleTime2m } from 'queries/queryOptions'; import { buildMulticallTradingEnabled, fetchMulticallHelper, @@ -16,7 +16,10 @@ export const useChainTradingEnabled = ({ enabled = true }: Props = {}) => { const query = useQuery( QueryKey.chainTradingEnabled(poolIds?.length), () => fetchMulticallHelper(poolIds!, buildMulticallTradingEnabled), - queryOptionsStaleTimeLow(!!poolIds && enabled) + { + ...queryOptionsStaleTime2m(!!poolIds && enabled), + useErrorBoundary: true, + } ); const getByID = (id: string) => query.data?.get(id); diff --git a/src/queries/chain/useChainTradingFee.ts b/src/queries/chain/useChainTradingFee.ts index 66702e460..abca3f42f 100644 --- a/src/queries/chain/useChainTradingFee.ts +++ b/src/queries/chain/useChainTradingFee.ts @@ -1,7 +1,7 @@ import { useQuery } from '@tanstack/react-query'; import { QueryKey } from 'queries/queryKeyFactory'; import { useChainPoolIds } from 'queries/chain/useChainPoolIds'; -import { queryOptionsStaleTimeLow } from 'queries/queryOptions'; +import { queryOptionsStaleTime2m } from 'queries/queryOptions'; import { buildMulticallTradingFee, fetchMulticallHelper, @@ -13,7 +13,8 @@ export const useChainTradingFee = () => { QueryKey.chainTradingFee(poolIds?.length), () => fetchMulticallHelper(poolIds!, buildMulticallTradingFee), { - ...queryOptionsStaleTimeLow(!!poolIds), + ...queryOptionsStaleTime2m(!!poolIds), + useErrorBoundary: true, } ); }; diff --git a/src/queries/chain/useChainTradingLiquidity.ts b/src/queries/chain/useChainTradingLiquidity.ts deleted file mode 100644 index d40bf1af0..000000000 --- a/src/queries/chain/useChainTradingLiquidity.ts +++ /dev/null @@ -1,73 +0,0 @@ -import { useQuery } from '@tanstack/react-query'; -import { QueryKey } from 'queries/queryKeyFactory'; -import { useChainPoolIds } from 'queries/chain/useChainPoolIds'; -import { queryOptionsStaleTimeLow } from 'queries/queryOptions'; -import { - buildMulticallTradingLiquidity, - fetchMulticallHelper, -} from 'services/web3/multicall/multicallFunctions'; -import { TradingLiquidityStructOutput } from 'services/web3/abis/types/BancorNetworkInfo'; -import { useChainDecimals } from 'queries/chain/useChainDecimals'; -import { utils } from 'ethers'; -import { bntToken } from 'services/web3/config'; -import { useApiBnt } from 'queries/api/useApiBnt'; - -interface Props { - enabled?: boolean; -} - -export const useChainTradingLiquidity = ({ enabled = true }: Props = {}) => { - const { data: poolIds } = useChainPoolIds(); - const { data: decimals } = useChainDecimals({ enabled }); - const { data: bnt } = useApiBnt({ enabled }); - - const query = useQuery( - QueryKey.chainTradingLiquidity(poolIds?.length), - () => - fetchMulticallHelper( - poolIds!.filter((id) => id !== bntToken), - buildMulticallTradingLiquidity - ), - queryOptionsStaleTimeLow(!!poolIds && enabled) - ); - - const _getBNT = () => { - if (!bnt) { - return undefined; - } - - return { - BNT: { - ...bnt.tradingLiquidity, - tkn: bnt.tradingLiquidity.bnt, - }, - TKN: { - tkn: '0', - }, - }; - }; - - const getByID = (id: string) => { - if (id === bntToken) { - return _getBNT(); - } - const dec = decimals?.get(id); - const liq = query.data?.get(id); - if (!liq || !dec) { - // TODO error handling - return undefined; - } - - return { - BNT: { - bnt: utils.formatUnits(liq.bntTradingLiquidity, dec), - tkn: utils.formatUnits(liq.bntTradingLiquidity, 18), - }, - TKN: { - tkn: utils.formatUnits(liq.baseTokenTradingLiquidity, dec), - }, - }; - }; - - return { ...query, getByID }; -}; diff --git a/src/queries/queryOptions.ts b/src/queries/queryOptions.ts index 0b987f321..9447a3c9f 100644 --- a/src/queries/queryOptions.ts +++ b/src/queries/queryOptions.ts @@ -1,8 +1,8 @@ export const queryOptionsDefaults = (enabled?: boolean) => ({ enabled, - refetchInterval: 60000, - staleTime: 30000, - useErrorBoundary: true, + refetchInterval: 30 * 1000, + staleTime: 15 * 1000, + useErrorBoundary: false, }); export const queryOptionsNoInterval = (enabled?: boolean) => ({ @@ -11,13 +11,13 @@ export const queryOptionsNoInterval = (enabled?: boolean) => ({ staleTime: 6 * 60 * 60 * 1000, }); -export const queryOptionsStaleTimeLow = (enabled?: boolean) => ({ +export const queryOptionsStaleTime2m = (enabled?: boolean) => ({ enabled, - refetchInterval: 5 * 60 * 1000, - staleTime: 5 * 60 * 1000, + refetchInterval: 2 * 60 * 1000, + staleTime: 2 * 60 * 1000, }); -export const queryOptionsStaleTimeHigh = (enabled?: boolean) => ({ +export const queryOptionsStaleTime15s = (enabled?: boolean) => ({ enabled, refetchInterval: 15 * 1000, staleTime: 15 * 1000, diff --git a/src/queries/types.ts b/src/queries/types.ts index ca913603c..13fbd9b95 100644 --- a/src/queries/types.ts +++ b/src/queries/types.ts @@ -22,9 +22,9 @@ export interface PoolV3Chain { name: string; symbol: string; decimals: number; - tradingLiquidity: { - BNT: PriceDictionaryV3; - TKN: PriceDictionaryV3; + tradingLiquidity?: { + BNT: PriceDictionary; + TKN: PriceDictionary; }; stakedBalance: PriceDictionaryV3; tradingFeePPM: number; diff --git a/src/queries/usePoolPick.ts b/src/queries/usePoolPick.ts index ca71c7ab4..7b20bed23 100644 --- a/src/queries/usePoolPick.ts +++ b/src/queries/usePoolPick.ts @@ -4,7 +4,7 @@ import { useChainPoolTokenIds } from 'queries/chain/useChainPoolTokenIds'; import { useChainPrograms } from 'queries/chain/useChainPrograms'; import { useChainTradingEnabled } from 'queries/chain/useChainTradingEnabled'; import { useApiApr } from 'queries/api/useApiApr'; -import { useChainTradingLiquidity } from 'queries/chain/useChainTradingLiquidity'; +import { useApiTradingLiquidity } from 'queries/api/useApiTradingLiquidity'; import { useApiFees } from 'queries/api/useApiFees'; import { useApiVolume } from 'queries/api/useApiVolume'; import { useApiStakedBalance } from 'queries/api/useApiStakedBalance'; @@ -62,7 +62,7 @@ const useFetchers = (select: PoolKey[]) => { enabled: set.has('depositingEnabled'), }); - const tradingLiquidity = useChainTradingLiquidity({ + const tradingLiquidity = useApiTradingLiquidity({ enabled: set.has('tradingLiquidity'), }); From 68f692d2efc1f6387385d78cf4952c7fa34fffcd Mon Sep 17 00:00:00 2001 From: Doron Zavelevsky Date: Mon, 1 Aug 2022 15:09:29 +0300 Subject: [PATCH 34/36] adapted deposit modal --- src/elements/earn/pools/TopPools.tsx | 2 +- .../earn/pools/poolsTable/PoolsTable.tsx | 4 +- .../pools/poolsTable/v3/DepositV3Modal.tsx | 88 +++++++++---------- .../earn/portfolio/v3/V3AvailableToStake.tsx | 2 +- .../v3/earningsTable/V3EarningTable.tsx | 2 +- 5 files changed, 47 insertions(+), 51 deletions(-) diff --git a/src/elements/earn/pools/TopPools.tsx b/src/elements/earn/pools/TopPools.tsx index e0ed1df41..c2862b82d 100644 --- a/src/elements/earn/pools/TopPools.tsx +++ b/src/elements/earn/pools/TopPools.tsx @@ -33,7 +33,7 @@ export const TopPools = () => { ? pools.map((pool, index) => { return ( (
-
+
diff --git a/src/elements/earn/pools/poolsTable/v3/DepositV3Modal.tsx b/src/elements/earn/pools/poolsTable/v3/DepositV3Modal.tsx index e72cd4c2e..0664e3a69 100644 --- a/src/elements/earn/pools/poolsTable/v3/DepositV3Modal.tsx +++ b/src/elements/earn/pools/poolsTable/v3/DepositV3Modal.tsx @@ -1,5 +1,4 @@ import { Button, ButtonSize } from 'components/button/Button'; -import { PoolV3 } from 'services/observables/pools'; import { ReactNode, useCallback, useMemo, useState } from 'react'; import { ContractsApi } from 'services/web3/v3/contractsApi'; import { useDispatch } from 'react-redux'; @@ -43,15 +42,24 @@ import { getOnOff, } from 'services/api/googleTagManager'; import { DepositDisabledModal } from './DepositDisabledModal'; +import { usePoolPick } from 'queries'; interface Props { - pool: PoolV3; + poolId: string; renderButton: (onClick: (pool_click_location?: string) => void) => ReactNode; } const REWARDS_EXTRA_GAS = 130_000; -export const DepositV3Modal = ({ pool, renderButton }: Props) => { +export const DepositV3Modal = ({ poolId, renderButton }: Props) => { + const { getOne } = usePoolPick([ + 'balance', + 'symbol', + 'latestProgram', + 'decimals', + 'apr', + ]); + const { data: pool } = getOne(poolId); const enableDeposit = useAppSelector((state) => state.user.enableDeposit); const account = useAppSelector((state) => state.user.account); const [isOpen, setIsOpen] = useState(false); @@ -75,15 +83,15 @@ export const DepositV3Modal = ({ pool, renderButton }: Props) => { }; const isInputError = useMemo( - () => !!account && new BigNumber(pool.reserveToken.balance || 0).lt(amount), - [account, amount, pool.reserveToken.balance] + () => !!account && new BigNumber(pool?.balance?.tkn || 0).lt(amount), + [account, amount, pool?.balance?.tkn] ); const dispatch = useDispatch(); const { goToPage } = useNavigation(); const deposit = async (approvalHash?: string) => { - if (!pool.reserveToken.balance || !account) { + if (!pool || !pool.balance?.tkn || !account) { return; } @@ -96,8 +104,8 @@ export const DepositV3Modal = ({ pool, renderButton }: Props) => { ); sendDepositEvent(DepositEvent.DepositWalletRequest); - const amountWei = expandToken(amount, pool.reserveToken.decimals); - const isETH = pool.reserveToken.address === ethToken; + const amountWei = expandToken(amount, pool.decimals); + const isETH = poolId === ethToken; try { setTxBusy(true); @@ -108,23 +116,16 @@ export const DepositV3Modal = ({ pool, renderButton }: Props) => { amountWei, { value: isETH ? amountWei : undefined } ) - : await ContractsApi.BancorNetwork.write.deposit( - pool.reserveToken.address, - amountWei, - { value: isETH ? amountWei : undefined } - ); + : await ContractsApi.BancorNetwork.write.deposit(poolId, amountWei, { + value: isETH ? amountWei : undefined, + }); sendDepositEvent( DepositEvent.DepositWalletConfirm, undefined, undefined, tx.hash ); - confirmDepositNotification( - dispatch, - tx.hash, - amount, - pool.reserveToken.symbol - ); + confirmDepositNotification(dispatch, tx.hash, amount, pool.symbol); setTxBusy(false); onClose(); goToPage.portfolio(); @@ -150,9 +151,10 @@ export const DepositV3Modal = ({ pool, renderButton }: Props) => { }; const [onStart, ApproveModal] = useApproveModal( - [{ amount: amount || '0', token: pool.reserveToken }], + //@ts-ignore + [{ amount: amount || '0', token: {} }], (approvalHash?: string) => deposit(approvalHash), - accessFullEarnings && pool.latestProgram?.isActive + accessFullEarnings && pool?.latestProgram?.isActive ? ContractsApi.StandardRewards.contractAddress : ContractsApi.BancorNetwork.contractAddress, () => sendDepositEvent(DepositEvent.DepositUnlimitedPopupRequest), @@ -170,13 +172,10 @@ export const DepositV3Modal = ({ pool, renderButton }: Props) => { ); const handleClick = useCallback(() => { - if (canDeposit) { + if (canDeposit && pool) { const portion = - pool.reserveToken.balance && - new BigNumber(amount) - .div(pool.reserveToken.balance) - .times(100) - .toFixed(0); + pool?.balance && + new BigNumber(amount).div(pool?.balance.tkn).times(100).toFixed(0); const deposit_portion = portion && (portion === '25' || @@ -186,11 +185,11 @@ export const DepositV3Modal = ({ pool, renderButton }: Props) => { ? portion : '(no value)'; setCurrentDeposit({ - deposit_pool: pool.name, + deposit_pool: pool.symbol, deposit_blockchain: getBlockchain(), deposit_blockchain_network: getBlockchainNetwork(), deposit_input_type: getFiat(isFiat), - deposit_token: pool.name, + deposit_token: pool.symbol, deposit_token_amount: amount, deposit_token_amount_usd: inputFiat, deposit_portion, @@ -211,8 +210,7 @@ export const DepositV3Modal = ({ pool, renderButton }: Props) => { amount, inputFiat, isFiat, - pool.name, - pool.reserveToken.balance, + pool, ]); const shouldPollForGasPrice = useMemo(() => { @@ -239,15 +237,17 @@ export const DepositV3Modal = ({ pool, renderButton }: Props) => { if (!enableDeposit) return ; + if (!pool) return null; + return ( <> {renderButton((pool_click_location) => { setCurrentDeposit({ - deposit_pool: pool.name, + deposit_pool: pool.symbol, deposit_blockchain: getBlockchain(), deposit_blockchain_network: getBlockchainNetwork(), deposit_input_type: getFiat(isFiat), - deposit_token: pool.name, + deposit_token: pool.symbol, deposit_token_amount: undefined, deposit_token_amount_usd: undefined, deposit_portion: undefined, @@ -276,7 +276,7 @@ export const DepositV3Modal = ({ pool, renderButton }: Props) => { {
{accessFullEarnings - ? pool.apr7d.total.toFixed(2) - : pool.apr7d.tradingFees.toFixed(2)} + ? pool.apr?.apr7d.total.toFixed(2) + : pool.apr?.apr7d.tradingFees.toFixed(2)} % {
Compounding rewards{' '} - - {pool.reserveToken.symbol} - + {pool.symbol} - {pool.apr7d.tradingFees.toFixed(2)}% + {pool.apr?.apr7d.tradingFees.toFixed(2)}%
@@ -345,7 +343,7 @@ export const DepositV3Modal = ({ pool, renderButton }: Props) => { {accessFullEarnings - ? pool.apr7d.standardRewards.toFixed(2) + ? pool.apr?.apr7d.standardRewards.toFixed(2) : 0} % @@ -356,11 +354,9 @@ export const DepositV3Modal = ({ pool, renderButton }: Props) => {
Compounding rewards{' '} - - {pool.reserveToken.symbol} - + {pool.symbol} - {pool.apr7d.tradingFees.toFixed(2)}% + {pool.apr?.apr7d.tradingFees.toFixed(2)}%
)} @@ -375,7 +371,7 @@ export const DepositV3Modal = ({ pool, renderButton }: Props) => { : shouldConnect ? 'Connect your wallet' : canDeposit - ? `Deposit ${pool.name}` + ? `Deposit ${pool.symbol}` : 'Enter amount'} diff --git a/src/elements/earn/portfolio/v3/V3AvailableToStake.tsx b/src/elements/earn/portfolio/v3/V3AvailableToStake.tsx index 045ff7ed6..a213a9e23 100644 --- a/src/elements/earn/portfolio/v3/V3AvailableToStake.tsx +++ b/src/elements/earn/portfolio/v3/V3AvailableToStake.tsx @@ -13,7 +13,7 @@ import { DepositV3Modal } from 'elements/earn/pools/poolsTable/v3/DepositV3Modal const AvailableItem = ({ token, pool }: { token: Token; pool: PoolV3 }) => { return ( (