diff --git a/package.json b/package.json index bc922749..fd1cd34c 100644 --- a/package.json +++ b/package.json @@ -26,7 +26,6 @@ "deploy": "gh-pages -d example/build" }, "dependencies": { - "@apollo/client": "^3.6.2", "@fortawesome/free-regular-svg-icons": "^6.1.0", "@fortawesome/free-solid-svg-icons": "^6.1.0", "@polkadot/extension-dapp": "^0.40.4", diff --git a/src/appState/accountState.ts b/src/appState/accountState.ts deleted file mode 100644 index 67d26f02..00000000 --- a/src/appState/accountState.ts +++ /dev/null @@ -1,356 +0,0 @@ -import { - catchError, - combineLatest, - distinctUntilChanged, - map, - merge, - mergeScan, - Observable, - of, - ReplaySubject, - scan, - shareReplay, - startWith, - Subject, - switchMap, - take, - withLatestFrom, -} from 'rxjs'; -import { Provider } from '@reef-defi/evm-provider'; -import { BigNumber } from 'ethers'; -import { filter } from 'rxjs/operators'; -import { AccountJson } from '@reef-defi/extension-base/background/types'; -import type { InjectedAccountWithMeta } from '@reef-defi/extension-inject/types'; -import type { Signer as InjectedSigningKey } from '@polkadot/api/types'; -import { graphql } from '@reef-chain/util-lib'; -import { UpdateDataCtx } from './updateStateModel'; -import { replaceUpdatedSigners, updateSignersEvmBindings } from './accountStateUtil'; -import { currentProvider$ } from './providerState'; -import { ReefSigner } from '../state'; -import { apolloExplorerClientInstance$, zenToRx } from '../graphql/apollo'; -import { accountJsonToMeta, metaAccountToSigner } from '../rpc/accounts'; - -export const accountsSubj = new ReplaySubject(1); -export const accountsJsonSubj = new ReplaySubject(1); -export const accountsJsonSigningKeySubj = new ReplaySubject(1); -export const reloadSignersSubj = new Subject>(); - -const signersFromJson$: Observable = combineLatest([accountsJsonSubj, currentProvider$, accountsJsonSigningKeySubj]).pipe( - switchMap(([jsonAccounts, provider, signingKey]: [(AccountJson[] | InjectedAccountWithMeta[] | null), Provider, InjectedSigningKey]) => { - let accounts = jsonAccounts || []; - if (accounts?.length && !accounts[0].meta) { - accounts = accounts.map((acc) => accountJsonToMeta(acc)); - } - return Promise.all( - accounts.map((account) => metaAccountToSigner(account, provider as Provider, signingKey as InjectedSigningKey)), - ).then((signers:ReefSigner[]) => signers.filter((s) => !!s)) as Promise; - }), - shareReplay(1), -); - -export const signersInjected$ = merge(accountsSubj, signersFromJson$).pipe( - map((signrs) => (signrs && signrs.length ? signrs : [])), - shareReplay(1), -); - -const signersLocallyUpdatedData$: Observable = reloadSignersSubj.pipe( - filter((reloadCtx: any) => !!reloadCtx.updateActions.length), - withLatestFrom(signersInjected$), - mergeScan( - ( - state: { - all: ReefSigner[]; - allUpdated: ReefSigner[]; - lastUpdated: ReefSigner[]; - }, - [updateCtx, signersInjected]: [any, ReefSigner[]], - ): any => { - const allSignersLatestUpdates = replaceUpdatedSigners( - signersInjected, - state.allUpdated, - ); - return of(updateCtx.updateActions || []) - .pipe( - switchMap((updateActions) => updateSignersEvmBindings( - updateActions, - allSignersLatestUpdates, - ) - .then((lastUpdated) => ({ - all: replaceUpdatedSigners( - allSignersLatestUpdates, - lastUpdated, - true, - ), - allUpdated: replaceUpdatedSigners( - state.allUpdated, - lastUpdated, - true, - ), - lastUpdated, - }))), - ); - }, - { - all: [], - allUpdated: [], - lastUpdated: [], - }, - ), - filter((val: any) => !!val.lastUpdated.length), - map((val: any): any => val.all), - startWith([]), - catchError((err) => { - console.log('signersLocallyUpdatedData$ ERROR=', err.message); - return of([]); - }), - shareReplay(1), -); - -const signersWithUpdatedBalances$ = combineLatest([ - currentProvider$, - signersInjected$, -]) - .pipe( - mergeScan( - ( - state: { unsub: any; balancesByAddressSubj: ReplaySubject }, - [provider, signers]: [Provider, ReefSigner[]], - ) => { - if (state.unsub) { - state.unsub(); - } - const distinctSignerAddresses = signers - .map((s) => s.address) - .reduce((distinctAddrList: string[], curr: string) => { - if (distinctAddrList.indexOf(curr) < 0) { - distinctAddrList.push(curr); - } - return distinctAddrList; - }, []); - // eslint-disable-next-line no-param-reassign - return provider.api.query.system.account - .multi(distinctSignerAddresses, (balances: any[]) => { - const balancesByAddr = balances.map(({ data }, index) => ({ - address: distinctSignerAddresses[index], - balance: data.free.toString(), - })); - state.balancesByAddressSubj.next({ - balances: balancesByAddr, - signers, - }); - }) - .then((unsub) => { - // eslint-disable-next-line no-param-reassign - state.unsub = unsub; - return state; - }); - }, - { - unsub: null, - balancesByAddressSubj: new ReplaySubject(1), - }, - ), - distinctUntilChanged( - (prev: any, curr: any): any => prev.balancesByAddressSubj !== curr.balancesByAddressSubj, - ), - switchMap( - (v: { - balancesByAddressSubj: Subject<{ balances: any; signers: ReefSigner[] }>; - }) => v.balancesByAddressSubj, - ), - map((balancesAndSigners: { balances: any; signers: ReefSigner[] }) => (!balancesAndSigners.signers - ? [] - : balancesAndSigners.signers.map((sig) => { - const bal = balancesAndSigners.balances.find( - (b: { address: string; balance: string }) => b.address === sig.address, - ); - if (bal && !BigNumber.from(bal.balance) - .eq(sig.balance)) { - return { - ...sig, - balance: BigNumber.from(bal.balance), - }; - } - return sig; - }))), - shareReplay(1), - catchError((err) => { - console.log('signersWithUpdatedBalances$ ERROR=', err.message); - return of([]); - }), - ); - -// const EVM_ADDRESS_UPDATE_GQL = graphql.EVM_ADDRESS_UPDATE_GQL; -/* -const EVM_ADDRESS_UPDATE_GQL = gql` - subscription query($accountIds: [String!]!) { - account( - where: { address: { _in: $accountIds } } - order_by: { timestamp: asc, address: asc } - ) { - address - evm_address - } - } -`; -*/ - -// eslint-disable-next-line camelcase -interface AccountEvmAddrData { - address: string; - // eslint-disable-next-line camelcase - evmAddress?: string; - isEvmClaimed?: boolean; -} - -const indexedAccountValues$ = combineLatest([ - apolloExplorerClientInstance$, - signersInjected$, -]) - .pipe( - switchMap(([apollo, signers]) => (!signers - ? [] - : zenToRx( - apollo.subscribe({ - query: graphql.EVM_ADDRESS_UPDATE_GQL, - variables: { accountIds: signers.map((s: any) => s.address) }, - fetchPolicy: 'network-only', - }), - ))), - map((result: any): AccountEvmAddrData[] => result.data.accounts.map((a) => ({ address: a.id, evmAddress: a.evmAddress, isEvmClaimed: !!a.evmAddress } as AccountEvmAddrData))), - filter((v) => !!v), - startWith([]), - ); - -const signersWithUpdatedData$ = combineLatest([ - signersWithUpdatedBalances$, - signersLocallyUpdatedData$, - indexedAccountValues$, -]) - .pipe( - scan( - ( - state: { - lastlocallyUpdated: ReefSigner[]; - lastIndexed: AccountEvmAddrData[]; - lastSigners: ReefSigner[]; - signers: ReefSigner[]; - }, - [signers, locallyUpdated, indexed], - ) => { - let updateBindValues: AccountEvmAddrData[] = []; - if (state.lastlocallyUpdated !== locallyUpdated) { - updateBindValues = locallyUpdated.map((updSigner) => ({ - address: updSigner.address, - isEvmClaimed: updSigner.isEvmClaimed, - evmAddress: updSigner.evmAddress, - })); - } else if (state.lastIndexed !== indexed) { - updateBindValues = indexed.map((updSigner: AccountEvmAddrData) => ({ - address: updSigner.address, - isEvmClaimed: updSigner.isEvmClaimed, - evmAddress: updSigner.evmAddress, - })); - } else { - updateBindValues = state.lastSigners.map((updSigner) => ({ - address: updSigner.address, - isEvmClaimed: updSigner.isEvmClaimed, - evmAddress: updSigner.evmAddress, - })); - } - updateBindValues.forEach((updVal: AccountEvmAddrData) => { - const signer = signers.find((sig) => sig.address === updVal.address); - if (signer) { - signer.isEvmClaimed = !!updVal.isEvmClaimed; - signer.evmAddress = updVal.evmAddress ? updVal.evmAddress : signer.evmAddress; - } - }); - return { - signers, - lastlocallyUpdated: locallyUpdated, - lastIndexed: indexed, - lastSigners: signers, - }; - }, - { - signers: [], - lastlocallyUpdated: [], - lastIndexed: [], - lastSigners: [], - }, - ), - map(({ signers }) => signers), - shareReplay(1), - catchError((err) => { - console.log('signersWithUpdatedData$ ERROR=', err.message); - return of(null); - }), - ); - -export const signers$: Observable = signersWithUpdatedData$; -const currentAddressSubj: Subject = new Subject(); -export const setCurrentAddress = (address: string|undefined) => currentAddressSubj.next(address); -export const currentAddress$: Observable = currentAddressSubj.asObservable() - .pipe( - startWith(''), - distinctUntilChanged(), - shareReplay(1), - ); - -// setting default signer (when signers exist) if no selected address exists -combineLatest([signers$, currentAddress$]) - .pipe(take(1)) - .subscribe(([signers, address]: [ReefSigner[] | null, string]): any => { - let saved: string | undefined = address; - try { - if (!saved) { - saved = localStorage?.getItem('selected_address_reef') || undefined; - } - } catch (e) { - // getting error in Flutter: 'The operation is insecure' - // console.log('Flutter error=', e.message); - } - - if (!saved) { - const firstSigner = signers && signers[0] ? signers[0].address : undefined; - setCurrentAddress( - saved || firstSigner, - ); - } - }); - -export const selectedSigner$: Observable = combineLatest([ - currentAddress$, - signers$, -]) - .pipe( - map(([selectedAddress, signers]: [string | undefined, ReefSigner[]|null]) => { - if (!selectedAddress || !signers || !signers.length) { - return undefined; - } - - let foundSigner = signers.find( - (signer: ReefSigner) => signer?.address === selectedAddress, - ); - if (!foundSigner) { - foundSigner = signers ? signers[0] as ReefSigner : undefined; - } - try { - if (foundSigner) { - localStorage.setItem( - 'selected_address_reef', - foundSigner.address || '', - ); - } - } catch (e) { - // getting error in Flutter: 'The operation is insecure' - // console.log('Flutter error=',e.message); - } - return foundSigner ? { ...foundSigner } as ReefSigner : undefined; - }), - catchError((err) => { - console.log('selectedSigner$ ERROR=', err.message); - return of(null); - }), - shareReplay(1), - ); diff --git a/src/appState/accountStateUtil.ts b/src/appState/accountStateUtil.ts deleted file mode 100644 index 4709ace0..00000000 --- a/src/appState/accountStateUtil.ts +++ /dev/null @@ -1,78 +0,0 @@ -import { UpdateAction, UpdateDataType } from './updateStateModel'; -import { ReefSigner } from '../state'; - -const getUpdAddresses = ( - updateType: UpdateDataType, - updateActions: UpdateAction[], -): string[] | null => { - const typeUpdateActions = updateActions.filter( - (ua) => ua.type === updateType, - ); - if (typeUpdateActions.length === 0) { - return null; - } - if (typeUpdateActions.some((tua) => !tua.address)) { - return []; - } - - return typeUpdateActions.map((ua) => ua.address as string); -}; - -export const isUpdateAll = (addresses: string[] | null): boolean => addresses?.length === 0; - -export const getSignersToUpdate = ( - updateType: UpdateDataType, - updateActions: UpdateAction[], - signers: ReefSigner[], -): ReefSigner[] => { - const updAddresses = getUpdAddresses(updateType, updateActions); - return isUpdateAll(updAddresses) - ? signers - : signers.filter((sig) => updAddresses?.some((addr) => addr === sig.address)); -}; - -export const replaceUpdatedSigners = ( - existingSigners: ReefSigner[] = [], - updatedSigners?: ReefSigner[], - appendNew?: boolean, -): ReefSigner[] => { - if (!appendNew && !existingSigners.length) { - return existingSigners; - } - if (!updatedSigners || !updatedSigners.length) { - return existingSigners; - } - const signers = existingSigners.map( - (existingSig) => updatedSigners.find((updSig) => updSig.address === existingSig.address) - || existingSig, - ); - if (!appendNew) { - return signers; - } - updatedSigners.forEach((updS) => { - if (!signers.some((s) => s.address === updS.address)) { - signers.push(updS); - } - }); - return signers; -}; - -export const updateSignersEvmBindings = ( - updateActions: UpdateAction[], - signers?: ReefSigner[], -): Promise => { - if (!signers || !signers.length) { - return Promise.resolve([]); - } - const updSigners = getSignersToUpdate( - UpdateDataType.ACCOUNT_EVM_BINDING, - updateActions, - signers, - ); - return Promise.all( - updSigners.map((sig: ReefSigner) => sig.signer.isClaimed()), - ).then((claimed: boolean[]) => claimed.map((isEvmClaimed: boolean, i: number) => { - const sig = updSigners[i]; - return { ...sig, isEvmClaimed }; - })); -}; diff --git a/src/appState/appState.ts b/src/appState/appState.ts index 9a7af0d5..68d7ca35 100644 --- a/src/appState/appState.ts +++ b/src/appState/appState.ts @@ -1,6 +1,3 @@ -export * from './accountState'; export * from './providerState'; -export * from './tokenState'; export * from './util'; export * from './updateStateModel'; -export * from './nftTokenState'; diff --git a/src/appState/nftTokenState.ts b/src/appState/nftTokenState.ts deleted file mode 100644 index 7054a43b..00000000 --- a/src/appState/nftTokenState.ts +++ /dev/null @@ -1,169 +0,0 @@ -import { - combineLatest, map, Observable, switchMap, -} from 'rxjs'; -import { graphql } from '@reef-chain/util-lib'; -import { BigNumber } from 'ethers'; -import { NFT } from '../state'; -import { apolloExplorerClientInstance$, zenToRx } from '../graphql'; -import { currentProvider$ } from './providerState'; -import { selectedSignerAddressUpdate$ } from './tokenState'; -import { resolveNftImageLinks } from '../utils/nftUtil'; -import { _NFT_IPFS_RESOLVER_FN } from './util'; - -const { SIGNER_NFTS_GQL } = graphql; -/* new graphql -const SIGNER_NFTS_GQL = gql` - subscription query($accountId: String) { - tokenHolders( - orderBy: balance_DESC - where: {AND: {nftId_isNull: false, token: {id_isNull: false}, signer: {id_eq: $accountId}, balance_gt: "0"}, type_eq: Account}, - limit:100 - ) { - token { - id - type - } - balance - nftId - } - }`; -; */ - -/* -const SIGNER_NFTS_GQL = gql` - subscription query($accountId: String) { - token_holder( - order_by: { balance: desc } - where: { - _and: [{ nft_id: { _is_null: false } }, { signer: { _eq: $accountId } }] - type: { _eq: "Account" } - } - ) { - token_address - balance - nft_id - info - contract { - verified_contract { - type - contract_data - } - } - } - }`; -*/ - -export interface VerifiedNft { - token_address: string; - balance: string; - nft_id: string; - info: { symbol: string }; - contractType: 'ERC1155' | 'ERC721'; -} - -const parseTokenHolderArray = (resArr: VerifiedNft[]): NFT[] => resArr.map(({ - balance, - nft_id: nftId, - info: { symbol }, - token_address, - contractType, -}) => ({ - contractType, - balance: BigNumber.from(balance), - nftId, - symbol, - decimals: 0, - address: token_address, - iconUrl: '', -} as NFT)); - -/* async function getSqwidContractNfts(queryResult: any[] | undefined, signer: ReefSigner, provider: Provider) { - const mainnetGHash = '0x7834781d38e4798d548e34ec947d19deea29df148a7bf32484b7b24dacf8d4b7'; - const network = await provider.api.genesisHash.toHuman(); - const isMainnet = mainnetGHash === network; - - if (queryResult?.length || !isMainnet) { - return queryResult; - } - - const sqwid1155Address = '0x0601202b75C96A61CDb9A99D4e2285E43c6e60e4' - - const nftItemsABI = [{ - "inputs": [ - { - "internalType": "address", - "name": "owner", - "type": "address" - } - ], - "name": "getTokensByOwner", - "outputs": [ - { - "internalType": "uint256[]", - "name": "", - "type": "uint256[]" - } - ], - "stateMutability": "view", - "type": "function" - }]; - const sqwid1155Contract = new Contract(sqwid1155Address, nftItemsABI, signer.signer); - const allTokens: BigNumber[] = await sqwid1155Contract.getTokensByOwner(signer.evmAddress); - const signerIds = allTokens.reduce((signerTokens:({ amt: string, nftId: string })[],tknAmt:BigNumber, i:number)=>{ - let amt = tknAmt.toString(); - if(amt !== '0'){ - signerTokens.push({amt, nftId:i.toString()}) - } - - return signerTokens; - },[]); - return signerIds.map(nftIdAmt=>({ - token_address: sqwid1155Address, - balance: nftIdAmt.amt, - nft_id: nftIdAmt.nftId, - info: { symbol: '' }, - contract: { - verified_contract: { - type: 'ERC1155', - contract_data: {type:ContractType.ERC1155} - } - } - } as VerifiedNft)); -} */ - -export const selectedSignerNFTs$: Observable = combineLatest([ - apolloExplorerClientInstance$, - selectedSignerAddressUpdate$, - currentProvider$, -]) - .pipe( - switchMap(([apollo, signer]) => (!signer - ? [] - : zenToRx( - apollo.subscribe({ - query: SIGNER_NFTS_GQL, - variables: { - accountId: signer.address, - }, - fetchPolicy: 'network-only', - }), - ) - .pipe( - map(({ data }) => { - const verNfts = data && Array.isArray(data.tokenHolders) - ? data.tokenHolders.map((th: any) => ({ - balance: th.balance, - nft_id: th.nftId, - info: { symbol: '' }, - token_address: th.token?.id, - contractType: th.token?.type, - } as VerifiedNft)) - : null; - return verNfts; - }), - // indexer fallback, loading directly from sqwid contract - // switchMap((res: VerifiedNft[] | undefined) => getSqwidContractNfts(res, signer as ReefSigner, provider)), - map((res: VerifiedNft[] | undefined) => parseTokenHolderArray(res || [])), - switchMap((nfts: NFT[]) => (resolveNftImageLinks(nfts, signer.signer, _NFT_IPFS_RESOLVER_FN) as Observable)), - ))), - ); diff --git a/src/appState/providerState.ts b/src/appState/providerState.ts index aafda189..da5bb526 100644 --- a/src/appState/providerState.ts +++ b/src/appState/providerState.ts @@ -1,23 +1,8 @@ -import { ReplaySubject, shareReplay } from 'rxjs'; -import { Provider } from '@reef-defi/evm-provider'; -import { Network } from '../state'; +import { reefState } from '@reef-chain/util-lib'; -const providerSubj: ReplaySubject = new ReplaySubject(1); -const selectedNetworkSubj: ReplaySubject = new ReplaySubject(); export const ACTIVE_NETWORK_LS_KEY = 'reef-app-active-network'; -export const currentProvider$ = providerSubj.asObservable().pipe(shareReplay(1)); -export const setCurrentProvider = (provider: Provider): void => providerSubj.next(provider); +export const currentProvider$ = reefState.selectedProvider$; -export const currentNetwork$ = selectedNetworkSubj.asObservable(); -export const setCurrentNetwork = (network: Network): void => { - if (network != null) { - try { - localStorage.setItem(ACTIVE_NETWORK_LS_KEY, JSON.stringify(network)); - } catch (e) { - // when cookies disabled localStorage can throw - } - } - selectedNetworkSubj.next(network); -}; -currentNetwork$.subscribe((network) => console.log('SELECTED NETWORK=', network)); +export const currentNetwork$ = reefState.selectedNetwork$; +export const setCurrentNetwork = reefState.setSelectedNetwork; diff --git a/src/appState/tokenState.ts b/src/appState/tokenState.ts deleted file mode 100644 index 45923b52..00000000 --- a/src/appState/tokenState.ts +++ /dev/null @@ -1,303 +0,0 @@ -import { - catchError, - combineLatest, - distinctUntilChanged, - map, - mergeScan, - Observable, - of, - shareReplay, startWith, - switchMap, - timer, -} from 'rxjs'; -import { BigNumber, FixedNumber, utils } from 'ethers'; -import { filter } from 'rxjs/operators'; -import { graphql } from '@reef-chain/util-lib'; -import { ApolloClient } from '@apollo/client'; -import { _NFT_IPFS_RESOLVER_FN, combineTokensDistinct, toTokensWithPrice } from './util'; -import { selectedSigner$ } from './accountState'; -import { currentNetwork$, currentProvider$ } from './providerState'; -import { apolloExplorerClientInstance$, zenToRx } from '../graphql/apollo'; -import { getIconUrl, getTransferUrl } from '../utils'; -import { getReefCoinBalance } from '../rpc'; -import { retrieveReefCoingeckoPrice } from '../api'; -import { - ContractType, reefTokenWithAmount, Token, TokenTransfer, TokenWithAmount, -} from '../state/token'; -import { Network, NFT, ReefSigner } from '../state'; -import {resolveNftImageLinks, toIpfsProviderUrl} from '../utils/nftUtil'; -import { apolloDexClientInstance$ } from '../graphql'; -import { PoolReserves, POOLS_RESERVES_GQL, PoolsWithReservesQuery } from '../graphql/pools'; - -// TODO replace with our own from lib and remove -const toPlainString = (num: number): string => `${+num}`.replace( - /(-?)(\d*)\.?(\d*)e([+-]\d+)/, - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore - (a, b, c, d, e) => (e < 0 - ? `${b}0.${Array(1 - e - c.length).join('0')}${c}${d}` - : b + c + d + Array(e - d.length + 1).join('0')), -); - -const validatedTokens = { tokens: [] }; - -export const reefPrice$: Observable = timer(0, 60000).pipe( - switchMap(retrieveReefCoingeckoPrice), - shareReplay(1), -); - -export const validatedTokens$ = of(validatedTokens.tokens as Token[]); -export const { SIGNER_TOKENS_GQL } = graphql; - -const { CONTRACT_DATA_GQL } = graphql; - -// eslint-disable-next-line camelcase -const fetchTokensData = ( - // apollo: ApolloClient, - apollo: any, - missingCacheContractDataAddresses: string[], - state: { tokens: Token[]; contractData: Token[] }, -): Promise => apollo - .query({ - query: CONTRACT_DATA_GQL, - variables: { addresses: missingCacheContractDataAddresses }, - }) -// eslint-disable-next-line camelcase - .then((verContracts) => verContracts.data.verifiedContracts.map( - // eslint-disable-next-line camelcase - (vContract: { id: string; contractData: any }) => ({ - address: vContract.id, - iconUrl: toIpfsProviderUrl(vContract.contractData.iconUrl)||vContract.contractData.iconUrl, - decimals: vContract.contractData.decimals, - name: vContract.contractData.name, - symbol: vContract.contractData.symbol, - } as Token), - )) - .then((newTokens) => newTokens.concat(state.contractData)); - -// eslint-disable-next-line camelcase -// const tokenBalancesWithContractDataCache = (apollo: ApolloClient) => ( -const tokenBalancesWithContractDataCache = (apollo: any) => ( - state: { tokens: Token[]; contractData: Token[] }, - // eslint-disable-next-line camelcase - tokenBalances: { token_address: string; balance: number }[], -) => { - const missingCacheContractDataAddresses = tokenBalances - .filter( - (tb) => !state.contractData.some((cd) => cd.address === tb.token_address), - ) - .map((tb) => tb.token_address); - const contractDataPromise = missingCacheContractDataAddresses.length - ? fetchTokensData(apollo, missingCacheContractDataAddresses, state) - : Promise.resolve(state.contractData); - return contractDataPromise.then((cData: Token[]) => { - const tkns = tokenBalances - .map((tBalance) => { - const cDataTkn = cData.find( - (cd) => cd.address === tBalance.token_address, - ) as Token; - return { - ...cDataTkn, - balance: BigNumber.from(toPlainString(tBalance.balance)), - }; - }) - .filter((v) => !!v); - return { tokens: tkns, contractData: cData }; - }); -}; - -const sortReefTokenFirst = (tokens): Token[] => { - const { address } = reefTokenWithAmount(); - const reefTokenIndex = tokens.findIndex((t: Token) => t.address === address); - if (reefTokenIndex > 0) { - return [tokens[reefTokenIndex], ...tokens.slice(0, reefTokenIndex), ...tokens.slice(reefTokenIndex + 1, tokens.length)]; - } - return tokens; -}; - -export const selectedSignerTokenBalances$: Observable = combineLatest([ - apolloExplorerClientInstance$, - selectedSigner$, - currentProvider$, -]).pipe( - switchMap(([apollo, signer, provider]) => (!signer - ? [] - : zenToRx( - apollo.subscribe({ - query: SIGNER_TOKENS_GQL, - variables: { accountId: signer.address }, - fetchPolicy: 'network-only', - }), - ).pipe( - map((res: any) => (res.data && res.data.tokenHolders - ? res.data.tokenHolders.map((th) => ({ token_address: th.token.id, balance: th.balance })) - : undefined)), - // eslint-disable-next-line camelcase - switchMap( - async ( - // eslint-disable-next-line camelcase - tokenBalances: { token_address: string; balance: number }[], - ) => { - const reefTkn = reefTokenWithAmount(); - const reefTokenResult = tokenBalances.find( - (tb) => tb.token_address === reefTkn.address, - ); - const reefBalance = await getReefCoinBalance( - signer.address, - provider, - ); - if (!reefTokenResult) { - tokenBalances.push({ - token_address: reefTkn.address, - balance: parseInt(utils.formatUnits(reefBalance, 'wei'), 10), - }); - return Promise.resolve(tokenBalances); - } - - reefTokenResult.balance = FixedNumber.fromValue(reefBalance).toUnsafeFloat(); - return Promise.resolve(tokenBalances); - }, - ), - // eslint-disable-next-line camelcase - mergeScan(tokenBalancesWithContractDataCache(apollo), { - tokens: [], - contractData: [reefTokenWithAmount()], - }), - map((val: { tokens: Token[] }) => val.tokens.map((t) => ({ - ...t, - iconUrl: t.iconUrl || getIconUrl(t.address), - }))), - map(sortReefTokenFirst), - ))), - catchError(((err) => { - console.log('selectedSignerTokenBalances$ ERROR=', err.message); - return of(null); - })), -); - -export const selectedSignerAddressUpdate$ = selectedSigner$.pipe( - filter((v) => !!v), - distinctUntilChanged((s1, s2) => s1?.address === s2?.address), -); - -export const allAvailableSignerTokens$: Observable = combineLatest([ - selectedSignerTokenBalances$, - validatedTokens$, -]).pipe(map(combineTokensDistinct), shareReplay(1)); - -export const pools$: Observable = combineLatest([ - allAvailableSignerTokens$, - apolloDexClientInstance$, -]).pipe( - switchMap(([tkns, dexClient]) => loadPoolsReserves(tkns, dexClient)), - shareReplay(1), -); - -const loadPoolsReserves = async ( - tokens: Token[], - dexClient: ApolloClient, -): Promise => { - if (tokens.length < 2) return []; - - const tokenAddresses = tokens.map((t) => t.address); - const res = await dexClient.query( - { query: POOLS_RESERVES_GQL, variables: { tokens: tokenAddresses } }, - ); - return res.data.poolsReserves || []; -}; - -export const tokenPrices$: Observable = combineLatest([ - allAvailableSignerTokens$, - reefPrice$, - pools$, -]).pipe( - map(toTokensWithPrice), - shareReplay(1), -); - -const resolveTransferHistoryNfts = (tokens: (Token | NFT)[], signer: ReefSigner): Observable<(Token | NFT)[]> => { - const nftOrNull: (NFT|null)[] = tokens.map((tr) => ('contractType' in tr && (tr.contractType === ContractType.ERC1155 || tr.contractType === ContractType.ERC721) ? tr : null)); - if (!nftOrNull.filter((v) => !!v).length) { - return of(tokens); - } - return of(nftOrNull) - .pipe( - switchMap((nfts) => resolveNftImageLinks(nfts, signer.signer, _NFT_IPFS_RESOLVER_FN)), - map((nftOrNullResolved: (NFT | null)[]) => { - const resolvedNftTransfers: (Token | NFT)[] = []; - nftOrNullResolved.forEach((nftOrN, i) => { - resolvedNftTransfers.push(nftOrN || tokens[i]); - }); - return resolvedNftTransfers; - }), - ); -}; - -const toTransferToken = (transfer): Token|NFT => (transfer.token.type === ContractType.ERC20 ? { - address: transfer.id, - balance: BigNumber.from(toPlainString(transfer.amount)), - name: transfer.token.contractData.name, - symbol: transfer.token.contractData.symbol, - decimals: - transfer.token.contractData.decimals, - iconUrl: - transfer.token.contractData.iconUrl - || getIconUrl(transfer.token.id), -} as Token - : { - address: transfer.token.id, - balance: BigNumber.from(toPlainString(transfer.amount)), - name: transfer.token.contractData.name, - symbol: transfer.token.contractData.symbol, - decimals: 0, - iconUrl: '', - nftId: transfer.nftId, - contractType: transfer.token.type, - } as NFT); - -const toTokenTransfers = (resTransferData: any[], signer, network: Network): TokenTransfer[] => resTransferData.map((transferData): TokenTransfer => ({ - from: transferData.from.evmAddress || transferData.from.id, - to: transferData.to.evmAddress || transferData.to.id, - inbound: - transferData.to.evmAddress === signer.evmAddress - || transferData.to.id === signer.address, - timestamp: transferData.timestamp, - token: toTransferToken(transferData), - url: getTransferUrl(transferData.extrinsic, network), - extrinsic: { blockId: transferData.extrinsic.block_id, hash: transferData.extrinsic.hash, index: transferData.extrinsic.index }, -})); - -export const transferHistory$: Observable< - | null - | TokenTransfer[] -> = combineLatest([apolloExplorerClientInstance$, selectedSigner$, currentNetwork$]).pipe( - switchMap(([apollo, signer, network]) => (!signer - ? [] - : zenToRx( - apollo.subscribe({ - query: graphql.TRANSFER_HISTORY_GQL, - variables: { accountId: signer.address }, - fetchPolicy: 'network-only', - }), - ) - .pipe( - map((res: any) => { - const resHist = res.data && Array.isArray(res.data.transfers) ? res.data.transfers : []; - return resHist; - }), - map((resData: any) => toTokenTransfers(resData, signer, network)), - switchMap((transfers: TokenTransfer[]) => { - const tokens = transfers.map((tr: TokenTransfer) => tr.token); - return resolveTransferHistoryNfts(tokens, signer) - .pipe( - map((resolvedTokens: (Token | NFT)[]) => resolvedTokens.map((resToken: Token | NFT, i) => ({ - ...transfers[i], - token: resToken, - }))), - ); - }), - map((transfers:TokenTransfer[])=>transfers.sort((a, b) => Date.parse(b.timestamp as any)- Date.parse(a.timestamp as any))) - ))), - startWith(null), - shareReplay(1), -); diff --git a/src/appState/updateStateModel.ts b/src/appState/updateStateModel.ts index 51cbe075..5621fb7e 100644 --- a/src/appState/updateStateModel.ts +++ b/src/appState/updateStateModel.ts @@ -13,36 +13,4 @@ export interface UpdateDataCtx { data?: T; updateActions: UpdateAction[]; ctx?: any; -} -/* - -export const createUpdateActions = (updateTypes: UpdateDataType[], addresses?: string[]): UpdateAction[] => { - const updateActions: UpdateAction[] = []; - if (addresses) { - addresses.forEach((address) => { - updateTypes.forEach((updT) => updateActions.push({ type: updT, address } as UpdateAction)); - }); - } else { - updateTypes.forEach((updT) => updateActions.push({ type: updT } as UpdateAction)); - } - return updateActions; -}; - -export const getUnwrappedData$ = (dataCtx$: Observable>): Observable => dataCtx$.pipe( - map((updCtx) => updCtx.data as T), - shareReplay(1), -); - -export const getAddressUpdateActionTypes = (address?: string, updateActions?: UpdateAction[]): UpdateDataType[] => { - if (!address || !updateActions) { - return []; - } - return updateActions.filter((ua) => !ua.address || ua.address === address).map((ua) => ua.type) - .reduce((distinctTypes, curr) => { - if (distinctTypes.indexOf(curr) < 0) { - distinctTypes.push(curr); - } - return distinctTypes; - }, [] as UpdateDataType[]); -}; -*/ +} \ No newline at end of file diff --git a/src/appState/util.ts b/src/appState/util.ts index e8926635..db3a728a 100644 --- a/src/appState/util.ts +++ b/src/appState/util.ts @@ -1,38 +1,16 @@ import { ContractInterface } from 'ethers'; -import { Provider } from '@reef-defi/evm-provider'; -import { ApolloClient } from '@apollo/client'; -import { - defer, finalize, Observable, scan, switchMap, tap, -} from 'rxjs'; -import type { Signer as InjectedSigningKey } from '@polkadot/api/types'; -import { AccountJson } from '@reef-defi/extension-base/background/types'; -import type { InjectedAccountWithMeta as InjectedAccountWithMetaReef } from '@reef-defi/extension-inject/types'; -import type { - InjectedAccountWithMeta, -} from '@polkadot/extension-inject/types'; +import { Subject } from 'rxjs'; import { ContractType, Token, TokenWithAmount } from '../state/token'; -import { - accountsJsonSigningKeySubj, accountsJsonSubj, accountsSubj, reloadSignersSubj, -} from './accountState'; -import { UpdateAction } from './updateStateModel'; -import { - availableNetworks, Network, ReefSigner, -} from '../state'; -import { calculateTokenPrice, disconnectProvider, TxStatusUpdate } from '../utils'; +import { UpdateAction, UpdateDataCtx } from './updateStateModel'; +import { calculateTokenPrice, TxStatusUpdate } from '../utils'; import { ERC20 } from '../assets/abi/ERC20'; import { ERC721Uri } from '../assets/abi/ERC721Uri'; import { ERC1155Uri } from '../assets/abi/ERC1155Uri'; -import { initProvider } from '../utils/providerUtil'; -import { currentNetwork$, setCurrentNetwork, setCurrentProvider } from './providerState'; -import { - apolloDexClientSubj, apolloExplorerClientSubj, GQLUrl, setApolloDexUrls, setApolloExplorerUrls, -} from '../graphql'; import { ipfsUrlResolverFn } from '../utils/nftUtil'; import { PoolReserves } from '../graphql/pools'; +import { ReefSigner } from '../state'; -type destroyConnection = ()=>void; - -type GQLUrlType = 'explorer' | 'dex'; +export const reloadSignersSubj = new Subject>(); // eslint-disable-next-line import/no-mutable-exports export let _NFT_IPFS_RESOLVER_FN: ipfsUrlResolverFn|undefined; @@ -87,133 +65,3 @@ export const getContractTypeAbi = (contractType: ContractType): ContractInterfac return [] as ContractInterface; } }; - -export const getGQLUrls = (network: Network): Map => { - const gqlUrls = new Map(); - if (!network.graphqlExplorerUrl) { - return gqlUrls; - } - - const wsExplorer = network.graphqlExplorerUrl.startsWith('http') - ? network.graphqlExplorerUrl.replace('http', 'ws') - : network.graphqlExplorerUrl; - const httpExplorer = network.graphqlExplorerUrl.startsWith('ws') - ? network.graphqlExplorerUrl.replace('ws', 'http') - : network.graphqlExplorerUrl; - gqlUrls.set('explorer', { - http: httpExplorer, - ws: wsExplorer, - }); - - const wsDex = network.graphqlDexsUrl.startsWith('http') - ? network.graphqlDexsUrl.replace('http', 'ws') - : network.graphqlDexsUrl; - const httpDex = network.graphqlDexsUrl.startsWith('ws') - ? network.graphqlDexsUrl.replace('ws', 'http') - : network.graphqlDexsUrl; - gqlUrls.set('dex', { - http: httpDex, - ws: wsDex, - }); - - return gqlUrls; -}; - -export interface State { - loading: boolean; - signers?: ReefSigner[]; - provider?: Provider; - network?: Network; - error?: any; // TODO! -} - -export interface StateOptions { - network?: Network; - signers?: ReefSigner[]; - explorerClient?: ApolloClient; - dexClient?: ApolloClient; - jsonAccounts?:{accounts: AccountJson[] | InjectedAccountWithMeta[] | InjectedAccountWithMetaReef[], injectedSigner: InjectedSigningKey} - ipfsHashResolverFn?: ipfsUrlResolverFn; -} - -export function initApolloClients(selectedNetwork?: Network, explorerClient?: ApolloClient, dexClient?: ApolloClient): void { - if (selectedNetwork) { - if (!explorerClient && !dexClient) { - const gqlUrls = getGQLUrls(selectedNetwork); - if (gqlUrls) { - if (gqlUrls.get('explorer')) { - setApolloExplorerUrls(gqlUrls.get('explorer')!); - } - if (gqlUrls.get('dex')) { - setApolloDexUrls(gqlUrls.get('dex')!); - } - } - } else { - if (explorerClient) { - apolloExplorerClientSubj.next(explorerClient); - } - if (dexClient) { - apolloDexClientSubj.next(dexClient); - } - } - } -} - -function finalizeWithValue(callback: (value: T) => void) { - return (source: Observable) => defer(() => { - let lastValue: T; - return source.pipe( - tap((value) => { - lastValue = value; - }), - finalize(() => callback(lastValue)), - ); - }); -} - -export const initReefState = ( - { - network, - explorerClient, - dexClient, - signers, - jsonAccounts, - ipfsHashResolverFn, - }: StateOptions, -): destroyConnection => { - const subscription = currentNetwork$.pipe( - switchMap((network) => initProvider(network.rpcUrl) - .then((provider) => ({ - provider, - network, - }))), - scan((state: { provider: Provider }, newVal: { provider: Provider, network }) => { - if (state.provider) { - disconnectProvider(state.provider); - } - return { provider: newVal.provider, network: newVal.network }; - }, {}), - tap((p_n: { provider: Provider, network: Network }) => { - setCurrentProvider(p_n.provider); - }), - tap((p_n) => { - initApolloClients(p_n.network, explorerClient, dexClient); - }), - finalizeWithValue(((p_n) => disconnectProvider(p_n.provider))), - ) - .subscribe({ - error: (e) => { - console.log('initReefState ERR=', e); - }, - }); - setCurrentNetwork(network || availableNetworks.mainnet); - setNftIpfsResolverFn(ipfsHashResolverFn); - if (signers) { - accountsSubj.next(signers || null); - } - if (jsonAccounts) { - accountsJsonSigningKeySubj.next(jsonAccounts.injectedSigner); - accountsJsonSubj.next(jsonAccounts.accounts); - } - return () => subscription.unsubscribe(); -}; diff --git a/src/graphql/apollo.ts b/src/graphql/apollo.ts deleted file mode 100644 index de5f70b2..00000000 --- a/src/graphql/apollo.ts +++ /dev/null @@ -1,109 +0,0 @@ -import { - ApolloClient, ApolloLink, HttpLink, InMemoryCache, split, -} from '@apollo/client'; -import { - distinctUntilChanged, map, merge, Observable, ReplaySubject, shareReplay, -} from 'rxjs'; -import { getMainDefinition } from '@apollo/client/utilities'; -import { Observable as ZenObservable } from 'zen-observable-ts'; -import { createClient } from 'graphql-ws'; -import { GraphQLWsLink } from '@apollo/client/link/subscriptions'; - -export interface GQLUrl { - http: string; - ws: string; -} - -// Explorer -const apolloExplorerUrlsSubj = new ReplaySubject(1); -export const apolloExplorerClientSubj = new ReplaySubject>(1); - -export const setApolloExplorerUrls = (urls: GQLUrl): void => { - apolloExplorerUrlsSubj.next(urls); -}; - -const splitExplorerLink$ = apolloExplorerUrlsSubj.pipe( - map((urls: GQLUrl) => { - const httpLink = new HttpLink({ - uri: urls.http, - }); - const wsLink = new GraphQLWsLink(createClient({ - url: urls.ws, - })); - return split( - ({ query }) => { - const definition = getMainDefinition(query); - - return ( - definition.kind === 'OperationDefinition' - && definition.operation === 'subscription' - ); - }, - wsLink, - httpLink, - ); - }), - shareReplay(1), -); -const apolloExplorerLinksClientInstance$: Observable> = splitExplorerLink$.pipe( - map( - (splitLink) => new ApolloClient({ - cache: new InMemoryCache(), - link: ApolloLink.from([splitLink]), - }), - ), - shareReplay(1), -); - -export const apolloExplorerClientInstance$: Observable> = merge(apolloExplorerLinksClientInstance$, apolloExplorerClientSubj).pipe( - distinctUntilChanged(), - shareReplay(1), -); - -// DEX -const apolloDexUrlsSubj = new ReplaySubject(1); -export const apolloDexClientSubj = new ReplaySubject>(1); - -export const setApolloDexUrls = (urls: GQLUrl): void => { - apolloDexUrlsSubj.next(urls); -}; - -const splitDexLink$ = apolloDexUrlsSubj.pipe( - map((urls: GQLUrl) => { - const httpLink = new HttpLink({ - uri: urls.http, - }); - const wsLink = new GraphQLWsLink(createClient({ - url: urls.ws, - })); - return split( - ({ query }) => { - const definition = getMainDefinition(query); - - return ( - definition.kind === 'OperationDefinition' - && definition.operation === 'subscription' - ); - }, - wsLink, - httpLink, - ); - }), - shareReplay(1), -); -const apolloDexLinksClientInstance$: Observable> = splitDexLink$.pipe( - map( - (splitLink) => new ApolloClient({ - cache: new InMemoryCache(), - link: ApolloLink.from([splitLink]), - }), - ), - shareReplay(1), -); - -export const apolloDexClientInstance$: Observable> = merge(apolloDexLinksClientInstance$, apolloDexClientSubj).pipe( - distinctUntilChanged(), - shareReplay(1), -); - -export const zenToRx = (zenObservable: ZenObservable): Observable => new Observable((observer) => zenObservable.subscribe(observer)); diff --git a/src/graphql/evmEvents.ts b/src/graphql/evmEvents.ts deleted file mode 100644 index fa61842a..00000000 --- a/src/graphql/evmEvents.ts +++ /dev/null @@ -1,124 +0,0 @@ -import { ApolloClient, gql, SubscriptionOptions } from '@apollo/client'; -import { utils } from 'ethers'; -import { - from, map, Observable, of, scan, shareReplay, switchMap, -} from 'rxjs'; -import { apolloExplorerClientInstance$, zenToRx } from './apollo'; - -const getGqlContractEventsQuery = ( - contractAddress: string, - methodSignature?: string | null, - fromBlockId?: number, - toBlockId?: number, -): SubscriptionOptions => { - const EVM_EVENT_GQL = gql` - query evmEvent( - $address: String_comparison_exp! - $blockId: bigint_comparison_exp! - $topic0: String_comparison_exp - ) { - evm_event( - order_by: [ - { block_id: desc } - { extrinsic_index: desc } - { event_index: desc } - ] - where: { - _and: [ - { contract_address: $address } - { topic_0: $topic0 } - { method: { _eq: "Log" } } - { block_id: $blockId } - ] - } - ) { - contract_address - data_parsed - data_raw - topic_0 - topic_1 - topic_2 - topic_3 - block_id - extrinsic_index - event_index - } - } - `; - return { - query: EVM_EVENT_GQL, - variables: { - address: { _eq: contractAddress }, - topic0: methodSignature - ? { _eq: utils.keccak256(utils.toUtf8Bytes(methodSignature)) } - : {}, - blockId: toBlockId ? { _gte: fromBlockId, _lte: toBlockId } : { _eq: fromBlockId }, - }, - fetchPolicy: 'network-only', - }; -}; - -const getGqlLastFinalizedBlock = (): SubscriptionOptions => { - const FINALISED_BLOCK_GQL = gql` - subscription finalisedBlock { - block(order_by: {id: desc}, limit: 1, where: {finalized: {_eq: true}}) { - id - } - } - `; - return { - query: FINALISED_BLOCK_GQL, - variables: {}, - fetchPolicy: 'network-only', - }; -}; - -export function getEvmEvents$(contractAddress: string, methodSignature?: string, fromBlockId?: number, toBlockId?: number): Observable<{ fromBlockId:number, toBlockId:number, evmEvents:any[] }|null> { - if (!contractAddress) { - console.warn('getEvmEvents$ expects contractAddress'); - return of(null); - } - if (!fromBlockId) { - return apolloExplorerClientInstance$.pipe( - switchMap((apolloClient: ApolloClient) => zenToRx(apolloClient.subscribe(getGqlLastFinalizedBlock())).pipe( - scan((state, res: any) => { - const block = res?.data?.block?.length ? res.data.block[0] : null; - if (!block) { - console.warn('getEvmEvents$ NO FINALISED BLOCK RESULT', res); - return state; - } - const newBlockId = block.id; - const diff = state.prevBlockId ? newBlockId - state.prevBlockId : 1; - let fromBlockId = newBlockId; - let toBlockId; - if (diff > 1 && state.prevBlockId) { - toBlockId = newBlockId; - fromBlockId = state.prevBlockId + 1; - } - return { prevBlockId: newBlockId, fromBlockId, toBlockId }; - }, { prevBlockId: undefined, fromBlockId: undefined, toBlockId: undefined }), - switchMap((res: { fromBlockId: number, toBlockId: number | undefined }) => from(apolloClient?.query( - getGqlContractEventsQuery(contractAddress, methodSignature, res.fromBlockId, res.toBlockId), - )).pipe( - map((events) => ({ - fromBlockId: res.fromBlockId, - toBlockId: res.toBlockId || res.fromBlockId, - evmEvents: events.data.evm_event, - })), - )), - ) as Observable), - shareReplay(1), - ); - } - return apolloExplorerClientInstance$.pipe( - switchMap((apolloClient: ApolloClient) => from(apolloClient?.query( - getGqlContractEventsQuery(contractAddress, methodSignature, fromBlockId, toBlockId), - ))), - map((events) => ({ - fromBlockId, - toBlockId: toBlockId || fromBlockId, - evmEvents: events.data.evm_event, - })), - shareReplay(1), - ); -} diff --git a/src/graphql/index.ts b/src/graphql/index.ts index e559057d..8a12aabd 100644 --- a/src/graphql/index.ts +++ b/src/graphql/index.ts @@ -1,3 +1 @@ -export * from './apollo'; export * from './gql'; -export * from './evmEvents'; diff --git a/src/graphql/pools.ts b/src/graphql/pools.ts index b267d699..7846b64e 100644 --- a/src/graphql/pools.ts +++ b/src/graphql/pools.ts @@ -1,4 +1,3 @@ -import { DocumentNode, gql } from '@apollo/client'; import { BaseFeeData, BaseReservedData, BaseVolumeData, FeeData, PriceData, ReservedData, VolumeData, } from '../state'; @@ -278,7 +277,7 @@ export type PoolsListCountVar = PoolSearchVar // Graphql statements // Total supply of all pools -export const POOLS_TOTAL_VALUE_LOCKED = gql` +export const POOLS_TOTAL_VALUE_LOCKED = ` query totalSupply($toTime: String!) { totalSupply(toTime: $toTime) { pool { @@ -293,7 +292,7 @@ export const POOLS_TOTAL_VALUE_LOCKED = gql` `; // Aggregating pool hour volume -export const POOL_24H_VOLUME = gql` +export const POOL_24H_VOLUME = ` query volume($fromTime: String!) { volume(fromTime: $fromTime) { pool { @@ -307,7 +306,7 @@ export const POOL_24H_VOLUME = gql` } `; -export const POOL_SUPPLY_GQL = gql` +export const POOL_SUPPLY_GQL = ` query poolSupply($address: String!) { poolMinuteSupplies( where: { poolId_eq: $address } @@ -320,7 +319,7 @@ export const POOL_SUPPLY_GQL = gql` } `; -export const POOL_VOLUME_AGGREGATE_GQL = gql` +export const POOL_VOLUME_AGGREGATE_GQL = ` query poolVolume( $address: String! $fromTime: String! @@ -337,7 +336,7 @@ export const POOL_VOLUME_AGGREGATE_GQL = gql` } `; -const volumeQuery = (time: Time): DocumentNode => gql` +const volumeQuery = (time: Time): string => ` query volume($address: String!, $fromTime: String!) { pool${time}Volumes( where: { @@ -356,7 +355,7 @@ export const POOL_DAY_VOLUME_GQL = volumeQuery('Day'); export const POOL_HOUR_VOLUME_GQL = volumeQuery('Hour'); export const POOL_MINUTE_VOLUME_GQL = volumeQuery('Minute'); -export const POOL_FEES_GQL = gql` +export const POOL_FEES_GQL = ` query poolFee( $address: String! $fromTime: String! @@ -371,7 +370,7 @@ export const POOL_FEES_GQL = gql` } `; -export const POOL_GQL = gql` +export const POOL_GQL = ` query pool($address: String!) { poolById(id: $address) { id @@ -394,7 +393,7 @@ export const POOL_GQL = gql` } `; -export const POOL_CURRENT_RESERVES_GQL = gql` +export const POOL_CURRENT_RESERVES_GQL = ` query poolEvent($address: String!) { poolEvents( where: { pool: { id_eq: $address }, type_eq: Sync } @@ -407,7 +406,7 @@ export const POOL_CURRENT_RESERVES_GQL = gql` } `; -export const POOLS_RESERVES_GQL = gql` +export const POOLS_RESERVES_GQL = ` query poolsReserves($tokens: [String!]!) { poolsReserves(tokens: $tokens) { token1 @@ -418,7 +417,7 @@ export const POOLS_RESERVES_GQL = gql` } `; -export const POOL_TRANSACTIONS_GQL = gql` +export const POOL_TRANSACTIONS_GQL = ` subscription transactions( $search: String! $type: [PoolType!] @@ -463,7 +462,7 @@ export const POOL_TRANSACTIONS_GQL = gql` } `; -export const POOL_TRANSACTION_COUNT_GQL = gql` +export const POOL_TRANSACTION_COUNT_GQL = ` query transactionCount( $search: String! $type: [PoolType!] @@ -486,7 +485,7 @@ export const POOL_TRANSACTION_COUNT_GQL = gql` // Charts queries & subscriptions type Time = 'Day' | 'Hour' | 'Minute'; -const tvlQuery = (time: Time): DocumentNode => gql` +const tvlQuery = (time: Time): string => ` query poolSupply($address: String!, $fromTime: String!) { poolTimeSupplies( address: $address @@ -509,7 +508,7 @@ export const POOL_DAY_TVL_GQL = tvlQuery('Day'); export const POOL_HOUR_TVL_GQL = tvlQuery('Hour'); export const POOL_MINUTE_TVL_GQL = tvlQuery('Minute'); -const feeQuery = (time: Time): DocumentNode => gql` +const feeQuery = (time: Time): string => ` query fee($address: String!, $fromTime: String!) { poolTimeFees( address: $address @@ -526,7 +525,7 @@ export const POOL_DAY_FEE_QUERY_GQL = feeQuery('Day'); export const POOL_HOUR_FEE_QUERY_GQL = feeQuery('Hour'); export const POOL_MINUTE_FEE_QUERY_GQL = feeQuery('Minute'); -export const POOL_TOKENS_DATA_GQL = gql` +export const POOL_TOKENS_DATA_GQL = ` query poolTokens($address: String!) { poolById(id: $address) { token1 { @@ -547,7 +546,7 @@ export const POOL_TOKENS_DATA_GQL = gql` } `; -export const POOL_INFO_GQL = gql` +export const POOL_INFO_GQL = ` query poolInfo( $address: String! $signerAddress: String! @@ -582,7 +581,7 @@ export const POOL_INFO_GQL = gql` } `; -export const poolDataQuery = (time: Time): DocumentNode => gql` +export const poolDataQuery = (time: Time): string => ` query poolData($address: String!, $fromTime: String!) { poolData( address: $address, @@ -613,7 +612,7 @@ export const poolDataQuery = (time: Time): DocumentNode => gql` } `; -export const ALL_POOLS = gql` +export const ALL_POOLS = ` query allPools { allPools { address @@ -633,7 +632,7 @@ export const ALL_POOLS = gql` } `; -export const ALL_POOLS_LIST = gql` +export const ALL_POOLS_LIST = ` query allPoolsList($signerAddress: String!, $limit: Float!, $offset: Float!, $search: String!) { allPoolsList(signerAddress: $signerAddress, limit: $limit, offset: $offset, search: $search) { id @@ -659,13 +658,13 @@ export const ALL_POOLS_LIST = gql` } `; -export const ALL_POOLS_LIST_COUNT = gql` +export const ALL_POOLS_LIST_COUNT = ` query allPoolsListCount($signerAddress: String!, $search: String!) { allPoolsListCount(signerAddress: $signerAddress, search: $search) } `; -export const USER_POOLS_LIST = gql` +export const USER_POOLS_LIST = ` query userPoolsList($signerAddress: String!, $limit: Float!, $offset: Float!, $search: String!) { userPoolsList(signerAddress: $signerAddress, limit: $limit, offset: $offset, search: $search) { id @@ -689,13 +688,13 @@ export const USER_POOLS_LIST = gql` } `; -export const USER_POOLS_LIST_COUNT = gql` +export const USER_POOLS_LIST_COUNT = ` query userPoolsListCount($signerAddress: String!, $search: String!) { userPoolsListCount(signerAddress: $signerAddress, search: $search) } `; -export const USER_POOL_SUPPLY = gql` +export const USER_POOL_SUPPLY = ` query userPoolSupply($token1: String!, $token2: String!, $signerAddress: String!) { userPoolSupply(token1: $token1, token2: $token2, signerAddress: $signerAddress) { address diff --git a/src/graphql/utils.ts b/src/graphql/utils.ts new file mode 100644 index 00000000..25622a54 --- /dev/null +++ b/src/graphql/utils.ts @@ -0,0 +1,52 @@ +import { AxiosInstance } from "axios"; +const ACTIVE_NETWORK_LS_KEY = "reef-app-active-network"; + +const graphqlUrls = { + explorerTestnet:'https://squid.subsquid.io/reef-explorer-testnet/graphql', + dexTestnet:'https://squid.subsquid.io/reef-swap-testnet/graphql', + explorerMainnet:'https://squid.subsquid.io/reef-explorer/graphql', + dexMainnet:'https://squid.subsquid.io/reef-swap/graphql' + } + + const getGraphqlEndpoint = (network:string,isExplorer:boolean):string=>{ + if(isExplorer){ + if(network=='testnet'){ + return graphqlUrls.explorerTestnet + }else{ + return graphqlUrls.explorerMainnet + } + }else{ + if(network=='testnet'){ + return graphqlUrls.dexTestnet; + } + } + return graphqlUrls.dexMainnet; + } + + export const graphqlRequest = ( + httpClient: AxiosInstance, + queryObj: { query: string; variables: any }, + isExplorer?:boolean + ) => { + let selectedNetwork:string="mainnet"; + try { + let storedNetwork = localStorage.getItem(ACTIVE_NETWORK_LS_KEY); + if(storedNetwork){ + let parsedStoredNetwork = JSON.parse(storedNetwork); + selectedNetwork = parsedStoredNetwork.name; + } + } catch (error) { + console.log(error); + } + const graphql = JSON.stringify(queryObj); + if(isExplorer){ + let url = getGraphqlEndpoint(selectedNetwork!,true); + return httpClient.post(url, graphql, { + headers: { 'Content-Type': 'application/json' }, + }); + } + let url = getGraphqlEndpoint(selectedNetwork!,false); + return httpClient.post(url, graphql, { + headers: { 'Content-Type': 'application/json' }, + }); +}; \ No newline at end of file diff --git a/src/hooks/index.ts b/src/hooks/index.ts index 04e008e1..5108642c 100644 --- a/src/hooks/index.ts +++ b/src/hooks/index.ts @@ -2,9 +2,6 @@ export * from './useProvider'; export * from './useAsyncEffect'; export * from './useUpdateAccountBalance'; export * from './useLoadSignerTokens'; -export * from './useReefPriceInterval'; -export * from './useLoadSigners'; -export * from './useInitReefState'; export * from './useObservableState'; export * from './useLoader'; export * from './poolHooks'; diff --git a/src/hooks/poolHooks.ts b/src/hooks/poolHooks.ts index 70eb7bcb..142f2188 100644 --- a/src/hooks/poolHooks.ts +++ b/src/hooks/poolHooks.ts @@ -1,71 +1,129 @@ import { - ApolloClient, - QueryResult, SubscriptionResult, useQuery, - useSubscription, -} from '@apollo/client'; -import { - PoolBasicTransactionVar, PoolDayFeeQuery, PoolDayVolumeQuery, PoolFeeQuery, PoolFeeVar, PoolDayFeeVar, - PoolQuery, PoolReservesQuery, PoolReservesVar, PoolSupplyQuery, PoolSupplyVar, PoolTransactionCountQuery, - PoolTransactionQuery, PoolTransactionVar, PoolDayTvlQuery, PoolDayTvlVar, PoolVar, PoolVolumeAggregateQuery, - PoolVolumeAggregateVar, PoolVolumeVar, POOL_CURRENT_RESERVES_GQL, POOL_DAY_FEE_QUERY_GQL, POOL_DAY_TVL_GQL, + PoolBasicTransactionVar, PoolDayFeeQuery, PoolDayVolumeQuery, PoolFeeQuery, + PoolQuery, PoolReservesQuery, PoolSupplyQuery, PoolTransactionCountQuery, + PoolTransactionQuery, PoolDayTvlQuery, PoolVolumeAggregateQuery, + POOL_CURRENT_RESERVES_GQL, POOL_DAY_FEE_QUERY_GQL, POOL_DAY_TVL_GQL, POOL_DAY_VOLUME_GQL, POOL_FEES_GQL, POOL_GQL, POOL_SUPPLY_GQL, POOL_TRANSACTIONS_GQL, POOL_TRANSACTION_COUNT_GQL, POOL_VOLUME_AGGREGATE_GQL, TransactionTypes, } from '../graphql/pools'; import useInterval from './userInterval'; import { POLL_INTERVAL } from '../utils'; +import axios, { AxiosInstance } from 'axios'; +import { useEffect, useState } from 'react'; +import { graphqlRequest } from '../graphql/utils'; + +const getPoolVolumeAggregateQuery = (address: string, + fromTime: string, + toTime: string) => ({ + query: POOL_VOLUME_AGGREGATE_GQL, + variables: { + address, + fromTime, + toTime, + }, +}); // Intermediate query hooks export const useDayVolume = ( address: string, fromTime: string, toTime: string, -): QueryResult => useQuery( - POOL_VOLUME_AGGREGATE_GQL, - { - variables: { - address, - fromTime, - toTime, - }, - }, -); +): PoolVolumeAggregateQuery => { + const [data, setData] = useState() + const poolCurrReservesQry = getPoolVolumeAggregateQuery(address,fromTime,toTime); + useEffect(()=>{ + const handleResponse = async()=>{ + const response = await graphqlRequest(axios,poolCurrReservesQry); + setData(response.data); + } + handleResponse(); + },[]); + + return data as any; +} + +const getPoolSupplyQuery = (address: string) => ({ + query: POOL_SUPPLY_GQL, + variables: { address }, +}); + export const useCurrentPoolSupply = ( address: string, -): QueryResult => useQuery(POOL_SUPPLY_GQL, { - variables: { address }, +): PoolSupplyQuery =>{ + const [data, setData] = useState() + const poolCurrReservesQry = getPoolSupplyQuery(address); + useEffect(()=>{ + const handleResponse = async()=>{ + const response = await graphqlRequest(axios,poolCurrReservesQry); + setData(response.data); + } + handleResponse(); + },[]); + + return data as any; + +} + +export const getPoolFeesQuery = (address: string, fromTime: string) => ({ + query: POOL_FEES_GQL, + variables: { + address, + fromTime, + }, }); + export const useDayFee = ( address: string, fromTime: string, -): QueryResult => useQuery(POOL_FEES_GQL, { - variables: { address, fromTime }, -}); +): PoolFeeQuery =>{ + + const [data, setData] = useState() + const poolCurrReservesQry = getPoolFeesQuery(address,fromTime); + useEffect(()=>{ + const handleResponse = async()=>{ + const response = await graphqlRequest(axios,poolCurrReservesQry); + setData(response.data); + } + handleResponse(); + },[]); -export const usePoolQuery = (address: string): QueryResult => useQuery(POOL_GQL, { + return data as any; +} + +const getPoolQuery = (address: string) => ({ + query: POOL_GQL, variables: { address }, }); +export const usePoolQuery = (address: string): PoolQuery => +{ + const [data, setData] = useState() + const poolQry = getPoolQuery(address); + useEffect(()=>{ + const handleResponse = async()=>{ + const response = await graphqlRequest(axios,poolQry); + setData(response.data); + } + handleResponse(); + },[]); + + return data as any; +} export const useCurrentPoolReserve = ( address: string, -): QueryResult => useQuery(POOL_CURRENT_RESERVES_GQL, { - variables: { address }, -}); +): PoolReservesQuery =>{ + const [data, setData] = useState() + const poolCurrReservesQry = getPoolCurrentReservesQry(address); + useEffect(()=>{ + const handleResponse = async()=>{ + const response = await graphqlRequest(axios,poolCurrReservesQry); + setData(response.data); + } + handleResponse(); + },[]); -// export const usePools = ( -// fromTime: string, -// offset: number, -// search?: string, -// ): QueryResult => useQuery(POOLS_GQL, { -// variables: { -// fromTime, -// offset, -// search: search || '', -// }, -// }); - -// export const usePoolCount = (search?: string): QueryResult => useQuery(POOL_COUNT_GQL, { -// variables: { search: search ? { _ilike: `${search}%` } : {} }, -// }); + return data as any; +} const resolveTransactionVariables = ( search: string | undefined, @@ -74,75 +132,142 @@ const resolveTransactionVariables = ( search: search || '', type: type === 'All' ? ['Swap', 'Mint', 'Burn'] : [type], }); + +const getPoolTransactionCountQry =(address: string | undefined, type: TransactionTypes) => ({ + query: POOL_TRANSACTION_COUNT_GQL, + variables: resolveTransactionVariables(address, type), +}); + +const getPoolCurrentReservesQry =(address: string) => ({ + query: POOL_CURRENT_RESERVES_GQL, + variables: {address}, +}); + +const getPoolTransactionQry = (address: string | undefined, type: TransactionTypes, limit: number, pageIndex: number): {query: string, variables: any} => ({ + query: POOL_TRANSACTIONS_GQL, + variables: { + ...resolveTransactionVariables(address, type), + limit, + offset: pageIndex * limit, + }, +}); + + export const usePoolTransactionCountSubscription = ( address: string | undefined, type: TransactionTypes, - dexClient: ApolloClient, -): QueryResult => { - if (dexClient === undefined) { + httpClient: AxiosInstance, +): {data:PoolTransactionCountQuery,loading:boolean} => { + const [data,setData]= useState(); + const [loading,setLoading] = useState(true); + if (httpClient === undefined) { return [undefined, true] as any; } - - const { data, loading, refetch } = useQuery( - POOL_TRANSACTION_COUNT_GQL, - { - client: dexClient, - variables: resolveTransactionVariables(address, type), - }, - ); - - useInterval(() => { - refetch(); + const queryObj = getPoolTransactionCountQry(address, type); + useInterval(async() => { + setLoading(true); + const response = await graphqlRequest(httpClient, queryObj); + setData(response.data); + setLoading(false); }, POLL_INTERVAL); - return [data, loading] as any; + return {data, loading} as any; }; + export const usePoolTransactionSubscription = ( address: string | undefined, type: TransactionTypes, pageIndex = 0, limit = 10, - dexClient: ApolloClient, -): SubscriptionResult => useSubscription( - POOL_TRANSACTIONS_GQL, - { - client: dexClient, + httpClient: AxiosInstance, +): {data:PoolTransactionQuery,loading:boolean} => { + const [data,setData]= useState(); + const [loading,setLoading] = useState(true); + if (httpClient === undefined) { + return [undefined, true] as any; + } + const queryObj = getPoolTransactionQry(address, type, limit, pageIndex); + + useInterval(async() => { + setLoading(true); + const response = await graphqlRequest(httpClient, queryObj); + setData(response.data); + setLoading(false); + }, POLL_INTERVAL); + + return {data, loading} as any; + } + + const getPoolDayTvlQuery = (address: string, fromTime: string) => ({ + query: POOL_DAY_TVL_GQL, variables: { - ...resolveTransactionVariables(address, type), - limit, - offset: pageIndex * limit, + address, + fromTime, }, - }, -); + }); export const useDayTvl = ( address: string, fromTime: number, -): QueryResult => useQuery(POOL_DAY_TVL_GQL, { +): PoolDayTvlQuery => { + const [data, setData] = useState() + const poolCurrReservesQry = getPoolDayTvlQuery(address, new Date(fromTime).toISOString()); + useEffect(()=>{ + const handleResponse = async()=>{ + const response = await graphqlRequest(axios,poolCurrReservesQry); + setData(response.data); + } + handleResponse(); + },[]); + + return data as any; +} + +const getPoolDayVolumeQuery = (address: string, fromTime: string) => ({ + query: POOL_DAY_VOLUME_GQL, variables: { address, - fromTime: new Date(fromTime).toISOString(), + fromTime, }, }); + export const useDayPoolVolume = ( address: string, fromTime: number, -): QueryResult => useQuery(POOL_DAY_VOLUME_GQL, { +): PoolDayVolumeQuery => { + const [data, setData] = useState() + const poolCurrReservesQry = getPoolDayVolumeQuery(address, new Date(fromTime).toISOString()); + useEffect(()=>{ + const handleResponse = async()=>{ + const response = await graphqlRequest(axios,poolCurrReservesQry); + setData(response.data); + } + handleResponse(); + },[]); + + return data as any; +} + +const getPoolDayFeeQuery = (address: string, fromTime: string) => ({ + query: POOL_DAY_FEE_QUERY_GQL, variables: { address, - fromTime: new Date(fromTime).toISOString(), + fromTime, }, }); export const useDayPoolFee = ( address: string, fromTime: number, -): SubscriptionResult => useQuery( - POOL_DAY_FEE_QUERY_GQL, - { - variables: { - address, - fromTime: new Date(fromTime).toISOString(), - }, - }, -); +): PoolDayFeeQuery => {const [data, setData] = useState() + const poolCurrReservesQry = getPoolDayFeeQuery(address, new Date(fromTime).toISOString()); + useEffect(()=>{ + const handleResponse = async()=>{ + const response = await graphqlRequest(axios,poolCurrReservesQry); + setData(response.data); + } + handleResponse(); + },[]); + + return data as any; +} \ No newline at end of file diff --git a/src/hooks/useAddLiquidity.tsx b/src/hooks/useAddLiquidity.tsx index 36cb8f5d..a584a26e 100644 --- a/src/hooks/useAddLiquidity.tsx +++ b/src/hooks/useAddLiquidity.tsx @@ -1,7 +1,6 @@ import Uik from '@reef-chain/ui-kit'; import React, { Dispatch, useEffect } from 'react'; import { BigNumber, Contract } from 'ethers'; -import { ApolloClient } from '@apollo/client'; import { ERC20 } from '../assets/abi/ERC20'; import { getReefswapRouter } from '../rpc'; import { @@ -40,13 +39,14 @@ import { import { useKeepTokenUpdated } from './useKeepTokenUpdated'; import { useLoadPool } from './useLoadPool'; import { useUpdateLiquidityAmount } from './useUpdateAmount'; +import { AxiosInstance } from 'axios'; interface UseAddLiquidityState { address1: string; address2: string; state: AddLiquidityState; tokens: Token[]; - dexClient?: ApolloClient; + httpClient?: AxiosInstance; signer?: ReefSigner; tokenPrices: AddressToNumber; dispatch: Dispatch; @@ -91,7 +91,7 @@ export const useAddLiquidity = ({ state, tokens, signer, - dexClient, + httpClient, tokenPrices, }: UseAddLiquidityState): void => { const { @@ -101,7 +101,7 @@ export const useAddLiquidity = ({ token1, token2, signer?.address || '', - dexClient, + httpClient, isLoading, ); const newPoolSupply = calculatePoolSupply(token1, token2, pool); @@ -435,4 +435,4 @@ export const onAddLiquidity = ({ dispatch(setLoadingAction(false)); dispatch(clearTokenAmountsAction()); } -}; +}; \ No newline at end of file diff --git a/src/hooks/useAllNfts.ts b/src/hooks/useAllNfts.ts index 00f1f3a2..2c9f47d9 100644 --- a/src/hooks/useAllNfts.ts +++ b/src/hooks/useAllNfts.ts @@ -1,11 +1,11 @@ import { NFT } from '../state'; import { useObservableState } from './useObservableState'; -import { selectedSignerNFTs$ } from '../appState/nftTokenState'; +import {reefState} from "@reef-chain/util-lib"; type UseAllNfts = [NFT[], boolean]; export const useAllNfts = (): UseAllNfts => { - const nfts = useObservableState(selectedSignerNFTs$); + const nfts = useObservableState(reefState.selectedNFTs$); const loading = nfts === undefined; - + return [nfts || [], loading]; }; diff --git a/src/hooks/useAllPools.ts b/src/hooks/useAllPools.ts index 8ddc0c2e..d584b49c 100644 --- a/src/hooks/useAllPools.ts +++ b/src/hooks/useAllPools.ts @@ -1,24 +1,28 @@ -import { ApolloClient, useQuery } from '@apollo/client'; -import { AllPoolsQuery, ALL_POOLS } from '../graphql/pools'; +import { AxiosInstance } from 'axios'; +import { ALL_POOLS } from '../graphql/pools'; import { POLL_INTERVAL, getIconUrl } from '../utils'; +import { useState } from 'react'; import useInterval from './userInterval'; import { PoolWithReserves } from '../state'; +import { graphqlRequest } from '../graphql/utils'; -export const useAllPools = (dexClient: ApolloClient): PoolWithReserves[] => { - const { data, refetch } = useQuery( - ALL_POOLS, - { client: dexClient }, - ); +export const getAllPoolsQuery = () => ({ + query: ALL_POOLS, + variables: {} +}); +export const useAllPools = (httpClient: AxiosInstance): PoolWithReserves[] => { + const [allPools,setAllPools] = useState([]); + const getAllPoolsQry = getAllPoolsQuery(); - useInterval(() => { - refetch(); + useInterval(async() => { + const response = await graphqlRequest(httpClient, getAllPoolsQry); + let pools = response.data.data?.allPools.map((pool) => ({ + ...pool, + iconUrl1: pool.iconUrl1 === '' ? getIconUrl(pool.token1) : pool.iconUrl1, + iconUrl2: pool.iconUrl2 === '' ? getIconUrl(pool.token2) : pool.iconUrl2, + })); + setAllPools(pools); }, POLL_INTERVAL); - const pools = data?.allPools.map((pool) => ({ - ...pool, - iconUrl1: pool.iconUrl1 === '' ? getIconUrl(pool.token1) : pool.iconUrl1, - iconUrl2: pool.iconUrl2 === '' ? getIconUrl(pool.token2) : pool.iconUrl2, - })); - - return pools || []; -}; + return allPools; +}; \ No newline at end of file diff --git a/src/hooks/useFromTime.ts b/src/hooks/useFromTime.ts index 8c94c8ca..970f8f2d 100644 --- a/src/hooks/useFromTime.ts +++ b/src/hooks/useFromTime.ts @@ -50,4 +50,4 @@ export const calcTimeRange = (timeUnit: TimeUnit, timeSpan: number) => { const fromTime = new Date(toTime.getTime() - timeDataToMs({ timeUnit, timeSpan })); return { fromTime, toTime }; -}; +}; \ No newline at end of file diff --git a/src/hooks/useInitReefState.ts b/src/hooks/useInitReefState.ts deleted file mode 100644 index d297fdf5..00000000 --- a/src/hooks/useInitReefState.ts +++ /dev/null @@ -1,84 +0,0 @@ -import { useEffect, useState } from 'react'; -import { useObservableState } from './useObservableState'; -import { availableNetworks, Network } from '../state'; -import { useProvider } from './useProvider'; -import { - ACTIVE_NETWORK_LS_KEY, - currentNetwork$, - setCurrentNetwork, - setCurrentProvider, -} from '../appState/providerState'; -import { accountsSubj } from '../appState/accountState'; -import { useLoadSigners } from './useLoadSigners'; -import { disconnectProvider } from '../utils/providerUtil'; -import { - _NFT_IPFS_RESOLVER_FN, initApolloClients, setNftIpfsResolverFn, State, StateOptions, -} from '../appState/util'; - -const getNetworkFallback = (): Network => { - let storedNetwork; - try { - storedNetwork = localStorage.getItem(ACTIVE_NETWORK_LS_KEY); - storedNetwork = JSON.parse(storedNetwork); - storedNetwork = availableNetworks[storedNetwork.name]; - } catch (e) { - // when cookies disabled localStorage can throw - } - return storedNetwork != null ? storedNetwork : availableNetworks.mainnet; -}; - -export const useInitReefState = ( - applicationDisplayName: string, - options: StateOptions = {}, -): State => { - const { - network, explorerClient, dexClient, signers, ipfsHashResolverFn, - } = options; - const selectedNetwork: Network|undefined = useObservableState(currentNetwork$); - const [provider, isProviderLoading] = useProvider((selectedNetwork as Network)?.rpcUrl); - const [loadedSigners, isSignersLoading, error] = useLoadSigners(applicationDisplayName, signers ? undefined : provider, signers); - const [loading, setLoading] = useState(false); - useEffect(() => { - const newNetwork = network ?? getNetworkFallback(); - if (newNetwork !== selectedNetwork) { - setCurrentNetwork(newNetwork); - } - }, [network]); - - useEffect(() => { - setNftIpfsResolverFn(ipfsHashResolverFn); - }, [ipfsHashResolverFn]); - - useEffect(() => { - initApolloClients(selectedNetwork, explorerClient, dexClient); - }, [selectedNetwork, explorerClient, dexClient]); - - useEffect(() => { - if (provider) { - setCurrentProvider(provider); - } - return () => { - if (provider) { - const disc = async (prov) => { - await disconnectProvider(prov); - }; - disc(provider); - } - }; - }, [provider]); - - useEffect(() => { - accountsSubj.next(signers || loadedSigners || []); - }, [loadedSigners, signers]); - - useEffect(() => { - setLoading(isProviderLoading || isSignersLoading); - }, [isProviderLoading, isSignersLoading]); - return { - error, - loading, - provider, - network: selectedNetwork, - signers: loadedSigners, - }; -}; diff --git a/src/hooks/useKeepTokenUpdated.ts b/src/hooks/useKeepTokenUpdated.ts index c6c79c8a..3cf2edc4 100644 --- a/src/hooks/useKeepTokenUpdated.ts +++ b/src/hooks/useKeepTokenUpdated.ts @@ -32,4 +32,4 @@ export const useKeepTokenUpdated = ( const price = tokenPrices[address]; setToken({ ...foundToken, amount: token.amount, price }); }, [address, tokens, tokenPrices[address]]); -}; +}; \ No newline at end of file diff --git a/src/hooks/useLoadPool.ts b/src/hooks/useLoadPool.ts index b2e8c6df..2dd3d99f 100644 --- a/src/hooks/useLoadPool.ts +++ b/src/hooks/useLoadPool.ts @@ -1,30 +1,27 @@ import { useState, useEffect } from 'react'; -import { ApolloClient } from '@apollo/client'; import { BigNumber } from 'ethers'; import { Pool, Token } from '..'; -import { USER_POOL_SUPPLY, UserPoolSupplyQuery, UserPoolSupplyVar } from '../graphql/pools'; +import { USER_POOL_SUPPLY } from '../graphql/pools'; import { EMPTY_ADDRESS, ensure } from '../utils'; +import { AxiosInstance } from 'axios'; +import { graphqlRequest } from '../graphql/utils'; type LoadingPool = Pool | undefined; +export const getUserPoolSupply = (token1:string, token2:string, signerAddress:string) => ({ + query: USER_POOL_SUPPLY, + variables: { token1, token2, signerAddress }, +}); + export const loadPool = async ( token1: Token, token2: Token, signerAddress: string, - dexClient: ApolloClient, + httpClient:AxiosInstance, ): Promise => { - const result = await dexClient.query( - { - query: USER_POOL_SUPPLY, - variables: { - token1: token1.address, - token2: token2.address, - signerAddress, - }, - }, - ); - - const userPoolSupply = result.data?.userPoolSupply || undefined; + const getUserPoolQry = getUserPoolSupply(token1.address, token2.address, signerAddress); + const result = await graphqlRequest(httpClient, getUserPoolQry); + const userPoolSupply = result.data.data?.userPoolSupply || undefined; ensure(!!userPoolSupply && userPoolSupply.address !== EMPTY_ADDRESS, 'Pool does not exist!'); @@ -54,7 +51,7 @@ export const useLoadPool = ( token1: Token, token2: Token, userAddress: string, - dexClient?: ApolloClient, + httpClient?:AxiosInstance, disable?: boolean, ): [LoadingPool, boolean] => { const [pool, setPool] = useState(); @@ -62,12 +59,12 @@ export const useLoadPool = ( useEffect(() => { const load = async (): Promise => { - if (!token1.address || !token2.address || token2.address === '0x' || userAddress === '' || !dexClient || disable) { + if (!token1.address || !token2.address || token2.address === '0x' || userAddress === '' || !httpClient || disable) { return; } Promise.resolve() .then(() => setIsLoading(true)) - .then(() => loadPool(token1, token2, userAddress, dexClient)) + .then(() => loadPool(token1, token2, userAddress, httpClient)) .then(setPool) .catch((e: any) => { console.error('useLoadPool error', e); @@ -80,4 +77,4 @@ export const useLoadPool = ( }, [token1.address, token2.address, token1.balance, token2.balance]); return [pool, isLoading]; -}; +}; \ No newline at end of file diff --git a/src/hooks/useLoadPools.ts b/src/hooks/useLoadPools.ts index ddf8567e..e1448f3b 100644 --- a/src/hooks/useLoadPools.ts +++ b/src/hooks/useLoadPools.ts @@ -1,13 +1,13 @@ import { useEffect, useRef, useState } from 'react'; -import { ApolloClient } from '@apollo/client'; import { Token, Pool } from '..'; import { ensureVoidRun, uniqueCombinations } from '../utils/utils'; import { loadPool } from './useLoadPool'; +import { AxiosInstance } from 'axios'; export const loadPools = async ( tokens: Token[], userAddress: string, - dexClient: ApolloClient, + httpClient: AxiosInstance, ): Promise => { const tokenCombinations = uniqueCombinations(tokens); const pools: Pool[] = []; @@ -15,7 +15,7 @@ export const loadPools = async ( try { const [token1, token2] = tokenCombinations[index]; /* eslint-disable no-await-in-loop */ - const pool = await loadPool(token1, token2, userAddress, dexClient); + const pool = await loadPool(token1, token2, userAddress, httpClient); /* eslint-disable no-await-in-loop */ pools.push(pool); } catch (e) {} @@ -26,7 +26,7 @@ export const loadPools = async ( export const useLoadPools = ( tokens: Token[], userAddress: string, - dexClient?: ApolloClient, + httpClient?: AxiosInstance, ): [Pool[], boolean] => { const mounted = useRef(true); @@ -36,13 +36,13 @@ export const useLoadPools = ( const ensureMounted = ensureVoidRun(mounted.current); useEffect(() => { - if (!dexClient) return; + if (!httpClient) return; const load = async (): Promise => Promise.resolve() .then(() => { mounted.current = true; }) .then(() => setIsLoading(true)) - .then(() => loadPools(tokens, userAddress, dexClient)) + .then(() => loadPools(tokens, userAddress, httpClient)) .then((res) => ensureMounted(setPools, res)) .catch(() => ensureMounted(setPools, [])) .finally(() => ensureMounted(setIsLoading, false)); @@ -51,7 +51,7 @@ export const useLoadPools = ( return () => { mounted.current = false; }; - }, [tokens, dexClient, userAddress]); + }, [tokens, httpClient, userAddress]); return [pools, isLoading]; -}; +}; \ No newline at end of file diff --git a/src/hooks/useLoadSigners.ts b/src/hooks/useLoadSigners.ts deleted file mode 100644 index 7b59a166..00000000 --- a/src/hooks/useLoadSigners.ts +++ /dev/null @@ -1,109 +0,0 @@ -import { Provider } from '@reef-defi/evm-provider'; -import { web3Accounts, web3Enable } from '@reef-defi/extension-dapp'; -import { InjectedExtension } from '@reef-defi/extension-inject/types'; -import { useEffect, useState } from 'react'; -import { ReefSigner } from '../state'; -import { useAsyncEffect } from './useAsyncEffect'; -import { getExtensionSigners } from '../rpc'; -import { setCurrentAddress } from '../appState/accountState'; - -function getBrowserExtensionUrl(): string | undefined { - const isFirefox = navigator.userAgent.toLowerCase().indexOf('firefox') > -1; - if (isFirefox) { - return 'https://addons.mozilla.org/en-US/firefox/addon/reef-js-extension/'; - } - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore - const isChrome = navigator.userAgent.toLowerCase().indexOf('chrome') > -1; - if (isChrome) { - return 'https://chrome.google.com/webstore/detail/reefjs-extension/mjgkpalnahacmhkikiommfiomhjipgjn'; - } - return undefined; -} - -function getInstallExtensionMessage(): { message: string; url?: string } { - const extensionUrl = getBrowserExtensionUrl(); - const installText = extensionUrl - ? 'Please install Reef chain or some other Solidity browser extension and refresh the page.' - : 'Please use Chrome or Firefox browser.'; - return { - message: `App uses browser extension to get accounts and securely sign transactions. ${installText}`, - url: extensionUrl, - }; -} - -export const useLoadSigners = ( - appDisplayName: string, - // if provider is not passed we need to pass signers and vice versa - provider?: Provider, - signers?: ReefSigner[], -): [ - ReefSigner[], - boolean, - { code?: number; message: string; url?: string } | undefined -] => { - const [signersVal, setSignersVal] = useState(signers || []); - const [isLoading, setIsLoading] = useState(true); - const [error, setError] = useState<{ message: string; code?: number; url?: string }>(); - - useEffect(() => { - if (signers && signers.length) { - setSignersVal(signers); - } - }, [signers]); - - useAsyncEffect(async () => { - if (!provider) { - return; - } - - try { - setIsLoading(true); - const extensions: InjectedExtension[] = await web3Enable(appDisplayName); - if (extensions.length < 1) { - const installExtensionMessage = getInstallExtensionMessage(); - setError({ - code: 1, - ...installExtensionMessage, - }); - setIsLoading(false); - return; - } - - const web3accounts = await web3Accounts(); - if (web3accounts.length < 1) { - setError({ - code: 2, - message: - 'App requires at least one account in browser extension. Please create or import account/s and refresh the page.', - }); - setIsLoading(false); - return; - } - - const sgnrs = await getExtensionSigners(extensions, provider); - // TODO signers objects are large cause of provider object inside. Find a way to overcome this problem. - setSignersVal(sgnrs); - } catch (e) { - console.log('Error when loading signers!', e); - setError(e as { message: string }); - } finally { - setIsLoading(false); - } - }, [provider]); - - useEffect(() => { - if (!signersVal.length) { - return; - } - - const storedAddr = localStorage.getItem('selected_address_reef'); - if (storedAddr && signersVal.some((s) => storedAddr === s.address)) { - setCurrentAddress(storedAddr); - return; - } - setCurrentAddress(signersVal[0].address); - }, [signersVal]); - - return [signersVal, isLoading, error]; -}; diff --git a/src/hooks/usePoolData.ts b/src/hooks/usePoolData.ts index 7c474adc..538f9dda 100644 --- a/src/hooks/usePoolData.ts +++ b/src/hooks/usePoolData.ts @@ -1,9 +1,10 @@ -import { ApolloClient, useQuery } from '@apollo/client'; import BigNumber from 'bignumber.js'; -import { useEffect, useMemo } from 'react'; -import { PoolDataQuery, PoolDataVar, poolDataQuery } from '../graphql/pools'; +import { useEffect, useMemo, useState } from 'react'; +import { PoolDataQuery, poolDataQuery } from '../graphql/pools'; import { BaseCandlestickData, BaseVolumeData, CandlestickData } from '../state'; import { calcTimeRange, timeDataToMs, truncateDate } from './useFromTime'; +import { AxiosInstance } from 'axios'; +import { graphqlRequest } from '../graphql/utils'; interface Time { time: Date; @@ -172,25 +173,42 @@ interface UsePoolData { timeData: TimeData; } +const getPoolDataQry = (timeData: any,address:string,fromTime:any) => ({ + query: poolDataQuery(timeData.timeUnit), + variables: { + address, + fromTime + }, +}); + export const usePoolData = ({ address, decimals1, decimals2, price1, price2, timeData = { timeUnit: 'Day', timeSpan: 31 }, -}: UsePoolData, dexClient: ApolloClient): UsePoolDataOutput => { +}: UsePoolData, httpClient:AxiosInstance): UsePoolDataOutput => { const { fromTime, toTime } = calcTimeRange(timeData.timeUnit, timeData.timeSpan); // ********************* Get pool data from GraphQL ************************************** - const { data, loading, refetch } = useQuery( - poolDataQuery(timeData.timeUnit), - { - client: dexClient, - variables: { - address, - fromTime: fromTime.toISOString(), - }, - }, - ); + const [data, setData] = useState(); + const [loading,setLoading] = useState(true); + // const { data, loading, refetch } = useQuery( + // poolDataQuery(timeData.timeUnit), + // { + // client: dexClient, + // variables: { + // address, + // fromTime: fromTime.toISOString(), + // }, + // }, + // ); + const queryObj = getPoolDataQry(timeData,address, fromTime.toISOString()); useEffect(() => { - refetch(); - }, [timeData, refetch]); + const handleResp = async()=>{ + setLoading(true); + const response = await graphqlRequest(httpClient, queryObj); + setData(response.data.data); + setLoading(false); + } + handleResp(); + }, [timeData]); const processed = useMemo((): PoolDataTime => { if (!data) { @@ -347,4 +365,4 @@ export const usePoolData = ({ }, [data, price1, price2, decimals1, decimals2]); return [processed, loading]; -}; +}; \ No newline at end of file diff --git a/src/hooks/usePoolLists.ts b/src/hooks/usePoolLists.ts index 3297ff35..ba53fdc9 100644 --- a/src/hooks/usePoolLists.ts +++ b/src/hooks/usePoolLists.ts @@ -1,11 +1,12 @@ -import { ApolloClient, useQuery } from '@apollo/client'; import BigNumber from 'bignumber.js'; -import { useMemo } from 'react'; +import { useEffect, useMemo, useState } from 'react'; import { - AllPoolsListCountQuery, AllPoolsListQuery, ALL_POOLS_LIST, ALL_POOLS_LIST_COUNT, PoolListItem, PoolsListCountVar, PoolsListVar, UserPoolsListCountQuery, UserPoolsListQuery, USER_POOLS_LIST, USER_POOLS_LIST_COUNT, + AllPoolsListCountQuery, AllPoolsListQuery, ALL_POOLS_LIST, ALL_POOLS_LIST_COUNT, PoolListItem, PoolsListVar, UserPoolsListCountQuery, UserPoolsListQuery, USER_POOLS_LIST, USER_POOLS_LIST_COUNT, } from '../graphql/pools'; import { TokenPrices } from '../state'; import { getIconUrl } from '../utils'; +import { AxiosInstance } from 'axios'; +import { graphqlRequest } from '../graphql/utils'; interface PoolItem { address: string; @@ -25,7 +26,7 @@ interface PoolItem { interface UsePoolsList extends PoolsListVar { tokenPrices: TokenPrices; - dexClient: ApolloClient; + httpClient: AxiosInstance; queryType: 'All' | 'User'; } @@ -96,26 +97,63 @@ const calculateUserLiquidity = ( return res.gt(0) ? res.toFormat(2) : undefined; }; +const getUserPoolList = (queryType:any,limit:any, offset:any, search:any, signerAddress:any,) => ({ + query: queryType === 'User' ? USER_POOLS_LIST : ALL_POOLS_LIST, + variables: { + limit, offset, search, signerAddress, + }, +}); + +const getUserPoolCountQry = (queryType:any,search:any, signerAddress:any,) => ({ + query: queryType === 'User' ? USER_POOLS_LIST_COUNT : ALL_POOLS_LIST_COUNT, + variables: { search, signerAddress }, +}); + export const usePoolsList = ({ - limit, offset, search, signerAddress, tokenPrices, queryType, dexClient, + limit, offset, search, signerAddress, tokenPrices, queryType, httpClient, }: UsePoolsList): [PoolItem[], boolean, number] => { - const { data: dataPoolsList, loading: loadingPoolsList } = useQuery( - queryType === 'User' ? USER_POOLS_LIST : ALL_POOLS_LIST, - { - client: dexClient, - variables: { - limit, offset, search, signerAddress, - }, - }, - ); + const [dataPoolsList, setdataPoolsList] = useState(); + const [dataPoolsCount, setDataPoolsCount] = useState(); + const [loadingPoolsList, setLoadingPoolsList] = useState(true) + const [loadingPoolsCount, setLoadingPoolsCount] = useState(true) + // const { data: dataPoolsList, loading: loadingPoolsList } = useQuery( + // queryType === 'User' ? USER_POOLS_LIST : ALL_POOLS_LIST, + // { + // client: dexClient, + // variables: { + // limit, offset, search, signerAddress, + // }, + // }, + // ); + useEffect(() => { + const handleResp = async()=>{ + const userPoolQry = getUserPoolList(queryType,limit, offset, search, signerAddress); + setLoadingPoolsList(true); + const response = await graphqlRequest(httpClient, userPoolQry); + setdataPoolsList(response.data.data); + setLoadingPoolsList(false); + } + handleResp(); + }, [limit, offset]); - const { data: dataPoolsCount, loading: loadingPoolsCount } = useQuery( - queryType === 'User' ? USER_POOLS_LIST_COUNT : ALL_POOLS_LIST_COUNT, - { - client: dexClient, - variables: { search, signerAddress }, - }, - ); + const userPoolCountQry = getUserPoolCountQry(queryType, search, signerAddress); + useEffect(() => { + const handleResp = async()=>{ + setLoadingPoolsCount(true); + const response = await graphqlRequest(httpClient, userPoolCountQry); + setDataPoolsCount(response.data.data); + setLoadingPoolsCount(false); + } + handleResp(); + }, []); + + // const { data: dataPoolsCount } = useQuery( + // queryType === 'User' ? USER_POOLS_LIST_COUNT : ALL_POOLS_LIST_COUNT, + // { + // client: dexClient, + // variables: { search, signerAddress }, + // }, + // ); const processed = useMemo((): PoolItem[] => { if (!dataPoolsList) return []; @@ -138,7 +176,6 @@ export const usePoolsList = ({ myLiquidity: calculateUserLiquidity(pool, tokenPrices), })); }, [dataPoolsList]); - return [ processed, loadingPoolsList || loadingPoolsCount, @@ -148,4 +185,4 @@ export const usePoolsList = ({ : (dataPoolsCount as AllPoolsListCountQuery).allPoolsListCount : 0, ]; -}; +}; \ No newline at end of file diff --git a/src/hooks/usePoolStats.ts b/src/hooks/usePoolStats.ts index 623ac988..9659e205 100644 --- a/src/hooks/usePoolStats.ts +++ b/src/hooks/usePoolStats.ts @@ -1,16 +1,11 @@ -import { ApolloClient, useQuery } from '@apollo/client'; import { BigNumber } from 'bignumber.js'; -import { useMemo } from 'react'; +import { useEffect, useMemo, useState } from 'react'; import { Pool24HVolume, PoolInfoQuery, - PoolInfoVar, PoolsTotalSupply, - PoolsTotalValueLockedVar, PoolTokensDataQuery, - PoolTokensVar, POOLS_TOTAL_VALUE_LOCKED, - PoolVolume24HVar, POOL_24H_VOLUME, POOL_INFO_GQL, POOL_TOKENS_DATA_GQL, @@ -18,8 +13,30 @@ import { import { getTokenPrice, TokenPrices } from '../state'; import { getIconUrl, normalize, POLL_INTERVAL } from '../utils'; import useInterval from './userInterval'; +import { AxiosInstance } from 'axios'; +import { graphqlRequest } from '../graphql/utils'; -export const useTotalSupply = (tokenPrices: TokenPrices, dexClient: ApolloClient, previous = false): string => { +const getPoolTotalValueLockedQry = (toTime: any) => ({ + query: POOLS_TOTAL_VALUE_LOCKED, + variables: { toTime }, +}); +const getPool24HvolQry = (fromTime: any) => ({ + query: POOL_24H_VOLUME, + variables: { fromTime }, +}); +const getPoolTokensDataQry = (address: string) => ({ + query: POOL_TOKENS_DATA_GQL, + variables: { address }, +}); +const getPoolInfoQry = (address:string, signerAddress:string, fromTime:string, toTime:string) => ({ + query: POOL_INFO_GQL, + variables: { + address, signerAddress, fromTime, toTime, + }, +}); + +export const useTotalSupply = (tokenPrices: TokenPrices, httpClient:AxiosInstance, previous = false): string => { + const [data, setData] = useState() const toTime = useMemo(() => { const tm = new Date(); if (previous) { @@ -27,38 +44,61 @@ export const useTotalSupply = (tokenPrices: TokenPrices, dexClient: ApolloClient } return tm; }, []); - const { data } = useQuery( - POOLS_TOTAL_VALUE_LOCKED, - { - client: dexClient, - variables: { toTime: toTime.toISOString() }, - }, - ); + + useEffect(() => { + const handleRes = async ()=>{ + const res = await graphqlRequest(httpClient,getPoolTotalValueLockedQry(toTime.toISOString())); + setData(res.data.data); + } + handleRes(); + }, []) + + // const { data } = useQuery( + // POOLS_TOTAL_VALUE_LOCKED, + // { + // client: dexClient, + // variables: { toTime: toTime.toISOString() }, + // }, + // ); if (!data || data.totalSupply.length === 0) { return '0'; } - return data.totalSupply.reduce((acc, { reserved1, reserved2, pool: { token1, token2 } }) => { - const tokenPrice1 = getTokenPrice(token1, tokenPrices); - const tokenPrice2 = getTokenPrice(token2, tokenPrices); - const r1 = tokenPrice1.multipliedBy(new BigNumber(reserved1).div(new BigNumber(10).pow(18))); - const r2 = tokenPrice2.multipliedBy(new BigNumber(reserved2).div(new BigNumber(10).pow(18))); - return acc.plus(r1).plus(r2); - }, new BigNumber(0)).toString(); -}; + const totalSupply = data.totalSupply.reduce((acc, { reserved1, reserved2, pool: { token1, token2 } }) => { + const tokenPrice1 = getTokenPrice(token1, tokenPrices); + const tokenPrice2 = getTokenPrice(token2, tokenPrices); + const r1 = tokenPrice1.multipliedBy(new BigNumber(reserved1).div(new BigNumber(10).pow(18))); + const r2 = tokenPrice2.multipliedBy(new BigNumber(reserved2).div(new BigNumber(10).pow(18))); + return acc.plus(r1).plus(r2); + }, new BigNumber(0)); + + return totalSupply.toString(); + }; + +export const usePoolVolume = (tokenPrices: TokenPrices, httpClient:AxiosInstance): string => { + const [data, setData] = useState() -export const usePoolVolume = (tokenPrices: TokenPrices, dexClient: ApolloClient): string => { const fromTime = useMemo( () => new Date(Date.now() - 24 * 60 * 60 * 1000).toISOString(), [], ); - const { data } = useQuery( - POOL_24H_VOLUME, - { - client: dexClient, - variables: { fromTime }, - }, - ); + + useEffect(() => { + const handleRes = async ()=>{ + const res = await graphqlRequest(httpClient,getPool24HvolQry(fromTime)); + setData(res.data.data); + } + handleRes(); + }, []) + + + // const { data } = useQuery( + // POOL_24H_VOLUME, + // { + // client: dexClient, + // variables: { fromTime }, + // }, + // ); if (!data || data.volume.length === 0) { return '0'; } @@ -100,7 +140,11 @@ export interface PoolStats { volumeChange24h: number; } -export const usePoolInfo = (address: string, signerAddress: string, tokenPrices: TokenPrices, dexClient: ApolloClient): [PoolStats|undefined, boolean] => { +export const usePoolInfo = (address: string, signerAddress: string, tokenPrices: TokenPrices, httpClient: AxiosInstance): [PoolStats|undefined, boolean] => { + const [tokensData, setTokensData] = useState() + const [poolInfoData, setPoolInfoData] = useState() + const [tokensLoading, setTokensLoading] = useState(true); + const [poolInfoLoading, setPoolInfoLoading] = useState(true); const toTime = useMemo(() => { const date = new Date(); date.setDate(date.getDate() - 1); @@ -113,20 +157,33 @@ export const usePoolInfo = (address: string, signerAddress: string, tokenPrices: return date.toISOString(); }, [address, signerAddress]); - const { data: tokensData, loading: tokensLoading } = useQuery(POOL_TOKENS_DATA_GQL, { - client: dexClient, - variables: { address }, - }); + // const { data: tokensData, loading: tokensLoading } = useQuery(POOL_TOKENS_DATA_GQL, { + // client: dexClient, + // variables: { address }, + // }); + useEffect(() => { + const handleRes = async ()=>{ + setTokensLoading(true); + const res = await graphqlRequest(httpClient,getPoolTokensDataQry(address)); + setTokensData(res.data.data); + setTokensLoading(false); + } + handleRes(); + }, []) - const { data: poolInfoData, loading: poolInfoLoading, refetch: refetchPoolInfo } = useQuery(POOL_INFO_GQL, { - client: dexClient, - variables: { - address, signerAddress, fromTime, toTime, - }, - }); + // const { data: poolInfoData, loading: poolInfoLoading, refetch: refetchPoolInfo } = useQuery(POOL_INFO_GQL, { + // client: dexClient, + // variables: { + // address, signerAddress, fromTime, toTime, + // }, + // }); - useInterval(() => { - refetchPoolInfo(); + const queryObj = getPoolInfoQry( address, signerAddress, fromTime, toTime); + useInterval(async() => { + setPoolInfoLoading(true); + const response = await graphqlRequest(httpClient, queryObj); + setPoolInfoData(response.data.data); + setPoolInfoLoading(false); }, POLL_INTERVAL); const info = useMemo(() => { @@ -221,4 +278,4 @@ export const usePoolInfo = (address: string, signerAddress: string, tokenPrices: }, [poolInfoData, tokensData, tokenPrices]); return [info, tokensLoading || poolInfoLoading]; -}; +}; \ No newline at end of file diff --git a/src/hooks/usePriceEstimator.ts b/src/hooks/usePriceEstimator.ts index e73ed8a0..bc768e55 100644 --- a/src/hooks/usePriceEstimator.ts +++ b/src/hooks/usePriceEstimator.ts @@ -99,4 +99,4 @@ export const estimatePrice = ( // } return extractTokenPrices(poolTokens, priceVector, tokenPosition); -}; +}; \ No newline at end of file diff --git a/src/hooks/useReefPriceInterval.ts b/src/hooks/useReefPriceInterval.ts deleted file mode 100644 index 57ee4e03..00000000 --- a/src/hooks/useReefPriceInterval.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { useEffect, useState } from 'react'; -import { DataProgress, DataWithProgress } from '../utils/dataWithProgress'; -import { reefPrice$ } from '../appState/tokenState'; - -export const useReefPriceInterval = ( -): DataWithProgress => { - const [reefPrice, setReefPrice] = useState>( - DataProgress.LOADING, - ); - useEffect(() => { - const subs = reefPrice$.subscribe((price) => setReefPrice(price)); - return () => { - subs.unsubscribe(); - }; - }, []); - return reefPrice; -}; diff --git a/src/hooks/useRemoveLiquidity.tsx b/src/hooks/useRemoveLiquidity.tsx index 81c0ce83..53bb8ffe 100644 --- a/src/hooks/useRemoveLiquidity.tsx +++ b/src/hooks/useRemoveLiquidity.tsx @@ -2,7 +2,6 @@ import Uik from '@reef-chain/ui-kit'; import BN from 'bignumber.js'; import { BigNumber, Contract } from 'ethers'; import React, { Dispatch, useEffect } from 'react'; -import { ApolloClient } from '@apollo/client'; import { ReefswapPair } from '../assets/abi/ReefswapPair'; import { getReefswapRouter } from '../rpc'; import { @@ -17,6 +16,7 @@ import { } from '../utils'; import { useKeepTokenUpdated } from './useKeepTokenUpdated'; import { useLoadPool } from './useLoadPool'; +import { AxiosInstance } from 'axios'; interface OnRemoveLiquidity { network?: Network; @@ -34,7 +34,7 @@ interface UseRemoveLiquidity { address2: string; tokens: Token[]; tokenPrices: AddressToNumber; - dexClient?: ApolloClient; + httpClient:AxiosInstance; signer?: ReefSigner; batchTxs?: boolean; state: RemoveLiquidityState; @@ -63,7 +63,7 @@ export const useRemoveLiquidity = ({ address2, state, signer, - dexClient, + httpClient, tokens, tokenPrices, dispatch, @@ -80,7 +80,7 @@ export const useRemoveLiquidity = ({ token1, token2, signer?.address || '', - dexClient, + httpClient, isLoading, ); // Updating pool @@ -304,4 +304,4 @@ export const onRemoveLiquidity = ({ dispatch(setLoadingAction(false)); dispatch(setPercentageAction(0)); } -}; +}; \ No newline at end of file diff --git a/src/hooks/useSwapState.ts b/src/hooks/useSwapState.ts index f7cd1a8f..c6ebe9a6 100644 --- a/src/hooks/useSwapState.ts +++ b/src/hooks/useSwapState.ts @@ -1,7 +1,6 @@ import Uik from '@reef-chain/ui-kit'; import { BigNumber, Contract } from 'ethers'; import { Dispatch, useEffect, useRef } from 'react'; -import { ApolloClient } from '@apollo/client'; import { ERC20 } from '../assets/abi/ERC20'; import { getReefswapRouter } from '../rpc'; import { @@ -31,6 +30,7 @@ import { } from '../utils'; import { findToken } from './useKeepTokenUpdated'; import { useLoadPool } from './useLoadPool'; +import { AxiosInstance } from 'axios'; const swapStatus = ( sell: TokenWithAmount, @@ -85,7 +85,7 @@ interface UseSwapState { state: SwapState; tokens: Token[]; account?: ReefSigner; - dexClient?: ApolloClient; + httpClient?:AxiosInstance; tokenPrices: AddressToNumber; dispatch: Dispatch; waitForPool?: boolean; @@ -95,7 +95,7 @@ export const useSwapState = ({ state, tokens, account, - dexClient, + httpClient, address1, address2, tokenPrices, @@ -126,7 +126,7 @@ export const useSwapState = ({ sell, buy, account?.evmAddress || '', - dexClient, + httpClient, isLoading, ); } @@ -387,4 +387,4 @@ export const onSwap = ({ dispatch(setLoadingAction(false)); dispatch(clearTokenAmountsAction()); } -}; +}; \ No newline at end of file diff --git a/src/hooks/useUpdateAccountBalance.ts b/src/hooks/useUpdateAccountBalance.ts index 4ba4ce1a..c2dcd229 100644 --- a/src/hooks/useUpdateAccountBalance.ts +++ b/src/hooks/useUpdateAccountBalance.ts @@ -26,4 +26,4 @@ export const useUpdateAccountBalance = ( }, [provider, address]); return balance; -}; +}; \ No newline at end of file diff --git a/src/hooks/useUpdateAmount.ts b/src/hooks/useUpdateAmount.ts index 50392b1d..f062fa12 100644 --- a/src/hooks/useUpdateAmount.ts +++ b/src/hooks/useUpdateAmount.ts @@ -62,4 +62,4 @@ export const useUpdateLiquidityAmount = ({ setPrevAddress1(token1.address); setPrevAddress2(token2.address); }, [token1.price, token2.price]); -}; +}; \ No newline at end of file diff --git a/src/utils/transactionUtil.ts b/src/utils/transactionUtil.ts index 83b1b617..6977f5af 100644 --- a/src/utils/transactionUtil.ts +++ b/src/utils/transactionUtil.ts @@ -117,8 +117,9 @@ export const getExtrinsicUrl = (extrinsic: {id:string}, network: Network = avail const [blockHeight, extrinsicIndex] = extrinsic.id.split('-'); return `${network.reefscanUrl}/extrinsic/${blockHeight}/${extrinsicIndex}`; }; -export const getTransferUrl = (extrinsic: {id:string}, network: Network = availableNetworks.mainnet): string => { +export const getTransferUrl = (extrinsic: {id:string},event:{index:string}, network: Network = availableNetworks.mainnet): string => { const [blockHeight, extrinsicIndex] = extrinsic.id.split('-'); - return `${network.reefscanUrl}/transfer/${blockHeight}/${extrinsicIndex}`; + return `${network.reefscanUrl}/transfer/${blockHeight}/${extrinsicIndex}/${event.index}`; }; + export const getContractUrl = (address: string, network: Network = availableNetworks.mainnet): string => `${network.reefscanUrl}/contract/${address}`; diff --git a/yarn.lock b/yarn.lock index 826e9feb..ee0aa072 100644 --- a/yarn.lock +++ b/yarn.lock @@ -29,7 +29,7 @@ jsonpointer "^5.0.0" leven "^3.1.0" -"@apollo/client@^3.6.2", "@apollo/client@^3.6.9": +"@apollo/client@^3.6.9": version "3.8.6" resolved "https://registry.yarnpkg.com/@apollo/client/-/client-3.8.6.tgz#d90f2a9b0147d8fc96c7a867588b5b2165cc4085" integrity sha512-FnHg3vhQP8tQzgBs6oTJCFFIbovelDGYujj6MK7CJneiHf62TJstCIO0Ot4A1h7XrgFEtgl8a/OgajQWqrTuYw== @@ -4046,9 +4046,9 @@ integrity sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw== "@types/express-serve-static-core@*", "@types/express-serve-static-core@^4.17.33": - version "4.17.38" - resolved "https://registry.yarnpkg.com/@types/express-serve-static-core/-/express-serve-static-core-4.17.38.tgz#d9c1d3a134a1226d84ec8e40c182f960f969d5a4" - integrity sha512-hXOtc0tuDHZPFwwhuBJXPbjemWtXnJjbvuuyNH2Y5Z6in+iXc63c4eXYDc7GGGqHy+iwYqAJMdaItqdnbcBKmg== + version "4.17.39" + resolved "https://registry.yarnpkg.com/@types/express-serve-static-core/-/express-serve-static-core-4.17.39.tgz#2107afc0a4b035e6cb00accac3bdf2d76ae408c8" + integrity sha512-BiEUfAiGCOllomsRAZOiMFP7LAnrifHpt56pc4Z7l9K6ACyN06Ns1JLMBxwkfLOjJRlSf06NwWsT7yzfpaVpyQ== dependencies: "@types/node" "*" "@types/qs" "*" @@ -6030,13 +6030,14 @@ cacheable-request@^6.0.0: normalize-url "^4.1.0" responselike "^1.0.2" -call-bind@^1.0.0, call-bind@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.2.tgz#b1d4e89e688119c3c9a903ad30abb2f6a919be3c" - integrity sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA== +call-bind@^1.0.0, call-bind@^1.0.2, call-bind@^1.0.4: + version "1.0.5" + resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.5.tgz#6fa2b7845ce0ea49bf4d8b9ef64727a2c2e2e513" + integrity sha512-C3nQxfFZxFRVoJoGKKI8y3MOEo129NQ+FgQ08iye+Mk4zNZZGdjfs06bVTr+DBSlA66Q2VEcMki/cUCP4SercQ== dependencies: - function-bind "^1.1.1" - get-intrinsic "^1.0.2" + function-bind "^1.1.2" + get-intrinsic "^1.2.1" + set-function-length "^1.1.1" callsites@^3.0.0: version "3.1.0" @@ -6584,21 +6585,21 @@ copy-to-clipboard@^3.3.1: toggle-selection "^1.0.6" core-js-compat@^3.31.0, core-js-compat@^3.32.2: - version "3.33.0" - resolved "https://registry.yarnpkg.com/core-js-compat/-/core-js-compat-3.33.0.tgz#24aa230b228406450b2277b7c8bfebae932df966" - integrity sha512-0w4LcLXsVEuNkIqwjjf9rjCoPhK8uqA4tMRh4Ge26vfLtUutshn+aRJU21I9LCJlh2QQHfisNToLjw1XEJLTWw== + version "3.33.1" + resolved "https://registry.yarnpkg.com/core-js-compat/-/core-js-compat-3.33.1.tgz#debe80464107d75419e00c2ee29f35982118ff84" + integrity sha512-6pYKNOgD/j/bkC5xS5IIg6bncid3rfrI42oBH1SQJbsmYPKF7rhzcFzYCcxYMmNQQ0rCEB8WqpW7QHndOggaeQ== dependencies: browserslist "^4.22.1" core-js-pure@^3.23.3, core-js-pure@^3.30.2: - version "3.33.0" - resolved "https://registry.yarnpkg.com/core-js-pure/-/core-js-pure-3.33.0.tgz#938a28754b4d82017a7a8cbd2727b1abecc63591" - integrity sha512-FKSIDtJnds/YFIEaZ4HszRX7hkxGpNKM7FC9aJ9WLJbSd3lD4vOltFuVIBLR8asSx9frkTSqL0dw90SKQxgKrg== + version "3.33.1" + resolved "https://registry.yarnpkg.com/core-js-pure/-/core-js-pure-3.33.1.tgz#7f27dd239da8eb97dbea30120071be8e5565cb0e" + integrity sha512-wCXGbLjnsP10PlK/thHSQlOLlLKNEkaWbTzVvHHZ79fZNeN1gUmw2gBlpItxPv/pvqldevEXFh/d5stdNvl6EQ== core-js@^3.19.2: - version "3.33.0" - resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.33.0.tgz#70366dbf737134761edb017990cf5ce6c6369c40" - integrity sha512-HoZr92+ZjFEKar5HS6MC776gYslNOKHt75mEBKWKnPeFDpZ6nH5OeF3S6HFT1mUAUZKrzkez05VboaX8myjSuw== + version "3.33.1" + resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.33.1.tgz#ef3766cfa382482d0a2c2bc5cb52c6d88805da52" + integrity sha512-qVSq3s+d4+GsqN0teRCJtM6tdEEXyWxjzbhVrCHmBS5ZTM0FS2MOS0D13dUXAWDUN6a+lHI/N1hF9Ytz6iLl9Q== core-util-is@1.0.2: version "1.0.2" @@ -7077,7 +7078,7 @@ defer-to-connect@^1.0.1: resolved "https://registry.yarnpkg.com/defer-to-connect/-/defer-to-connect-1.1.3.tgz#331ae050c08dcf789f8c83a7b81f0ed94f4ac591" integrity sha512-0ISdNousHvZT2EiFlZeZAHBUvSxmKswVCEf8hW7KWgG4a8MVEu/3Vb6uWYozkjylyCxe0JBIiRB1jV45S70WVQ== -define-data-property@^1.0.1: +define-data-property@^1.0.1, define-data-property@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/define-data-property/-/define-data-property-1.1.1.tgz#c35f7cd0ab09883480d12ac5cb213715587800b3" integrity sha512-E7uGkTzkk1d0ByLeSc6ZsFS79Axg+m1P/VsgYsxHgiuc3tFSj+MjMIwe90FC4lOAZzNBdY7kkO2P2wKdsQ1vgQ== @@ -7497,9 +7498,9 @@ ejs@^3.1.6: jake "^10.8.5" electron-to-chromium@^1.4.535: - version "1.4.559" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.559.tgz#050483c22c5eb2345017a8976a67b060559a33f4" - integrity sha512-iS7KhLYCSJbdo3rUSkhDTVuFNCV34RKs2UaB9Ecr7VlqzjjWW//0nfsFF5dtDmyXlZQaDYYtID5fjtC/6lpRug== + version "1.4.561" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.561.tgz#816f31d9ae01fe58abbf469fca7e125b16befd85" + integrity sha512-eS5t4ulWOBfVHdq9SW2dxEaFarj1lPjvJ8PaYMOjY0DecBaj/t4ARziL2IPpDr4atyWwjLFGQ2vo/VCgQFezVQ== elliptic@6.5.4, elliptic@^6.4.0, elliptic@^6.4.1, elliptic@^6.5.3, elliptic@^6.5.4: version "6.5.4" @@ -8951,7 +8952,7 @@ fsevents@^2.1.2, fsevents@^2.3.2, fsevents@~2.3.2: resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.3.tgz#cac6407785d03675a2a5e1a5305c697b347d90d6" integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw== -function-bind@^1.1.1: +function-bind@^1.1.1, function-bind@^1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.2.tgz#2c02d864d97f3ea6c8830c464cbd11ab6eab7a1c" integrity sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA== @@ -12392,13 +12393,12 @@ no-case@^3.0.4: tslib "^2.0.3" nock@^13.3.0: - version "13.3.4" - resolved "https://registry.yarnpkg.com/nock/-/nock-13.3.4.tgz#4ed3ed1465a75c87833044a881dbdd6546337e8d" - integrity sha512-DDpmn5oLEdCTclEqweOT4U7bEpuoifBMFUXem9sA4turDAZ5tlbrEoWqCorwXey8CaAw44mst5JOQeVNiwtkhw== + version "13.3.6" + resolved "https://registry.yarnpkg.com/nock/-/nock-13.3.6.tgz#b279968ec8d076c2393810a6c9bf2d4d5b3a1071" + integrity sha512-lT6YuktKroUFM+27mubf2uqQZVy2Jf+pfGzuh9N6VwdHlFoZqvi4zyxFTVR1w/ChPqGY6yxGehHp6C3wqCASCw== dependencies: debug "^4.1.0" json-stringify-safe "^5.0.1" - lodash "^4.17.21" propagate "^2.0.0" node-abi@^3.3.0: @@ -12634,9 +12634,9 @@ object-hash@^3.0.0: integrity sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw== object-inspect@^1.12.3, object-inspect@^1.9.0: - version "1.13.0" - resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.13.0.tgz#42695d3879e1cd5bda6df5062164d80c996e23e2" - integrity sha512-HQ4J+ic8hKrgIt3mqk6cVOVrW2ozL4KdvHlqpBv9vDYWx9ysAgENAdvy4FoGF+KFdhR7nQTNm5J0ctAeOwn+3g== + version "1.13.1" + resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.13.1.tgz#b96c6109324ccfef6b12216a956ca4dc2ff94bc2" + integrity sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ== object-keys@^1.1.1: version "1.1.1" @@ -15119,6 +15119,16 @@ set-blocking@^2.0.0: resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" integrity sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw== +set-function-length@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/set-function-length/-/set-function-length-1.1.1.tgz#4bc39fafb0307224a33e106a7d35ca1218d659ed" + integrity sha512-VoaqjbBJKiWtg4yRcKBQ7g7wnGnLV3M8oLvVWwOk2PdYY6PEFegR1vezXR0tw6fZGF9csVakIRjrJiy2veSBFQ== + dependencies: + define-data-property "^1.1.1" + get-intrinsic "^1.2.1" + gopd "^1.0.1" + has-property-descriptors "^1.0.0" + set-function-name@^2.0.0, set-function-name@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/set-function-name/-/set-function-name-2.0.1.tgz#12ce38b7954310b9f61faa12701620a0c882793a" @@ -15470,9 +15480,9 @@ sprintf-js@~1.0.2: integrity sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g== sshpk@^1.7.0: - version "1.17.0" - resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.17.0.tgz#578082d92d4fe612b13007496e543fa0fbcbe4c5" - integrity sha512-/9HIEs1ZXGhSPE8X6Ccm7Nam1z8KcoCqPdI7ecm1N33EzAetWahvQWVqLZtaZQ+IDKX4IyA2o0gBzqIMkAagHQ== + version "1.18.0" + resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.18.0.tgz#1663e55cddf4d688b86a46b77f0d5fe363aba028" + integrity sha512-2p2KJZTSqQ/I3+HX42EpYOa2l3f8Erv8MWKsy2I9uf4wA7yFIkXRffYdsx86y6z4vHtV8u7g+pPlr8/4ouAxsQ== dependencies: asn1 "~0.2.3" assert-plus "^1.0.0" @@ -17016,12 +17026,12 @@ which-module@^2.0.0: integrity sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ== which-typed-array@^1.1.11, which-typed-array@^1.1.9: - version "1.1.11" - resolved "https://registry.yarnpkg.com/which-typed-array/-/which-typed-array-1.1.11.tgz#99d691f23c72aab6768680805a271b69761ed61a" - integrity sha512-qe9UWWpkeG5yzZ0tNYxDmd7vo58HDBc39mZ0xWWpolAGADdFOzkfamWLDxkOWcvHQKVmdTyQdLD4NOfjLWTKew== + version "1.1.13" + resolved "https://registry.yarnpkg.com/which-typed-array/-/which-typed-array-1.1.13.tgz#870cd5be06ddb616f504e7b039c4c24898184d36" + integrity sha512-P5Nra0qjSncduVPEAr7xhoF5guty49ArDTwzJ/yNuPIbZppyRxFQsRCWrocxIY+CnMVG+qfbU2FmDKyvSGClow== dependencies: available-typed-arrays "^1.0.5" - call-bind "^1.0.2" + call-bind "^1.0.4" for-each "^0.3.3" gopd "^1.0.1" has-tostringtag "^1.0.0"