diff --git a/cypress/e2e/pages/limit-order.po.cy.ts b/cypress/e2e/pages/limit-order.po.cy.ts index 6b75549119..9f69cdadc2 100644 --- a/cypress/e2e/pages/limit-order.po.cy.ts +++ b/cypress/e2e/pages/limit-order.po.cy.ts @@ -21,4 +21,14 @@ export const LimitOder = { getCurrentTokenBuy(text: myCallbackType) { cy.getContent(LimitOrderLocators.dropdownTokenBuy, text) }, + + setSellingRate(text: string) { + cy.get(LimitOrderLocators.txtSellingRate).click().type(text) + }, + + getSellingRate() { + return cy.get(LimitOrderLocators.txtSellingRate).invoke('val').then(value => { + return value + }) + } } diff --git a/cypress/e2e/selectors/constants.cy.ts b/cypress/e2e/selectors/constants.cy.ts index 4376474012..f015f87d6c 100644 --- a/cypress/e2e/selectors/constants.cy.ts +++ b/cypress/e2e/selectors/constants.cy.ts @@ -12,11 +12,11 @@ export enum TAG { } export const TOKEN_SYMBOLS = { - 'Ethereum': ['BAND', 'DAI', 'USDT', 'USDC'], - 'Arbitrum': ['ANGLE', 'DAI', 'USDT', 'USDC.e'], - 'Optimism': ['BOB', 'DAI', 'USDT', 'USDC'], - 'Avalanche': ['AAVE.e', 'sAVAX', 'USDT.e', 'USDC.e'], - 'BNB': ['RICE', 'DAI', 'USDT', 'USDC'] + 'Ethereum': ['BAND', 'DAI', 'USDT', 'USDC', '1INCH'], + 'Arbitrum': ['ANGLE', 'DAI', 'USDT', 'USDC.e', 'MAI'], + 'Optimism': ['BOB', 'DAI', 'USDT', 'USDC', 'MAI'], + 'Avalanche': ['AAVE.e', 'sAVAX', 'USDT.e', 'USDC.e', 'MAI'], + 'BNB': ['RICE', 'DAI', 'USDT', 'USDC', 'MAI'] } export const UNWHITELIST_TOKENS = { diff --git a/cypress/e2e/selectors/selectors.cy.ts b/cypress/e2e/selectors/selectors.cy.ts index 4451a4168f..1d10220820 100644 --- a/cypress/e2e/selectors/selectors.cy.ts +++ b/cypress/e2e/selectors/selectors.cy.ts @@ -24,7 +24,8 @@ export const SwapPageLocators = { export const LimitOrderLocators = { dropdownTokenSell: '[data-testid=limit-order-input-tokena] [data-testid=token-symbol-container]', dropdownTokenBuy: '[data-testid=limit-order-input-tokenb] [data-testid=token-symbol-container]', - btnLimit: '[data-testid=limit-button]' + btnLimit: '[data-testid=limit-button]', + txtSellingRate: '[data-testid=input-selling-rate]' } export const WalletLocators = { diff --git a/cypress/e2e/specs/connect-wallet.e2e.cy.ts b/cypress/e2e/specs/connect-wallet.e2e.cy.ts index 34f9afabbb..3de9e0e8da 100644 --- a/cypress/e2e/specs/connect-wallet.e2e.cy.ts +++ b/cypress/e2e/specs/connect-wallet.e2e.cy.ts @@ -11,13 +11,13 @@ describe('Metamask Extension tests', { tags: TAG.regression }, () => { SwapPage.connectWallet() }) - it('Redirects to swap page when a user has already connected a wallet', () => { + it.skip('Redirects to swap page when a user has already connected a wallet', () => { cy.acceptMetamaskAccess() SwapPage.getStatusConnectedWallet() cy.url().should('include', '/swap') }) - it('Should approve permission to switch network', () => { + it.skip('Should approve permission to switch network', () => { if (NETWORK !== DEFAULT_NETWORK) { SwapPage.getStatusConnectedWallet() wallet.selectNetwork(NETWORK) diff --git a/cypress/e2e/specs/limit-order.e2e.cy.ts b/cypress/e2e/specs/limit-order.e2e.cy.ts index d77682cd85..4f069997a8 100644 --- a/cypress/e2e/specs/limit-order.e2e.cy.ts +++ b/cypress/e2e/specs/limit-order.e2e.cy.ts @@ -2,12 +2,8 @@ import { LimitOder } from "../pages/limit-order.po.cy" import { SwapPage, TokenCatalog } from "../pages/swap-page.po.cy" import { DEFAULT_URL, NETWORK, NORESULTS_TEXT, NOTOKENS_TEXT, TAG, TOKEN_SYMBOLS, UNWHITELIST_SYMBOL_TOKENS, UNWHITELIST_TOKENS } from "../selectors/constants.cy" -const unWhitelistTokens = UNWHITELIST_TOKENS[NETWORK] const tokenSymbols = TOKEN_SYMBOLS[NETWORK] -const arrAddress = [unWhitelistTokens[0].address, unWhitelistTokens[1].address, unWhitelistTokens[2].address] -const arrSymbol = [unWhitelistTokens[0].symbol, unWhitelistTokens[1].symbol, unWhitelistTokens[2].symbol] - const tokenCatalog = new TokenCatalog(); @@ -20,14 +16,14 @@ describe(`Token Catalog on ${NETWORK}`, { tags: TAG.regression }, () => { describe('Add/remove/select token with favorite tokens list', () => { it('Should be added, selected and removed favorite token sell', () => { - LimitOder.selectTokenSell().addFavoriteToken([tokenSymbols[0], tokenSymbols[1]]) + LimitOder.selectTokenSell().addFavoriteToken([tokenSymbols[0], tokenSymbols[4]]) tokenCatalog.getFavoriteTokens((list) => { - expect(list).to.include.members([tokenSymbols[1]]) + expect(list).to.include.members([tokenSymbols[4]]) }) - tokenCatalog.selectFavoriteToken(tokenSymbols[1]) + tokenCatalog.selectFavoriteToken(tokenSymbols[4]) LimitOder.getCurrentTokenSell((text) => { - expect(text).to.equal(tokenSymbols[1]) + expect(text).to.equal(tokenSymbols[4]) }) LimitOder.selectTokenSell() tokenCatalog.removeFavoriteToken(tokenSymbols[0]) @@ -37,14 +33,14 @@ describe(`Token Catalog on ${NETWORK}`, { tags: TAG.regression }, () => { }) it('Should be added, selected and removed favorite token buy', () => { - LimitOder.selectTokenBuy().addFavoriteToken([tokenSymbols[0], tokenSymbols[1]]) + LimitOder.selectTokenBuy().addFavoriteToken([tokenSymbols[0], tokenSymbols[4]]) tokenCatalog.getFavoriteTokens((list) => { - expect(list).to.include.members([tokenSymbols[1]]) + expect(list).to.include.members([tokenSymbols[4]]) }) - tokenCatalog.selectFavoriteToken(tokenSymbols[1]) + tokenCatalog.selectFavoriteToken(tokenSymbols[4]) LimitOder.getCurrentTokenBuy((text) => { - expect(text).to.equal(tokenSymbols[1]) + expect(text).to.equal(tokenSymbols[4]) }) LimitOder.selectTokenBuy() tokenCatalog.removeFavoriteToken(tokenSymbols[0]) @@ -69,18 +65,27 @@ describe(`Token Catalog on ${NETWORK}`, { tags: TAG.regression }, () => { }) }) - it('Should be unselected tokenIn not exist in whitelist', () => { + it('Should be unselected token sell not exist in whitelist', () => { LimitOder.selectTokenSell().searchToken(UNWHITELIST_SYMBOL_TOKENS[0]) tokenCatalog.getNoResultsFound((text) => { expect(text).to.equal(NORESULTS_TEXT) }) }) - it('Should be unselected tokenOut not exist in whitelist', () => { + it('Should be unselected token buy not exist in whitelist', () => { LimitOder.selectTokenBuy().searchToken(UNWHITELIST_SYMBOL_TOKENS[0]) tokenCatalog.getNoResultsFound((text) => { expect(text).to.equal(NORESULTS_TEXT) }) }) }) + + describe('Sell rate', () => { + it('Able to set selling rate by number', () => { + LimitOder.setSellingRate('1.2345..67') + LimitOder.getSellingRate().then((value) => { + cy.wrap(value).should('eq', '1.234567') + }) + }) + }) }) \ No newline at end of file diff --git a/package.json b/package.json index be9d66f6ab..285bf6399e 100644 --- a/package.json +++ b/package.json @@ -49,7 +49,7 @@ "@kybernetwork/oauth2": "1.0.0", "@kyberswap/krystal-walletconnect-v2": "0.0.1", "@kyberswap/ks-sdk-classic": "^1.0.3", - "@kyberswap/ks-sdk-core": "1.0.11", + "@kyberswap/ks-sdk-core": "1.0.13", "@kyberswap/ks-sdk-elastic": "^1.1.2", "@kyberswap/ks-sdk-solana": "^1.0.2", "@lingui/loader": "~3.14.0", @@ -200,7 +200,7 @@ "vite-tsconfig-paths": "^4.0.8" }, "resolutions": { - "@kyberswap/ks-sdk-core": "1.0.11", + "@kyberswap/ks-sdk-core": "1.0.13", "babel-plugin-lodash/@babel/types": "~7.20.0", "react-error-overlay": "6.0.9", "@lingui/babel-plugin-extract-messages": "3.14.0", diff --git a/src/components/Announcement/PrivateAnnoucement/InboxItemKyberAIWatchList.tsx b/src/components/Announcement/PrivateAnnoucement/InboxItemKyberAIWatchList.tsx index c1e091c5f6..19f2a3f02a 100644 --- a/src/components/Announcement/PrivateAnnoucement/InboxItemKyberAIWatchList.tsx +++ b/src/components/Announcement/PrivateAnnoucement/InboxItemKyberAIWatchList.tsx @@ -19,7 +19,7 @@ const ItemWrapper = styled.div` gap: 8px; ` export const TokenInfo = ({ - showPrice = true, + showPrice = false, logoSize = '12px', token, }: { @@ -73,7 +73,7 @@ function InboxItemBridge({ } return ( - + diff --git a/src/components/Announcement/PrivateAnnoucement/NotificationCenter/KyberAIWatchlist.tsx b/src/components/Announcement/PrivateAnnoucement/NotificationCenter/KyberAIWatchlist.tsx index c077f940ef..2bf1223fd5 100644 --- a/src/components/Announcement/PrivateAnnoucement/NotificationCenter/KyberAIWatchlist.tsx +++ b/src/components/Announcement/PrivateAnnoucement/NotificationCenter/KyberAIWatchlist.tsx @@ -53,7 +53,7 @@ export default function AnnouncementItem({ {!expand && minimalAssets.map((token, i) => ( - + {i === minimalAssets.length - 1 ? (minimalAssets.length < slice ? '' : ', ...') : ', '} ))} diff --git a/src/components/Announcement/helper.ts b/src/components/Announcement/helper.ts index 6dfcf4dfca..0ba391456d 100644 --- a/src/components/Announcement/helper.ts +++ b/src/components/Announcement/helper.ts @@ -1,10 +1,7 @@ import { ChainId } from '@kyberswap/ks-sdk-core' -import { useCallback } from 'react' -import AnnouncementApi from 'services/announcement' import { AnnouncementTemplatePopup, PopupContentAnnouncement, PopupItemType } from 'components/Announcement/type' import { TIMES_IN_SECS } from 'constants/index' -import { useAppDispatch } from 'state/hooks' const LsKey = 'ack-announcements' export const getAnnouncementsAckMap = () => JSON.parse(localStorage[LsKey] || '{}') @@ -42,20 +39,3 @@ export const isPopupCanShow = ( const isExpired = Date.now() < startAt * 1000 || Date.now() > endAt * 1000 return !isRead && !isExpired && isRightChain && isOwn } - -export const useInvalidateTags = (reducerPath: string) => { - const dispatch = useAppDispatch() - return useCallback( - (tag: string | string[]) => { - dispatch({ - type: `${reducerPath}/invalidateTags`, - payload: Array.isArray(tag) ? tag : [tag], - }) - }, - [dispatch, reducerPath], - ) -} - -export const useInvalidateTagAnnouncement = () => { - return useInvalidateTags(AnnouncementApi.reducerPath) -} diff --git a/src/components/Announcement/index.tsx b/src/components/Announcement/index.tsx index 3abf63be97..dd56ff5b27 100644 --- a/src/components/Announcement/index.tsx +++ b/src/components/Announcement/index.tsx @@ -10,13 +10,14 @@ import styled, { css } from 'styled-components' import AnnouncementView, { Tab } from 'components/Announcement/AnnoucementView' import DetailAnnouncementPopup from 'components/Announcement/Popups/DetailAnnouncementPopup' -import { formatNumberOfUnread, useInvalidateTagAnnouncement } from 'components/Announcement/helper' +import { formatNumberOfUnread } from 'components/Announcement/helper' import { Announcement, PrivateAnnouncement } from 'components/Announcement/type' import NotificationIcon from 'components/Icons/NotificationIcon' import MenuFlyout from 'components/MenuFlyout' import Modal from 'components/Modal' import { RTK_QUERY_TAGS } from 'constants/index' import useInterval from 'hooks/useInterval' +import { useInvalidateTagAnnouncement } from 'hooks/useInvalidateTags' import useMixpanel, { MIXPANEL_TYPE } from 'hooks/useMixpanel' import { ApplicationModal } from 'state/application/actions' import { useDetailAnnouncement, useModalOpen, useToggleNotificationCenter } from 'state/application/hooks' diff --git a/src/components/ClassicElasticTab.tsx b/src/components/ClassicElasticTab.tsx index e8285f4efc..ad8bed9727 100644 --- a/src/components/ClassicElasticTab.tsx +++ b/src/components/ClassicElasticTab.tsx @@ -45,7 +45,7 @@ function ClassicElasticTab() { const upToMedium = useMedia(`(max-width: ${MEDIA_WIDTHS.upToMedium}px)`) - const dontShowLegacy = [ChainId.ZKEVM, ChainId.BASE, ChainId.LINEA].includes(chainId) + const dontShowLegacy = [ChainId.ZKEVM, ChainId.BASE, ChainId.LINEA, ChainId.SCROLL].includes(chainId) const showLegacyExplicit = upToMedium || dontShowLegacy ? false : isFarmpage ? shouldShowFarmTab : shouldShowPositionTab diff --git a/src/components/Header/web3/WalletModal/index.tsx b/src/components/Header/web3/WalletModal/index.tsx index 67e7834b65..0986a50436 100644 --- a/src/components/Header/web3/WalletModal/index.tsx +++ b/src/components/Header/web3/WalletModal/index.tsx @@ -32,6 +32,7 @@ import { useWalletModalToggle, } from 'state/application/hooks' import { useIsConnectingWallet } from 'state/authen/hooks' +import { ExternalLink } from 'theme' import { isEVMWallet, isOverriddenWallet, isSolanaWallet } from 'utils' import Option from './Option' @@ -316,13 +317,13 @@ export default function WalletModal() { By connecting a wallet, you accept{' '} - e.stopPropagation()}> + e.stopPropagation()}> KyberSwap‘s Terms of Use - {' '} + {' '} and consent to its{' '} - e.stopPropagation()}> + e.stopPropagation()}> Privacy Policy - + . Last updated: {dayjs(TERM_FILES_PATH.VERSION).format('DD MMM YYYY')} diff --git a/src/components/Menu/index.tsx b/src/components/Menu/index.tsx index 87115a075a..44796e4579 100644 --- a/src/components/Menu/index.tsx +++ b/src/components/Menu/index.tsx @@ -473,7 +473,7 @@ export default function Menu() { )} - { toggle() @@ -482,10 +482,10 @@ export default function Menu() { > Terms - + - { toggle() @@ -494,7 +494,7 @@ export default function Menu() { > Privacy Policy - + { // change account sign in => refresh participant info try { refetch() - dispatch( - kyberAIapi.util.invalidateTags([ - RTK_QUERY_TAGS.GET_WATCHLIST_TOKENS_KYBER_AI, - RTK_QUERY_TAGS.GET_WATCHLIST_INFO_KYBER_AI, - ]), - ) + invalidateTags([RTK_QUERY_TAGS.GET_WATCHLIST_TOKENS_KYBER_AI, RTK_QUERY_TAGS.GET_WATCHLIST_INFO_KYBER_AI]) } catch (error) {} - }, [userInfo?.identityId, refetch, dispatch]) + }, [userInfo?.identityId, refetch, invalidateTags]) if (loading && !loadedPage.current) return if (!canAccessPage) return diff --git a/src/components/SearchModal/CurrencySearch.tsx b/src/components/SearchModal/CurrencySearch.tsx index c25bf3038e..6d8e5ea3d1 100644 --- a/src/components/SearchModal/CurrencySearch.tsx +++ b/src/components/SearchModal/CurrencySearch.tsx @@ -14,7 +14,7 @@ import Column from 'components/Column' import InfoHelper from 'components/InfoHelper' import { RowBetween } from 'components/Row' import { KS_SETTING_API } from 'constants/env' -import { isEVM, isSolana } from 'constants/networks' +import { isEVM } from 'constants/networks' import { Z_INDEXS } from 'constants/styles' import { NativeCurrencies } from 'constants/tokens' import { useActiveWeb3React } from 'hooks' @@ -156,7 +156,6 @@ export function CurrencySearch({ const [searchQuery, setSearchQuery] = useState('') const debouncedQuery = useDebounce(searchQuery, 200) const isQueryValidEVMAddress = isEVM(chainId) && !!isAddress(chainId, debouncedQuery) - const isQueryValidSolanaAddress = isSolana(chainId) && !!isAddress(chainId, debouncedQuery) const { favoriteTokens, toggleFavoriteToken } = useUserFavoriteTokens(chainId) @@ -266,6 +265,7 @@ export function CurrencySearch({ ) // menu ui + const isImportedTab = activeTab === Tab.Imported const [open, toggle] = useToggle(false) const node = useRef() useOnClickOutside(node, open ? toggle : undefined) @@ -317,8 +317,7 @@ export function CurrencySearch({ async (page?: number) => { const nextPage = (page ?? pageCount) + 1 let tokens: WrappedTokenInfo[] = [] - - if (debouncedQuery) { + if (debouncedQuery && !isImportedTab) { abortControllerRef.current.abort() abortControllerRef.current = new AbortController() tokens = await fetchTokens(debouncedQuery, nextPage, chainId, abortControllerRef.current.signal) @@ -346,11 +345,9 @@ export function CurrencySearch({ console.error('import token err', err) }) } - } else if (tokens.length === 0 && isQueryValidSolanaAddress) { - // TODO: query tokens from Solana token db } } else { - tokens = Object.values(defaultTokens) + tokens = isImportedTab ? [] : Object.values(defaultTokens) } setPageCount(nextPage) @@ -358,12 +355,12 @@ export function CurrencySearch({ setHasMoreToken(tokens.length === PAGE_SIZE && !!debouncedQuery) }, [ + isImportedTab, chainId, debouncedQuery, defaultTokens, fetchERC20TokenFromRPC, isQueryValidEVMAddress, - isQueryValidSolanaAddress, pageCount, importTokensToKsSettings, ], @@ -379,10 +376,10 @@ export function CurrencySearch({ // need call api when only debouncedQuery change }, [debouncedQuery, prevQuery, fetchListTokens]) - const isImportedTab = activeTab === Tab.Imported - const visibleCurrencies: Currency[] = useMemo(() => { - return isImportedTab ? tokenImportsFiltered : filteredSortedTokens + return isImportedTab || (!isImportedTab && !filteredSortedTokens.length) + ? tokenImportsFiltered + : filteredSortedTokens }, [isImportedTab, filteredSortedTokens, tokenImportsFiltered]) const removeToken = useRemoveUserAddedToken() diff --git a/src/components/YourCampaignTransactionsModal/index.tsx b/src/components/YourCampaignTransactionsModal/index.tsx index 52e151a255..68b3bc1962 100644 --- a/src/components/YourCampaignTransactionsModal/index.tsx +++ b/src/components/YourCampaignTransactionsModal/index.tsx @@ -5,11 +5,11 @@ import { CheckCircle, Copy, ExternalLink, Info, X } from 'react-feather' import { useSelector } from 'react-redux' import { useMedia } from 'react-use' import { Flex, Text } from 'rebass' +import { useGetTxsCampaignQuery } from 'services/campaign' import styled, { css } from 'styled-components' -import useSWR from 'swr' import Modal from 'components/Modal' -import { CAMPAIGN_YOUR_TRANSACTIONS_ITEM_PER_PAGE, SWR_KEYS } from 'constants/index' +import { CAMPAIGN_YOUR_TRANSACTIONS_ITEM_PER_PAGE } from 'constants/index' import { NETWORKS_INFO } from 'constants/networks' import { useActiveWeb3React } from 'hooks' import useCopyClipboard from 'hooks/useCopyClipboard' @@ -17,7 +17,6 @@ import useTheme from 'hooks/useTheme' import { AppState } from 'state' import { ApplicationModal } from 'state/application/actions' import { useModalOpen, useToggleYourCampaignTransactionsModal } from 'state/application/hooks' -import { CampaignProofData } from 'state/campaigns/actions' import { getEtherscanLink } from 'utils' import getShortenAddress from 'utils/getShortenAddress' @@ -32,37 +31,15 @@ export default function YourCampaignTransactionsModal() { const above768 = useMedia('(min-width: 768px)') const selectedCampaign = useSelector((state: AppState) => state.campaigns.selectedCampaign) - const { data: userCampaignTransactions } = useSWR( - account && selectedCampaign - ? SWR_KEYS.getCampaignTransactions( - selectedCampaign.id, - CAMPAIGN_YOUR_TRANSACTIONS_ITEM_PER_PAGE, - CAMPAIGN_YOUR_TRANSACTIONS_ITEM_PER_PAGE * (currentPage - 1), - account, - ) - : null, - async (url: string) => { - try { - const response = await fetch(url) - if (response.ok) { - const data = await response.json() - if (data && Array.isArray(data.data) && data.data.length) { - return data.data.map( - (item: any): CampaignProofData => ({ - id: item.id, - chainId: parseInt(item.chainId), - utcTimestamp: new Date(item.time).getTime(), - txPoint: item.txPoint, - txHash: item.tx, - }), - ) - } - } - return [] - } catch (err) { - console.error(err) - } + + const { data: userCampaignTransactions } = useGetTxsCampaignQuery( + { + campaignId: selectedCampaign?.id || 0, + limit: CAMPAIGN_YOUR_TRANSACTIONS_ITEM_PER_PAGE, + offset: CAMPAIGN_YOUR_TRANSACTIONS_ITEM_PER_PAGE * (currentPage - 1), + userAddress: account ?? '', }, + { skip: !selectedCampaign?.id }, ) const [isCopied, setCopied] = useCopyClipboard() diff --git a/src/components/swapv2/LimitOrder/LimitOrderForm.tsx b/src/components/swapv2/LimitOrder/LimitOrderForm.tsx index 3cae177bfb..35d7888231 100644 --- a/src/components/swapv2/LimitOrder/LimitOrderForm.tsx +++ b/src/components/swapv2/LimitOrder/LimitOrderForm.tsx @@ -739,6 +739,7 @@ const LimitOrderForm = forwardRef(function LimitOrd { invalidateTag(RTK_QUERY_TAGS.GET_LIST_ORDERS) }, [invalidateTag]) diff --git a/src/constants/abis/v2/farmv2.1.json b/src/constants/abis/v2/farmv2.1.json index 3cff91c838..4e492bbfe6 100644 --- a/src/constants/abis/v2/farmv2.1.json +++ b/src/constants/abis/v2/farmv2.1.json @@ -1,1474 +1,1474 @@ [ { + "type": "constructor", + "stateMutability": "nonpayable", "inputs": [ { - "internalType": "contract IERC721", + "type": "address", "name": "_nft", - "type": "address" + "internalType": "contract IERC721" }, { - "internalType": "contract IKSElasticLMHelper", + "type": "address", "name": "_helper", - "type": "address" + "internalType": "contract IKSElasticLMHelper" } - ], - "stateMutability": "nonpayable", - "type": "constructor" + ] }, { - "inputs": [], + "type": "error", "name": "EmergencyEnabled", - "type": "error" + "inputs": [] }, { - "inputs": [], + "type": "error", "name": "Expired", - "type": "error" + "inputs": [] }, { - "inputs": [], + "type": "error", "name": "FailToAdd", - "type": "error" + "inputs": [] }, { - "inputs": [], + "type": "error", "name": "FailToRemove", - "type": "error" + "inputs": [] }, { - "inputs": [], + "type": "error", "name": "FarmNotFound", - "type": "error" + "inputs": [] }, { - "inputs": [], + "type": "error", "name": "Forbidden", - "type": "error" + "inputs": [] }, { - "inputs": [], + "type": "error", "name": "InvalidFarm", - "type": "error" + "inputs": [] }, { - "inputs": [], + "type": "error", "name": "InvalidInput", - "type": "error" + "inputs": [] }, { - "inputs": [], + "type": "error", "name": "InvalidRange", - "type": "error" + "inputs": [] }, { - "inputs": [], + "type": "error", "name": "InvalidReward", - "type": "error" + "inputs": [] }, { - "inputs": [], + "type": "error", "name": "InvalidTime", - "type": "error" + "inputs": [] }, { - "inputs": [], + "type": "error", "name": "LiquidityNotMatch", - "type": "error" + "inputs": [] }, { - "inputs": [], + "type": "error", "name": "NotOwner", - "type": "error" + "inputs": [] }, { - "inputs": [], + "type": "error", "name": "PhaseSettled", - "type": "error" + "inputs": [] }, { - "inputs": [], + "type": "error", "name": "PositionNotEligible", - "type": "error" + "inputs": [] }, { - "inputs": [], + "type": "error", "name": "RangeNotFound", - "type": "error" + "inputs": [] }, { - "inputs": [], + "type": "error", "name": "RangeNotMatch", - "type": "error" + "inputs": [] }, { - "inputs": [], + "type": "error", "name": "StakeNotFound", - "type": "error" + "inputs": [] }, { - "anonymous": false, + "type": "event", + "name": "ActivateRange", "inputs": [ { - "indexed": true, - "internalType": "uint256", + "type": "uint256", "name": "fId", - "type": "uint256" + "internalType": "uint256", + "indexed": true }, { - "indexed": false, - "internalType": "uint256", + "type": "uint256", "name": "rangeId", - "type": "uint256" + "internalType": "uint256", + "indexed": false } ], - "name": "ActivateRange", - "type": "event" + "anonymous": false }, { - "anonymous": false, + "type": "event", + "name": "AddFarm", "inputs": [ { - "indexed": true, - "internalType": "uint256", + "type": "uint256", "name": "fId", - "type": "uint256" + "internalType": "uint256", + "indexed": true }, { - "indexed": false, - "internalType": "address", + "type": "address", "name": "poolAddress", - "type": "address" + "internalType": "address", + "indexed": false }, { + "type": "tuple[]", + "name": "ranges", + "internalType": "struct IKSElasticLMV2.RangeInput[]", + "indexed": false, "components": [ { - "internalType": "int24", + "type": "int24", "name": "tickLower", - "type": "int24" + "internalType": "int24" }, { - "internalType": "int24", + "type": "int24", "name": "tickUpper", - "type": "int24" + "internalType": "int24" }, { - "internalType": "uint32", + "type": "uint32", "name": "weight", - "type": "uint32" + "internalType": "uint32" } - ], - "indexed": false, - "internalType": "struct IKSElasticLMV2.RangeInput[]", - "name": "ranges", - "type": "tuple[]" + ] }, { + "type": "tuple", + "name": "phase", + "internalType": "struct IKSElasticLMV2.PhaseInput", + "indexed": false, "components": [ { - "internalType": "uint32", + "type": "uint32", "name": "startTime", - "type": "uint32" + "internalType": "uint32" }, { - "internalType": "uint32", + "type": "uint32", "name": "endTime", - "type": "uint32" + "internalType": "uint32" }, { + "type": "tuple[]", + "name": "rewards", + "internalType": "struct IKSElasticLMV2.RewardInput[]", "components": [ { - "internalType": "address", + "type": "address", "name": "rewardToken", - "type": "address" + "internalType": "address" }, { - "internalType": "uint256", + "type": "uint256", "name": "rewardAmount", - "type": "uint256" + "internalType": "uint256" } - ], - "internalType": "struct IKSElasticLMV2.RewardInput[]", - "name": "rewards", - "type": "tuple[]" + ] } - ], - "indexed": false, - "internalType": "struct IKSElasticLMV2.PhaseInput", - "name": "phase", - "type": "tuple" + ] }, { - "indexed": false, - "internalType": "address", + "type": "address", "name": "farmingToken", - "type": "address" + "internalType": "address", + "indexed": false } ], - "name": "AddFarm", - "type": "event" + "anonymous": false }, { - "anonymous": false, + "type": "event", + "name": "AddPhase", "inputs": [ { - "indexed": true, - "internalType": "uint256", + "type": "uint256", "name": "fId", - "type": "uint256" + "internalType": "uint256", + "indexed": true }, { + "type": "tuple", + "name": "phase", + "internalType": "struct IKSElasticLMV2.PhaseInput", + "indexed": false, "components": [ { - "internalType": "uint32", + "type": "uint32", "name": "startTime", - "type": "uint32" + "internalType": "uint32" }, { - "internalType": "uint32", + "type": "uint32", "name": "endTime", - "type": "uint32" + "internalType": "uint32" }, { + "type": "tuple[]", + "name": "rewards", + "internalType": "struct IKSElasticLMV2.RewardInput[]", "components": [ { - "internalType": "address", + "type": "address", "name": "rewardToken", - "type": "address" + "internalType": "address" }, { - "internalType": "uint256", + "type": "uint256", "name": "rewardAmount", - "type": "uint256" + "internalType": "uint256" } - ], - "internalType": "struct IKSElasticLMV2.RewardInput[]", - "name": "rewards", - "type": "tuple[]" + ] } - ], - "indexed": false, - "internalType": "struct IKSElasticLMV2.PhaseInput", - "name": "phase", - "type": "tuple" + ] } ], - "name": "AddPhase", - "type": "event" + "anonymous": false }, { - "anonymous": false, + "type": "event", + "name": "AddRange", "inputs": [ { - "indexed": true, - "internalType": "uint256", + "type": "uint256", "name": "fId", - "type": "uint256" + "internalType": "uint256", + "indexed": true }, { + "type": "tuple", + "name": "range", + "internalType": "struct IKSElasticLMV2.RangeInput", + "indexed": false, "components": [ { - "internalType": "int24", + "type": "int24", "name": "tickLower", - "type": "int24" + "internalType": "int24" }, { - "internalType": "int24", + "type": "int24", "name": "tickUpper", - "type": "int24" + "internalType": "int24" }, { - "internalType": "uint32", + "type": "uint32", "name": "weight", - "type": "uint32" + "internalType": "uint32" } - ], - "indexed": false, - "internalType": "struct IKSElasticLMV2.RangeInput", - "name": "range", - "type": "tuple" + ] } ], - "name": "AddRange", - "type": "event" + "anonymous": false }, { - "anonymous": false, + "type": "event", + "name": "ClaimReward", "inputs": [ { - "indexed": true, - "internalType": "uint256", + "type": "uint256", "name": "fId", - "type": "uint256" + "internalType": "uint256", + "indexed": true }, { - "indexed": false, - "internalType": "uint256", + "type": "uint256", "name": "nftId", - "type": "uint256" + "internalType": "uint256", + "indexed": false }, { - "indexed": false, - "internalType": "address", + "type": "address", "name": "token", - "type": "address" + "internalType": "address", + "indexed": false }, { - "indexed": false, - "internalType": "uint256", + "type": "uint256", "name": "amount", - "type": "uint256" + "internalType": "uint256", + "indexed": false }, { - "indexed": false, - "internalType": "address", + "type": "address", "name": "receiver", - "type": "address" + "internalType": "address", + "indexed": false } ], - "name": "ClaimReward", - "type": "event" + "anonymous": false }, { - "anonymous": false, + "type": "event", + "name": "ClaimReward", "inputs": [ { - "indexed": true, - "internalType": "uint256", + "type": "uint256", "name": "fId", - "type": "uint256" + "internalType": "uint256", + "indexed": true }, { - "indexed": false, - "internalType": "uint256[]", + "type": "uint256[]", "name": "nftIds", - "type": "uint256[]" + "internalType": "uint256[]", + "indexed": false }, { - "indexed": false, - "internalType": "address", + "type": "address", "name": "token", - "type": "address" + "internalType": "address", + "indexed": false }, { - "indexed": false, - "internalType": "uint256", + "type": "uint256", "name": "amount", - "type": "uint256" + "internalType": "uint256", + "indexed": false }, { - "indexed": false, - "internalType": "address", + "type": "address", "name": "receiver", - "type": "address" + "internalType": "address", + "indexed": false } ], - "name": "ClaimReward", - "type": "event" + "anonymous": false }, { - "anonymous": false, + "type": "event", + "name": "Deposit", "inputs": [ { - "indexed": true, - "internalType": "uint256", + "type": "uint256", "name": "fId", - "type": "uint256" + "internalType": "uint256", + "indexed": true }, { - "indexed": false, - "internalType": "uint256", + "type": "uint256", "name": "rangeId", - "type": "uint256" + "internalType": "uint256", + "indexed": false }, { - "indexed": false, - "internalType": "uint256[]", + "type": "uint256[]", "name": "nftIds", - "type": "uint256[]" + "internalType": "uint256[]", + "indexed": false }, { - "indexed": true, - "internalType": "address", + "type": "address", "name": "depositer", - "type": "address" + "internalType": "address", + "indexed": true }, { - "indexed": false, - "internalType": "address", + "type": "address", "name": "receiver", - "type": "address" + "internalType": "address", + "indexed": false } ], - "name": "Deposit", - "type": "event" + "anonymous": false }, { - "anonymous": false, + "type": "event", + "name": "ExpandEndTimeAndRewards", "inputs": [ { - "indexed": true, - "internalType": "uint256", + "type": "uint256", "name": "fId", - "type": "uint256" + "internalType": "uint256", + "indexed": true }, { - "indexed": false, - "internalType": "uint256", + "type": "uint256", "name": "duration", - "type": "uint256" + "internalType": "uint256", + "indexed": false }, { - "indexed": false, - "internalType": "uint256[]", + "type": "uint256[]", "name": "rewardAmounts", - "type": "uint256[]" + "internalType": "uint256[]", + "indexed": false } ], - "name": "ExpandEndTimeAndRewards", - "type": "event" + "anonymous": false }, { - "anonymous": false, + "type": "event", + "name": "ForceClosePhase", "inputs": [ { - "indexed": true, - "internalType": "uint256", + "type": "uint256", "name": "fId", - "type": "uint256" + "internalType": "uint256", + "indexed": true } ], - "name": "ForceClosePhase", - "type": "event" + "anonymous": false }, { - "anonymous": false, + "type": "event", + "name": "OwnershipTransferred", "inputs": [ { - "indexed": true, - "internalType": "address", + "type": "address", "name": "previousOwner", - "type": "address" + "internalType": "address", + "indexed": true }, { - "indexed": true, - "internalType": "address", + "type": "address", "name": "newOwner", - "type": "address" + "internalType": "address", + "indexed": true } ], - "name": "OwnershipTransferred", - "type": "event" + "anonymous": false }, { - "anonymous": false, + "type": "event", + "name": "Paused", "inputs": [ { - "indexed": false, - "internalType": "address", + "type": "address", "name": "account", - "type": "address" + "internalType": "address", + "indexed": false } ], - "name": "Paused", - "type": "event" + "anonymous": false }, { - "anonymous": false, + "type": "event", + "name": "RemoveRange", "inputs": [ { - "indexed": true, - "internalType": "uint256", + "type": "uint256", "name": "fId", - "type": "uint256" + "internalType": "uint256", + "indexed": true }, { - "indexed": false, - "internalType": "uint256", + "type": "uint256", "name": "rangeId", - "type": "uint256" + "internalType": "uint256", + "indexed": false } ], - "name": "RemoveRange", - "type": "event" + "anonymous": false }, { - "anonymous": false, + "type": "event", + "name": "Unpaused", "inputs": [ { - "indexed": false, - "internalType": "address", + "type": "address", "name": "account", - "type": "address" + "internalType": "address", + "indexed": false } ], - "name": "Unpaused", - "type": "event" + "anonymous": false }, { - "anonymous": false, + "type": "event", + "name": "UpdateEmergency", "inputs": [ { - "indexed": false, - "internalType": "bool", + "type": "bool", "name": "enableOrDisable", - "type": "bool" + "internalType": "bool", + "indexed": false } ], - "name": "UpdateEmergency", - "type": "event" + "anonymous": false }, { - "anonymous": false, + "type": "event", + "name": "UpdateGuardian", "inputs": [ { - "indexed": false, - "internalType": "address", + "type": "address", "name": "user", - "type": "address" + "internalType": "address", + "indexed": false }, { - "indexed": false, - "internalType": "bool", + "type": "bool", "name": "grantOrRevoke", - "type": "bool" + "internalType": "bool", + "indexed": false } ], - "name": "UpdateGuardian", - "type": "event" + "anonymous": false }, { - "anonymous": false, + "type": "event", + "name": "UpdateHelper", "inputs": [ { - "indexed": false, - "internalType": "contract IKSElasticLMHelper", + "type": "address", "name": "helper", - "type": "address" + "internalType": "contract IKSElasticLMHelper", + "indexed": false } ], - "name": "UpdateHelper", - "type": "event" + "anonymous": false }, { - "anonymous": false, + "type": "event", + "name": "UpdateLiquidity", "inputs": [ { - "indexed": true, - "internalType": "uint256", + "type": "uint256", "name": "fId", - "type": "uint256" + "internalType": "uint256", + "indexed": true }, { - "indexed": false, - "internalType": "uint256", + "type": "uint256", "name": "nftId", - "type": "uint256" + "internalType": "uint256", + "indexed": false }, { - "indexed": false, - "internalType": "uint256", + "type": "uint256", "name": "liquidity", - "type": "uint256" + "internalType": "uint256", + "indexed": false } ], - "name": "UpdateLiquidity", - "type": "event" + "anonymous": false }, { - "anonymous": false, + "type": "event", + "name": "UpdateOperator", "inputs": [ { - "indexed": false, - "internalType": "address", + "type": "address", "name": "user", - "type": "address" + "internalType": "address", + "indexed": false }, { - "indexed": false, - "internalType": "bool", + "type": "bool", "name": "grantOrRevoke", - "type": "bool" + "internalType": "bool", + "indexed": false } ], - "name": "UpdateOperator", - "type": "event" + "anonymous": false }, { - "anonymous": false, + "type": "event", + "name": "UpdateTokenCode", "inputs": [ { - "indexed": false, - "internalType": "bytes", + "type": "bytes", "name": "farmingTokenCode", - "type": "bytes" + "internalType": "bytes", + "indexed": false } ], - "name": "UpdateTokenCode", - "type": "event" + "anonymous": false }, { - "anonymous": false, + "type": "event", + "name": "Withdraw", "inputs": [ { - "indexed": false, - "internalType": "uint256[]", + "type": "uint256[]", "name": "nftIds", - "type": "uint256[]" + "internalType": "uint256[]", + "indexed": false }, { - "indexed": false, - "internalType": "address", + "type": "address", "name": "receiver", - "type": "address" + "internalType": "address", + "indexed": false } ], - "name": "Withdraw", - "type": "event" + "anonymous": false }, { - "anonymous": false, + "type": "event", + "name": "WithdrawEmergency", "inputs": [ { - "indexed": false, - "internalType": "uint256", + "type": "uint256", "name": "nftId", - "type": "uint256" + "internalType": "uint256", + "indexed": false }, { - "indexed": false, - "internalType": "address", + "type": "address", "name": "receiver", - "type": "address" + "internalType": "address", + "indexed": false } ], - "name": "WithdrawEmergency", - "type": "event" + "anonymous": false }, { - "anonymous": false, + "type": "event", + "name": "WithdrawUnusedRewards", "inputs": [ { - "indexed": false, - "internalType": "address", + "type": "address", "name": "token", - "type": "address" + "internalType": "address", + "indexed": false }, { - "indexed": false, - "internalType": "uint256", + "type": "uint256", "name": "amount", - "type": "uint256" + "internalType": "uint256", + "indexed": false }, { - "indexed": false, - "internalType": "address", + "type": "address", "name": "receiver", - "type": "address" + "internalType": "address", + "indexed": false } ], - "name": "WithdrawUnusedRewards", - "type": "event" + "anonymous": false }, { + "type": "function", + "stateMutability": "nonpayable", + "outputs": [], + "name": "activateRange", "inputs": [ { - "internalType": "uint256", + "type": "uint256", "name": "fId", - "type": "uint256" + "internalType": "uint256" }, { - "internalType": "uint256", + "type": "uint256", "name": "rangeId", - "type": "uint256" + "internalType": "uint256" } - ], - "name": "activateRange", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" + ] }, { + "type": "function", + "stateMutability": "nonpayable", + "outputs": [ + { + "type": "uint256", + "name": "fId", + "internalType": "uint256" + } + ], + "name": "addFarm", "inputs": [ { - "internalType": "address", + "type": "address", "name": "poolAddress", - "type": "address" + "internalType": "address" }, { + "type": "tuple[]", + "name": "ranges", + "internalType": "struct IKSElasticLMV2.RangeInput[]", "components": [ { - "internalType": "int24", + "type": "int24", "name": "tickLower", - "type": "int24" + "internalType": "int24" }, { - "internalType": "int24", + "type": "int24", "name": "tickUpper", - "type": "int24" + "internalType": "int24" }, { - "internalType": "uint32", + "type": "uint32", "name": "weight", - "type": "uint32" + "internalType": "uint32" } - ], - "internalType": "struct IKSElasticLMV2.RangeInput[]", - "name": "ranges", - "type": "tuple[]" + ] }, { + "type": "tuple", + "name": "phase", + "internalType": "struct IKSElasticLMV2.PhaseInput", "components": [ { - "internalType": "uint32", + "type": "uint32", "name": "startTime", - "type": "uint32" + "internalType": "uint32" }, { - "internalType": "uint32", + "type": "uint32", "name": "endTime", - "type": "uint32" + "internalType": "uint32" }, { + "type": "tuple[]", + "name": "rewards", + "internalType": "struct IKSElasticLMV2.RewardInput[]", "components": [ { - "internalType": "address", + "type": "address", "name": "rewardToken", - "type": "address" + "internalType": "address" }, { - "internalType": "uint256", + "type": "uint256", "name": "rewardAmount", - "type": "uint256" + "internalType": "uint256" } - ], - "internalType": "struct IKSElasticLMV2.RewardInput[]", - "name": "rewards", - "type": "tuple[]" + ] } - ], - "internalType": "struct IKSElasticLMV2.PhaseInput", - "name": "phase", - "type": "tuple" + ] }, { - "internalType": "bool", + "type": "bool", "name": "isUsingToken", - "type": "bool" - } - ], - "name": "addFarm", - "outputs": [ - { - "internalType": "uint256", - "name": "fId", - "type": "uint256" + "internalType": "bool" } - ], - "stateMutability": "nonpayable", - "type": "function" + ] }, { + "type": "function", + "stateMutability": "nonpayable", + "outputs": [], + "name": "addLiquidity", "inputs": [ { - "internalType": "uint256", + "type": "uint256", "name": "fId", - "type": "uint256" + "internalType": "uint256" }, { - "internalType": "uint256", + "type": "uint256", "name": "rangeId", - "type": "uint256" + "internalType": "uint256" }, { - "internalType": "uint256[]", + "type": "uint256[]", "name": "nftIds", - "type": "uint256[]" + "internalType": "uint256[]" } - ], - "name": "addLiquidity", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" + ] }, { + "type": "function", + "stateMutability": "nonpayable", + "outputs": [], + "name": "addPhase", "inputs": [ { - "internalType": "uint256", + "type": "uint256", "name": "fId", - "type": "uint256" + "internalType": "uint256" }, { + "type": "tuple", + "name": "phaseInput", + "internalType": "struct IKSElasticLMV2.PhaseInput", "components": [ { - "internalType": "uint32", + "type": "uint32", "name": "startTime", - "type": "uint32" + "internalType": "uint32" }, { - "internalType": "uint32", + "type": "uint32", "name": "endTime", - "type": "uint32" + "internalType": "uint32" }, { + "type": "tuple[]", + "name": "rewards", + "internalType": "struct IKSElasticLMV2.RewardInput[]", "components": [ { - "internalType": "address", + "type": "address", "name": "rewardToken", - "type": "address" + "internalType": "address" }, { - "internalType": "uint256", + "type": "uint256", "name": "rewardAmount", - "type": "uint256" + "internalType": "uint256" } - ], - "internalType": "struct IKSElasticLMV2.RewardInput[]", - "name": "rewards", - "type": "tuple[]" + ] } - ], - "internalType": "struct IKSElasticLMV2.PhaseInput", - "name": "phaseInput", - "type": "tuple" + ] } - ], - "name": "addPhase", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" + ] }, { + "type": "function", + "stateMutability": "nonpayable", + "outputs": [], + "name": "addRange", "inputs": [ { - "internalType": "uint256", + "type": "uint256", "name": "fId", - "type": "uint256" + "internalType": "uint256" }, { + "type": "tuple", + "name": "range", + "internalType": "struct IKSElasticLMV2.RangeInput", "components": [ { - "internalType": "int24", + "type": "int24", "name": "tickLower", - "type": "int24" + "internalType": "int24" }, { - "internalType": "int24", + "type": "int24", "name": "tickUpper", - "type": "int24" + "internalType": "int24" }, { - "internalType": "uint32", + "type": "uint32", "name": "weight", - "type": "uint32" + "internalType": "uint32" } - ], - "internalType": "struct IKSElasticLMV2.RangeInput", - "name": "range", - "type": "tuple" + ] } - ], - "name": "addRange", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" + ] }, { + "type": "function", + "stateMutability": "nonpayable", + "outputs": [], + "name": "claimFee", "inputs": [ { - "internalType": "uint256", + "type": "uint256", "name": "fId", - "type": "uint256" + "internalType": "uint256" }, { - "internalType": "uint256[]", + "type": "uint256[]", "name": "nftIds", - "type": "uint256[]" + "internalType": "uint256[]" }, { - "internalType": "uint256", + "type": "uint256", "name": "amount0Min", - "type": "uint256" + "internalType": "uint256" }, { - "internalType": "uint256", + "type": "uint256", "name": "amount1Min", - "type": "uint256" + "internalType": "uint256" }, { - "internalType": "uint256", + "type": "uint256", "name": "deadline", - "type": "uint256" + "internalType": "uint256" }, { - "internalType": "uint8", + "type": "uint8", "name": "flags", - "type": "uint8" + "internalType": "uint8" } - ], - "name": "claimFee", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" + ] }, { + "type": "function", + "stateMutability": "nonpayable", + "outputs": [], + "name": "claimReward", "inputs": [ { - "internalType": "uint256", + "type": "uint256", "name": "fId", - "type": "uint256" + "internalType": "uint256" }, { - "internalType": "uint256[]", + "type": "uint256[]", "name": "nftIds", - "type": "uint256[]" + "internalType": "uint256[]" } - ], - "name": "claimReward", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" + ] }, { + "type": "function", + "stateMutability": "nonpayable", + "outputs": [], + "name": "deposit", "inputs": [ { - "internalType": "uint256", + "type": "uint256", "name": "fId", - "type": "uint256" + "internalType": "uint256" }, { - "internalType": "uint256", + "type": "uint256", "name": "rangeId", - "type": "uint256" + "internalType": "uint256" }, { - "internalType": "uint256[]", + "type": "uint256[]", "name": "nftIds", - "type": "uint256[]" + "internalType": "uint256[]" }, { - "internalType": "address", + "type": "address", "name": "receiver", - "type": "address" + "internalType": "address" } - ], - "name": "deposit", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" + ] }, { - "inputs": [], - "name": "disableLogic", - "outputs": [], + "type": "function", "stateMutability": "nonpayable", - "type": "function" + "outputs": [], + "name": "disableLogic", + "inputs": [] }, { - "inputs": [], - "name": "emergencyEnabled", + "type": "function", + "stateMutability": "view", "outputs": [ { - "internalType": "bool", + "type": "bool", "name": "", - "type": "bool" + "internalType": "bool" } ], - "stateMutability": "view", - "type": "function" + "name": "emergencyEnabled", + "inputs": [] }, { - "inputs": [], - "name": "enableLogic", - "outputs": [], + "type": "function", "stateMutability": "nonpayable", - "type": "function" + "outputs": [], + "name": "enableLogic", + "inputs": [] }, { - "inputs": [], - "name": "farmCount", + "type": "function", + "stateMutability": "view", "outputs": [ { - "internalType": "uint256", + "type": "uint256", "name": "", - "type": "uint256" + "internalType": "uint256" } ], - "stateMutability": "view", - "type": "function" + "name": "farmCount", + "inputs": [] }, { + "type": "function", + "stateMutability": "nonpayable", + "outputs": [], + "name": "forceClosePhase", "inputs": [ { - "internalType": "uint256", + "type": "uint256", "name": "fId", - "type": "uint256" + "internalType": "uint256" } - ], - "name": "forceClosePhase", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" + ] }, { - "inputs": [ - { - "internalType": "address", - "name": "user", - "type": "address" - } - ], - "name": "getDepositedNFTs", + "type": "function", + "stateMutability": "view", "outputs": [ { - "internalType": "uint256[]", + "type": "uint256[]", "name": "listNFTs", - "type": "uint256[]" + "internalType": "uint256[]" } ], - "stateMutability": "view", - "type": "function" - }, - { + "name": "getDepositedNFTs", "inputs": [ { - "internalType": "uint256", - "name": "fId", - "type": "uint256" + "type": "address", + "name": "user", + "internalType": "address" } - ], - "name": "getFarm", + ] + }, + { + "type": "function", + "stateMutability": "view", "outputs": [ { - "internalType": "address", + "type": "address", "name": "poolAddress", - "type": "address" + "internalType": "address" }, { + "type": "tuple[]", + "name": "ranges", + "internalType": "struct IKSElasticLMV2.RangeInfo[]", "components": [ { - "internalType": "int24", + "type": "int24", "name": "tickLower", - "type": "int24" + "internalType": "int24" }, { - "internalType": "int24", + "type": "int24", "name": "tickUpper", - "type": "int24" + "internalType": "int24" }, { - "internalType": "uint32", + "type": "uint32", "name": "weight", - "type": "uint32" + "internalType": "uint32" }, { - "internalType": "bool", + "type": "bool", "name": "isRemoved", - "type": "bool" + "internalType": "bool" } - ], - "internalType": "struct IKSElasticLMV2.RangeInfo[]", - "name": "ranges", - "type": "tuple[]" + ] }, { + "type": "tuple", + "name": "phase", + "internalType": "struct IKSElasticLMV2.PhaseInfo", "components": [ { - "internalType": "uint32", + "type": "uint32", "name": "startTime", - "type": "uint32" + "internalType": "uint32" }, { - "internalType": "uint32", + "type": "uint32", "name": "endTime", - "type": "uint32" + "internalType": "uint32" }, { - "internalType": "bool", + "type": "bool", "name": "isSettled", - "type": "bool" + "internalType": "bool" }, { + "type": "tuple[]", + "name": "rewards", + "internalType": "struct IKSElasticLMV2.RewardInput[]", "components": [ { - "internalType": "address", + "type": "address", "name": "rewardToken", - "type": "address" + "internalType": "address" }, { - "internalType": "uint256", + "type": "uint256", "name": "rewardAmount", - "type": "uint256" + "internalType": "uint256" } - ], - "internalType": "struct IKSElasticLMV2.RewardInput[]", - "name": "rewards", - "type": "tuple[]" + ] } - ], - "internalType": "struct IKSElasticLMV2.PhaseInfo", - "name": "phase", - "type": "tuple" + ] }, { - "internalType": "uint256", + "type": "uint256", "name": "liquidity", - "type": "uint256" + "internalType": "uint256" }, { - "internalType": "address", + "type": "address", "name": "farmingToken", - "type": "address" + "internalType": "address" }, { - "internalType": "uint256[]", + "type": "uint256[]", "name": "sumRewardPerLiquidity", - "type": "uint256[]" + "internalType": "uint256[]" }, { - "internalType": "uint32", + "type": "uint32", "name": "lastTouchedTime", - "type": "uint32" + "internalType": "uint32" } ], - "stateMutability": "view", - "type": "function" + "name": "getFarm", + "inputs": [ + { + "type": "uint256", + "name": "fId", + "internalType": "uint256" + } + ] }, { - "inputs": [], - "name": "getNft", + "type": "function", + "stateMutability": "view", "outputs": [ { - "internalType": "contract IERC721", + "type": "address", "name": "", - "type": "address" + "internalType": "contract IERC721" } ], - "stateMutability": "view", - "type": "function" + "name": "getNft", + "inputs": [] }, { - "inputs": [ - { - "internalType": "uint256", - "name": "nftId", - "type": "uint256" - } - ], - "name": "getStake", + "type": "function", + "stateMutability": "view", "outputs": [ { - "internalType": "address", + "type": "address", "name": "owner", - "type": "address" + "internalType": "address" }, { - "internalType": "uint256", + "type": "uint256", "name": "fId", - "type": "uint256" + "internalType": "uint256" }, { - "internalType": "uint256", + "type": "uint256", "name": "rangeId", - "type": "uint256" + "internalType": "uint256" }, { - "internalType": "uint256", + "type": "uint256", "name": "liquidity", - "type": "uint256" + "internalType": "uint256" }, { - "internalType": "uint256[]", + "type": "uint256[]", "name": "lastSumRewardPerLiquidity", - "type": "uint256[]" + "internalType": "uint256[]" }, { - "internalType": "uint256[]", + "type": "uint256[]", "name": "rewardUnclaimed", - "type": "uint256[]" + "internalType": "uint256[]" } ], - "stateMutability": "view", - "type": "function" + "name": "getStake", + "inputs": [ + { + "type": "uint256", + "name": "nftId", + "internalType": "uint256" + } + ] }, { - "inputs": [ + "type": "function", + "stateMutability": "view", + "outputs": [ { - "internalType": "address", + "type": "bool", "name": "", - "type": "address" + "internalType": "bool" } ], "name": "guardians", - "outputs": [ + "inputs": [ { - "internalType": "bool", + "type": "address", "name": "", - "type": "bool" + "internalType": "address" } - ], - "stateMutability": "view", - "type": "function" + ] }, { - "inputs": [ + "type": "function", + "stateMutability": "view", + "outputs": [ { - "internalType": "address", + "type": "bool", "name": "", - "type": "address" + "internalType": "bool" } ], "name": "operators", - "outputs": [ + "inputs": [ { - "internalType": "bool", + "type": "address", "name": "", - "type": "bool" + "internalType": "address" } - ], - "stateMutability": "view", - "type": "function" + ] }, { - "inputs": [], - "name": "owner", + "type": "function", + "stateMutability": "view", "outputs": [ { - "internalType": "address", + "type": "address", "name": "", - "type": "address" + "internalType": "address" } ], - "stateMutability": "view", - "type": "function" + "name": "owner", + "inputs": [] }, { - "inputs": [], - "name": "paused", + "type": "function", + "stateMutability": "view", "outputs": [ { - "internalType": "bool", + "type": "bool", "name": "", - "type": "bool" + "internalType": "bool" } ], - "stateMutability": "view", - "type": "function" + "name": "paused", + "inputs": [] }, { + "type": "function", + "stateMutability": "nonpayable", + "outputs": [], + "name": "removeLiquidity", "inputs": [ { - "internalType": "uint256", + "type": "uint256", "name": "nftId", - "type": "uint256" + "internalType": "uint256" }, { - "internalType": "uint128", + "type": "uint128", "name": "liquidity", - "type": "uint128" + "internalType": "uint128" }, { - "internalType": "uint256", + "type": "uint256", "name": "amount0Min", - "type": "uint256" + "internalType": "uint256" }, { - "internalType": "uint256", + "type": "uint256", "name": "amount1Min", - "type": "uint256" + "internalType": "uint256" }, { - "internalType": "uint256", + "type": "uint256", "name": "deadline", - "type": "uint256" + "internalType": "uint256" }, { - "internalType": "uint8", + "type": "uint8", "name": "flags", - "type": "uint8" + "internalType": "uint8" } - ], - "name": "removeLiquidity", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" + ] }, { + "type": "function", + "stateMutability": "nonpayable", + "outputs": [], + "name": "removeRange", "inputs": [ { - "internalType": "uint256", + "type": "uint256", "name": "fId", - "type": "uint256" + "internalType": "uint256" }, { - "internalType": "uint256", + "type": "uint256", "name": "rangeId", - "type": "uint256" + "internalType": "uint256" } - ], - "name": "removeRange", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" + ] }, { - "inputs": [], - "name": "renounceOwnership", - "outputs": [], + "type": "function", "stateMutability": "nonpayable", - "type": "function" + "outputs": [], + "name": "renounceOwnership", + "inputs": [] }, { + "type": "function", + "stateMutability": "nonpayable", + "outputs": [], + "name": "transferOwnership", "inputs": [ { - "internalType": "address", + "type": "address", "name": "newOwner", - "type": "address" + "internalType": "address" } - ], - "name": "transferOwnership", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" + ] }, { + "type": "function", + "stateMutability": "nonpayable", + "outputs": [], + "name": "updateEmergency", "inputs": [ { - "internalType": "bool", + "type": "bool", "name": "enableOrDisable", - "type": "bool" + "internalType": "bool" } - ], - "name": "updateEmergency", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" + ] }, { + "type": "function", + "stateMutability": "nonpayable", + "outputs": [], + "name": "updateGuardian", "inputs": [ { - "internalType": "address", + "type": "address", "name": "user", - "type": "address" + "internalType": "address" }, { - "internalType": "bool", + "type": "bool", "name": "grantOrRevoke", - "type": "bool" + "internalType": "bool" } - ], - "name": "updateGuardian", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" + ] }, { + "type": "function", + "stateMutability": "nonpayable", + "outputs": [], + "name": "updateHelper", "inputs": [ { - "internalType": "contract IKSElasticLMHelper", + "type": "address", "name": "_helper", - "type": "address" + "internalType": "contract IKSElasticLMHelper" } - ], - "name": "updateHelper", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" + ] }, { + "type": "function", + "stateMutability": "nonpayable", + "outputs": [], + "name": "updateOperator", "inputs": [ { - "internalType": "address", + "type": "address", "name": "user", - "type": "address" + "internalType": "address" }, { - "internalType": "bool", + "type": "bool", "name": "grantOrRevoke", - "type": "bool" + "internalType": "bool" } - ], - "name": "updateOperator", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" + ] }, { + "type": "function", + "stateMutability": "nonpayable", + "outputs": [], + "name": "updateTokenCode", "inputs": [ { - "internalType": "bytes", + "type": "bytes", "name": "_farmingTokenCreationCode", - "type": "bytes" + "internalType": "bytes" } - ], - "name": "updateTokenCode", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" + ] }, { - "inputs": [], - "name": "weth", + "type": "function", + "stateMutability": "view", "outputs": [ { - "internalType": "address", + "type": "address", "name": "", - "type": "address" + "internalType": "address" } ], - "stateMutability": "view", - "type": "function" + "name": "weth", + "inputs": [] }, { + "type": "function", + "stateMutability": "nonpayable", + "outputs": [], + "name": "withdraw", "inputs": [ { - "internalType": "uint256", + "type": "uint256", "name": "fId", - "type": "uint256" + "internalType": "uint256" }, { - "internalType": "uint256[]", + "type": "uint256[]", "name": "nftIds", - "type": "uint256[]" + "internalType": "uint256[]" } - ], - "name": "withdraw", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" + ] }, { + "type": "function", + "stateMutability": "nonpayable", + "outputs": [], + "name": "withdrawEmergency", "inputs": [ { - "internalType": "uint256[]", + "type": "uint256[]", "name": "nftIds", - "type": "uint256[]" + "internalType": "uint256[]" } - ], - "name": "withdrawEmergency", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" + ] }, { + "type": "function", + "stateMutability": "nonpayable", + "outputs": [], + "name": "withdrawUnusedRewards", "inputs": [ { - "internalType": "address[]", + "type": "address[]", "name": "tokens", - "type": "address[]" + "internalType": "address[]" }, { - "internalType": "uint256[]", + "type": "uint256[]", "name": "amounts", - "type": "uint256[]" + "internalType": "uint256[]" } - ], - "name": "withdrawUnusedRewards", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" + ] }, { - "stateMutability": "payable", - "type": "receive" + "type": "receive", + "stateMutability": "payable" } ] diff --git a/src/constants/bases.ts b/src/constants/bases.ts index 8a4bd0bae2..808d2b0641 100644 --- a/src/constants/bases.ts +++ b/src/constants/bases.ts @@ -28,6 +28,7 @@ const WETH_ONLY: ChainTokenList = { [ChainId.LINEA]: [WETH[ChainId.LINEA]], [ChainId.ZKEVM]: [WETH[ChainId.ZKEVM]], [ChainId.BASE]: [WETH[ChainId.BASE]], + [ChainId.SCROLL]: [WETH[ChainId.SCROLL]], [ChainId.SOLANA_DEVNET]: [WETH[ChainId.SOLANA_DEVNET]], } @@ -179,4 +180,5 @@ export const SUGGESTED_BASES: ChainTokenList = { new Token(ChainId.LINEA, '0x7d43aabc515c356145049227cee54b608342c0ad', 18, 'BUSD', 'BUSD'), ], [ChainId.BASE]: [...WETH_ONLY[ChainId.BASE], USDC[ChainId.BASE], DAI[ChainId.BASE]], + [ChainId.SCROLL]: [...WETH_ONLY[ChainId.SCROLL], USDT[ChainId.SCROLL], USDC[ChainId.SCROLL], DAI[ChainId.SCROLL]], } diff --git a/src/constants/index.ts b/src/constants/index.ts index 3d4e58903b..d3a1d084d2 100644 --- a/src/constants/index.ts +++ b/src/constants/index.ts @@ -5,7 +5,7 @@ import { v4 as uuid } from 'uuid' import { TransactionFlowState } from 'types/TransactionFlowState' -import { CAMPAIGN_BASE_URL as CAMPAIGN_BASE_DOMAIN } from './env' +import { CAMPAIGN_BASE_URL } from './env' import * as ENV from './env' import { EVM_MAINNET_NETWORKS, EVM_NETWORK, NETWORKS_INFO, SUPPORTED_NETWORKS, isEVM } from './networks' @@ -186,16 +186,10 @@ export const CAMPAIGN_YOUR_TRANSACTIONS_ITEM_PER_PAGE = 10000 export const ELASTIC_BASE_FEE_UNIT = 100_000 export const KYBERSWAP_SOURCE = '{"source":"kyberswap"}' -export const CAMPAIGN_BASE_URL = `${CAMPAIGN_BASE_DOMAIN}/api/v1/campaigns` export const SWR_KEYS = { - getGrantProgramLeaderBoard: (id: number | string) => `${CAMPAIGN_BASE_DOMAIN}/api/v1/competitions/${id}/leaderboard`, - getListGrantPrograms: `${CAMPAIGN_BASE_DOMAIN}/api/v1/competitions`, - getGrantProgram: (id: number | string) => `${CAMPAIGN_BASE_DOMAIN}/api/v1/competitions/${id}`, - getListCampaign: CAMPAIGN_BASE_URL, - getLeaderboard: (id: number) => CAMPAIGN_BASE_URL + '/' + id + '/leaderboard', - getLuckyWinners: (id: number) => CAMPAIGN_BASE_URL + '/' + id + '/lucky-winners', - getCampaignTransactions: (campaignId: number, limit: number, offset: number, account: string) => - `${CAMPAIGN_BASE_URL}/${campaignId}/proofs?limit=${limit}&offset=${offset}&userAddress=${account}`, + getGrantProgramLeaderBoard: (id: number | string) => `${CAMPAIGN_BASE_URL}/api/v1/competitions/${id}/leaderboard`, + getListGrantPrograms: `${CAMPAIGN_BASE_URL}/api/v1/competitions`, + getGrantProgram: (id: number | string) => `${CAMPAIGN_BASE_URL}/api/v1/competitions/${id}`, } // https://www.nasdaq.com/glossary/b/bip @@ -341,6 +335,7 @@ export const TYPE_AND_SWAP_NOT_SUPPORTED_CHAINS: ChainId[] = [ ChainId.LINEA, ChainId.ZKEVM, ChainId.BASE, + ChainId.SCROLL, ] export const SWAP_FEE_RECEIVER_ADDRESS = '0x4f82e73EDb06d29Ff62C91EC8f5Ff06571bdeb29' diff --git a/src/constants/networks.ts b/src/constants/networks.ts index 51149291d8..2ffd52dd5e 100644 --- a/src/constants/networks.ts +++ b/src/constants/networks.ts @@ -20,6 +20,7 @@ import { matic, mumbai, optimism, + scroll, solana, solanaDevnet, zkEvm, @@ -51,6 +52,7 @@ const NETWORKS_INFO_CONFIG: NETWORKS_INFO_CONFIG_TYPE = { [ChainId.LINEA]: linea, [ChainId.ZKEVM]: zkEvm, [ChainId.BASE]: base, + [ChainId.SCROLL]: scroll, [ChainId.SOLANA]: solana, [ChainId.SOLANA_DEVNET]: solanaDevnet, } as const @@ -77,6 +79,7 @@ export const MAINNET_NETWORKS = [ ChainId.ZKEVM, ChainId.ZKSYNC, ChainId.BASE, + ChainId.SCROLL, ChainId.BSCMAINNET, ChainId.AVAXMAINNET, // ChainId.SOLANA, @@ -148,6 +151,7 @@ export const STATIC_FEE_OPTIONS: { [chainId: number]: number[] | undefined } = { [ChainId.LINEA]: [8, 10, 50, 300, 500, 1000], [ChainId.ZKEVM]: [8, 10, 50, 300, 500, 1000], [ChainId.BASE]: [8, 10, 50, 300, 500, 1000], + [ChainId.SCROLL]: [8, 10, 50, 300, 500, 1000], } export const ONLY_STATIC_FEE_CHAINS = [ @@ -159,6 +163,7 @@ export const ONLY_STATIC_FEE_CHAINS = [ ChainId.LINEA, ChainId.ZKEVM, ChainId.BASE, + ChainId.SCROLL, ] // hardcode for unavailable subgraph @@ -185,6 +190,7 @@ export const SUPPORTED_NETWORKS_FOR_MY_EARNINGS = [ ChainId.LINEA, ChainId.BASE, ChainId.ZKSYNC, + ChainId.SCROLL, ChainId.BSCMAINNET, ChainId.AVAXMAINNET, ChainId.FANTOM, diff --git a/src/constants/networks/index.ts b/src/constants/networks/index.ts index d5d210bd1b..f64d1000fd 100644 --- a/src/constants/networks/index.ts +++ b/src/constants/networks/index.ts @@ -17,4 +17,5 @@ export { default as zksync } from './zksync' export { default as linea } from './linea' export { default as zkEvm } from './zkevm' export { default as base } from './base' +export { default as scroll } from './scroll' export { default as solanaDevnet } from './solana-devnet' diff --git a/src/constants/networks/scroll.ts b/src/constants/networks/scroll.ts new file mode 100644 index 0000000000..97b19d22bb --- /dev/null +++ b/src/constants/networks/scroll.ts @@ -0,0 +1,71 @@ +import { ChainId } from '@kyberswap/ks-sdk-core' + +import EthereumLogo from 'assets/images/ethereum-logo.png' +import { EVMNetworkInfo } from 'constants/networks/type' + +const EMPTY = '' +const EMPTY_ARRAY: any[] = [] +const NOT_SUPPORT = null + +const scroll: EVMNetworkInfo = { + chainId: ChainId.SCROLL, + route: 'scroll', + ksSettingRoute: 'scroll', + priceRoute: 'scroll', + poolFarmRoute: 'scroll', + aggregatorRoute: 'scroll', + name: 'Scroll', + icon: 'https://storage.googleapis.com/ks-setting-1d682dca/fe12013c-4d72-4ac3-9415-a278b7d474c71697595633825.png', + + iconSelected: NOT_SUPPORT, + + defaultBlockSubgraph: 'https://scroll-graph.kyberengineering.io/subgraphs/name/kybernetwork/scroll-blocks', + etherscanUrl: 'https://scrollscan.com', + etherscanName: 'Scrollscan', + bridgeURL: 'https://scroll.io/bridge', + nativeToken: { + symbol: 'ETH', + name: 'ETH', + logo: EthereumLogo, + decimal: 18, + minForGas: 10 ** 16, + }, + defaultRpcUrl: 'https://rpc.scroll.io', + multicall: '0xcA11bde05977b3631167028862bE2a173976CA11', + classic: { + defaultSubgraph: 'https://scroll-graph.kyberengineering.io/subgraphs/name/kybernetwork/kyberswap-exchange-scroll', + static: { + zap: '0x2abE8750e4a65584d7452316356128C936273e0D', + router: '0x5649B4DD00780e99Bab7Abb4A3d581Ea1aEB23D0', + factory: '0x1c758aF0688502e49140230F6b0EBd376d429be5', + }, + oldStatic: NOT_SUPPORT, + dynamic: NOT_SUPPORT, + claimReward: NOT_SUPPORT, + fairlaunch: EMPTY_ARRAY, + fairlaunchV2: EMPTY_ARRAY, + }, + elastic: { + defaultSubgraph: 'https://scroll-graph.kyberengineering.io/subgraphs/name/kybernetwork/kyberswap-elastic-scroll', + startBlock: 36376, + coreFactory: '0xC7a590291e07B9fe9E64b86c58fD8fC764308C4A', + nonfungiblePositionManager: '0xe222fBE074A436145b255442D919E4E3A6c6a480', + tickReader: '0x8Fd8Cb948965d9305999D767A02bf79833EADbB3', + initCodeHash: '0x00e263aaa3a2c06a89b53217a9e7aad7e15613490a72e0f95f303c4de2dc7045', + quoter: '0x4d47fd5a29904Dae0Ef51b1c450C9750F15D7856', + routers: '0xF9c2b5746c946EF883ab2660BbbB1f10A5bdeAb4', + farms: ['0x7D5ba536ab244aAA1EA42aB88428847F25E3E676'], + farmv2Quoter: '0x6AFeb9EDd6Cf44fA8E89b1eee28284e6dD7705C8', + farmV2S: [], + 'farmV2.1S': ['0x3D6AfE2fB73fFEd2E3dD00c501A174554e147a43', '0xf2BcDf38baA52F6b0C1Db5B025DfFf01Ae1d6dBd'], + }, + limitOrder: NOT_SUPPORT, + averageBlockTimeInSeconds: 8.4, // dont use for base + coingeckoNetworkId: 'scroll', + coingeckoNativeTokenId: 'ethereum', + deBankSlug: EMPTY, + dexToCompare: NOT_SUPPORT, + geckoTermialId: NOT_SUPPORT, +} + +export default scroll diff --git a/src/constants/tokens.ts b/src/constants/tokens.ts index 8087ffb1e5..6baa86c82c 100644 --- a/src/constants/tokens.ts +++ b/src/constants/tokens.ts @@ -57,6 +57,7 @@ export const STABLE_COIN_ADDRESSES_TO_TAKE_FEE: Record = { [ChainId.ZKEVM]: [], [ChainId.LINEA]: [], [ChainId.BASE]: [], + [ChainId.SCROLL]: [], [ChainId.SOLANA_DEVNET]: [], } @@ -151,6 +152,7 @@ export const SUPER_STABLE_COINS_ADDRESS: { [chainId in ChainId]: string[] } = { '0x50c5725949A6F0c72E6C4a641F24049A917DB0Cb', // DAI ], [ChainId.LINEA]: [], + [ChainId.SCROLL]: [], [ChainId.SOLANA_DEVNET]: [], } @@ -200,6 +202,7 @@ export const CORRELATED_COINS_ADDRESS: { [chainId in ChainId]: string[][] } = { [ChainId.ZKEVM]: [], [ChainId.LINEA]: [], [ChainId.BASE]: [], + [ChainId.SCROLL]: [], [ChainId.SOLANA_DEVNET]: [], } @@ -243,6 +246,8 @@ export const DAI: { [chainId in ChainId]: Token } = { 'DAI', 'DAI (Wormhole)', ), + // TDOD: Get real DAI + [ChainId.SCROLL]: new Token(ChainId.SCROLL, '0x50c5725949a6f0c72e6c4a641f24049a917db0cb', 18, 'DAI', 'Dai'), } export const USDC: { [chainId in ChainId]: Token } = { @@ -284,6 +289,8 @@ export const USDC: { [chainId in ChainId]: Token } = { [ChainId.ZKEVM]: new Token(ChainId.ZKEVM, '0xA8CE8aee21bC2A48a5EF670afCc9274C7bbbC035', 6, 'USDC', 'USD Coin'), [ChainId.LINEA]: new Token(ChainId.LINEA, '0x176211869cA2b568f2A7D4EE941E073a821EE1ff', 6, 'USDC', 'USD Coin'), [ChainId.BASE]: new Token(ChainId.BASE, '0xd9aAEc86B65D86f6A7B5B1b0c42FFA531710b6CA', 6, 'USDC', 'USD Coin'), + // TODO: verify this USDC on Scroll + [ChainId.SCROLL]: new Token(ChainId.SCROLL, '0x06eFdBFf2a14a7c8E15944D1F4A48F9F95F663A4', 6, 'USDC', 'USD Coin'), } export const USDT: { [chainId in ChainId]: Token } = { @@ -352,6 +359,8 @@ export const USDT: { [chainId in ChainId]: Token } = { // not existed [ChainId.BASE]: new Token(ChainId.BASE, '0xA219439258ca9da29E9Cc4cE5596924745e12B93', 6, 'USDT', 'Tether USD'), + // TODO: verify this address + [ChainId.SCROLL]: new Token(ChainId.SCROLL, '0xf55BEC9cafDbE8730f096Aa55dad6D22d44099Df', 6, 'USDT', 'Tether USD'), } export const COMP = new Token(ChainId.MAINNET, '0xc00e94Cb662C3520282E6f5717214004A7f26888', 18, 'COMP', 'Compound') @@ -381,12 +390,13 @@ export const KNC: { [chainId in ChainId]: Token } = { [ChainId.OPTIMISM]: new Token(ChainId.OPTIMISM, '0xa00e3a3511aac35ca78530c85007afcd31753819', 18, 'KNC', 'KNC'), [ChainId.LINEA]: new Token(ChainId.LINEA, '0x3b2F62d42DB19B30588648bf1c184865D4C3B1D6', 18, 'KNC', 'KNC'), [ChainId.ZKEVM]: new Token(ChainId.ZKEVM, '0x6A80A465409ce8D36C513129C0FEEa61BEd579ba', 18, 'KNC', 'KNC'), + [ChainId.BASE]: new Token(ChainId.BASE, '0x28fe69Ff6864C1C218878BDCA01482D36B9D57b1', 18, 'KNC', 'KNC'), // TODO(viet-nv): KNC does not exist on the below chain [ChainId.CRONOS]: new Token(ChainId.CRONOS, KNC_ADDRESS, 18, 'KNC', 'KNC'), [ChainId.AURORA]: new Token(ChainId.AURORA, KNC_ADDRESS, 18, 'KNC', 'KNC'), [ChainId.FANTOM]: new Token(ChainId.FANTOM, KNC_ADDRESS, 18, 'KNC', 'KNC'), - [ChainId.BASE]: new Token(ChainId.BASE, KNC_ADDRESS, 18, 'KNC', 'KNC'), + [ChainId.SCROLL]: new Token(ChainId.SCROLL, KNC_ADDRESS, 18, 'KNC', 'KNC'), [ChainId.ZKSYNC]: new Token(ChainId.ZKSYNC, KNC_ADDRESS, 18, 'KNC', 'KNC'), [ChainId.AVAXTESTNET]: new Token(ChainId.AVAXTESTNET, KNC_ADDRESS, 18, 'KNC', 'KNC'), @@ -430,6 +440,7 @@ export const DEFAULT_OUTPUT_TOKEN_BY_CHAIN: Partial> = { [ChainId.ZKEVM]: USDT[ChainId.ZKEVM], [ChainId.LINEA]: USDC[ChainId.LINEA], [ChainId.BASE]: USDC[ChainId.BASE], + [ChainId.SCROLL]: USDT[ChainId.SCROLL], } export const DEFAULT_SWAP_FEE_STABLE_PAIRS = 4 diff --git a/src/hooks/kyberdao/index.tsx b/src/hooks/kyberdao/index.tsx index b7606cb214..f292df57b6 100644 --- a/src/hooks/kyberdao/index.tsx +++ b/src/hooks/kyberdao/index.tsx @@ -495,6 +495,7 @@ export function useVotingInfo() { rewardStats: { knc: rewardStats ? +rewardStats.pending?.totalAmountInKNC + +rewardStats.liquidated?.totalAmountInKNC : 0, usd: rewardStats ? +rewardStats.pending?.totalAmountInUSD + +rewardStats.liquidated?.totalAmountInUSD : 0, + apr: rewardStats ? +rewardStats.apr : 0, }, } return result diff --git a/src/hooks/kyberdao/types.ts b/src/hooks/kyberdao/types.ts index 11867aecd9..081eca4f10 100644 --- a/src/hooks/kyberdao/types.ts +++ b/src/hooks/kyberdao/types.ts @@ -37,6 +37,7 @@ interface VoteStat { total_address_count: number total_vote_count: number votes: VoteDetail[] | null + quorum_status: number } export interface ProposalDetail { cancelled: boolean @@ -130,4 +131,5 @@ export interface RewardStats { totalAmountInKNC: string totalAmountInUSD: string } + apr: string } diff --git a/src/hooks/useInvalidateTags.ts b/src/hooks/useInvalidateTags.ts new file mode 100644 index 0000000000..3a1c9cb3e1 --- /dev/null +++ b/src/hooks/useInvalidateTags.ts @@ -0,0 +1,28 @@ +import { useCallback } from 'react' +import announcementApi from 'services/announcement' +import limitOrderApi from 'services/limitOrder' + +import kyberAIApi from 'pages/TrueSightV2/hooks/useKyberAIData' +import { useAppDispatch } from 'state/hooks' + +const useInvalidateTags = (api: any) => { + const dispatch = useAppDispatch() + return useCallback( + (tag: string | string[]) => { + dispatch(api.util.invalidateTags(Array.isArray(tag) ? tag : [tag])) + }, + [dispatch, api], + ) +} + +export const useInvalidateTagAnnouncement = () => { + return useInvalidateTags(announcementApi) +} + +export const useInvalidateTagKyberAi = () => { + return useInvalidateTags(kyberAIApi) +} + +export const useInvalidateTagLimitOrder = () => { + return useInvalidateTags(limitOrderApi) +} diff --git a/src/hooks/useLogin.tsx b/src/hooks/useLogin.tsx index 556937ed93..2c492a0f31 100644 --- a/src/hooks/useLogin.tsx +++ b/src/hooks/useLogin.tsx @@ -31,11 +31,15 @@ import { filterTruthy, isAddress } from 'utils' import { setLoginRedirectUrl } from 'utils/redirectUponLogin' import { isEmailValid } from 'utils/string' -KyberOauth2.initialize({ - clientId: OAUTH_CLIENT_ID, - redirectUri: `${window.location.protocol}//${window.location.host}${APP_PATHS.VERIFY_AUTH}`, - mode: ENV_KEY, -}) +export const initializeOauthKyberSwap = () => { + KyberOauth2.initialize({ + clientId: OAUTH_CLIENT_ID, + redirectUri: `${window.location.protocol}//${window.location.host}${APP_PATHS.VERIFY_AUTH}`, + mode: ENV_KEY, + }) +} + +initializeOauthKyberSwap() const useLogin = (autoLogin = false) => { const { account, chainId, isEVM } = useActiveWeb3React() @@ -166,6 +170,7 @@ const useLogin = (autoLogin = false) => { const redirectSignIn = useCallback( (account: string) => { + if (window.location.pathname.startsWith(APP_PATHS.IAM_LOGIN)) return setLoginRedirectUrl(window.location.href) KyberOauth2.authenticate(isEVM ? { wallet_address: account } : {}) // navigate to login page }, diff --git a/src/pages/About/AboutKyberSwap/index.tsx b/src/pages/About/AboutKyberSwap/index.tsx index 7db120d347..42dc9950c2 100644 --- a/src/pages/About/AboutKyberSwap/index.tsx +++ b/src/pages/About/AboutKyberSwap/index.tsx @@ -1017,6 +1017,11 @@ function AboutKyberSwap() { alt="Base" width="100%" /> + Sroll diff --git a/src/pages/Campaign/CampaignContent.tsx b/src/pages/Campaign/CampaignContent.tsx index 27a96703e6..c43b010e8a 100644 --- a/src/pages/Campaign/CampaignContent.tsx +++ b/src/pages/Campaign/CampaignContent.tsx @@ -1,6 +1,6 @@ import { Trans, t } from '@lingui/macro' import dayjs from 'dayjs' -import { useEffect, useMemo, useRef, useState } from 'react' +import { useCallback, useEffect, useMemo, useRef, useState } from 'react' import { isMobile } from 'react-device-detect' import { BarChart, ChevronDown, Clock, Share2, Star, Users } from 'react-feather' import { useSelector } from 'react-redux' @@ -8,7 +8,6 @@ import { useNavigate } from 'react-router-dom' import { useMedia } from 'react-use' import { Flex, Text } from 'rebass' import styled, { css } from 'styled-components' -import { useSWRConfig } from 'swr' import { ButtonEmpty, ButtonLight } from 'components/Button' import Divider from 'components/Divider' @@ -18,7 +17,6 @@ import ProgressBar from 'components/ProgressBar' import ShareModal from 'components/ShareModal' import { MouseoverTooltip, TextDashed } from 'components/Tooltip' import YourCampaignTransactionsModal from 'components/YourCampaignTransactionsModal' -import { SWR_KEYS } from 'constants/index' import { useActiveWeb3React, useWeb3React } from 'hooks' import useInterval from 'hooks/useInterval' import useMixpanel, { MIXPANEL_TYPE } from 'hooks/useMixpanel' @@ -57,6 +55,8 @@ import oembed2iframe from 'utils/oembed2iframe' import ModalSelectCampaign from './ModalSelectCampaign' +export const MINUTE_TO_REFRESH = 5 * 60 + const LoaderParagraphs = () => ( <> @@ -176,7 +176,7 @@ export default function Campaign({ refreshListCampaign, ...props }: CampaignProp const { mixpanelHandler } = useMixpanel() - const above768 = useMedia(`(min-width: ${MEDIA_WIDTHS.upToSmall}px)`) + const upToSmall = useMedia(`(min-width: ${MEDIA_WIDTHS.upToSmall}px)`) const campaignDetailImageRef = useRef(null) const [campaignDetailMediaLoadedMap, setCampaignDetailMediaLoadedMap] = useState<{ [id: string]: boolean }>({}) @@ -313,9 +313,12 @@ export default function Campaign({ refreshListCampaign, ...props }: CampaignProp const toggleSelectCampaignModal = useSelectCampaignModalToggle() const navigate = useNavigate() - const onSelectCampaign = (campaign: CampaignData) => { - navigate(getSlugUrlCampaign(campaign.id, campaign.name)) - } + const onSelectCampaign = useCallback( + (campaign: CampaignData) => { + navigate(getSlugUrlCampaign(campaign.id, campaign.name)) + }, + [navigate], + ) const now = Date.now() @@ -323,13 +326,9 @@ export default function Campaign({ refreshListCampaign, ...props }: CampaignProp loadingCampaignData, loadingCampaignDataError, data: campaigns, - selectedCampaignLeaderboardPageNumber, - selectedCampaignLeaderboardLookupAddress, } = useSelector((state: AppState) => state.campaigns) - const MINUTE_TO_REFRESH = 5 - const [campaignsRefreshIn, setCampaignsRefreshIn] = useState(MINUTE_TO_REFRESH * 60) - const { mutate } = useSWRConfig() + const [campaignsRefreshIn, setCampaignsRefreshIn] = useState(MINUTE_TO_REFRESH) const dispatch = useAppDispatch() useInterval( () => { @@ -339,10 +338,7 @@ export default function Campaign({ refreshListCampaign, ...props }: CampaignProp setCampaignData({ campaigns: campaigns.map(campaign => { if (campaign.id === selectedCampaign.id) { - return { - ...campaign, - status, - } + return { ...campaign, status } } return campaign }), @@ -364,36 +360,12 @@ export default function Campaign({ refreshListCampaign, ...props }: CampaignProp ) { updateCampaignStatus(CampaignStatus.ENDED) } - setCampaignsRefreshIn(prev => { - if (prev === 0) { - return MINUTE_TO_REFRESH * 60 - } - return prev - 1 - }) + setCampaignsRefreshIn(prev => (prev === 0 ? MINUTE_TO_REFRESH : prev - 1)) }, selectedCampaign?.campaignState === CampaignState.CampaignStateReady ? 1000 : null, true, ) - useEffect(() => { - if (campaignsRefreshIn === 0 && selectedCampaign) { - mutate([ - selectedCampaign, - SWR_KEYS.getLeaderboard(selectedCampaign.id), - selectedCampaignLeaderboardPageNumber, - selectedCampaignLeaderboardLookupAddress, - account, - ]) - } - }, [ - mutate, - campaignsRefreshIn, - selectedCampaign, - selectedCampaignLeaderboardPageNumber, - selectedCampaignLeaderboardLookupAddress, - account, - ]) - if (campaigns.length === 0 && loadingCampaignData) { return } @@ -409,218 +381,214 @@ export default function Campaign({ refreshListCampaign, ...props }: CampaignProp return ( <> - - - - - - - - - - Campaigns - - - - - - - - - - - - - { - setTimeout(() => { - if (selectedCampaign) - setCampaignDetailMediaLoadedMap(prev => ({ ...prev, [selectedCampaign.id]: true })) - }, 500) - }} - onError={() => { + + + + + + + + + Campaigns + + + + + + + + + + + + + { + setTimeout(() => { if (selectedCampaign) setCampaignDetailMediaLoadedMap(prev => ({ ...prev, [selectedCampaign.id]: true })) - if (campaignDetailImageRef && campaignDetailImageRef.current) { - campaignDetailImageRef.current.style.display = 'none' - } - }} + }, 500) + }} + onError={() => { + if (selectedCampaign) + setCampaignDetailMediaLoadedMap(prev => ({ ...prev, [selectedCampaign.id]: true })) + if (campaignDetailImageRef && campaignDetailImageRef.current) { + campaignDetailImageRef.current.style.display = 'none' + } + }} + /> + + + + {selectedCampaign?.name} + + + + + + + + mixpanelHandler(MIXPANEL_TYPE.CAMPAIGN_SHARE_TRADING_CONTEST_CLICKED, { + campaign_name: selectedCampaign?.name, + }) + } /> - - - - {selectedCampaign?.name} + + + + + + {selectedCampaign?.status === CampaignStatus.UPCOMING + ? t`Starting In` + : isOngoing + ? t`Ending In` + : t`Ended On`} - - - - - - - mixpanelHandler(MIXPANEL_TYPE.CAMPAIGN_SHARE_TRADING_CONTEST_CLICKED, { - campaign_name: selectedCampaign?.name, - }) - } - /> - - - - - - {selectedCampaign?.status === CampaignStatus.UPCOMING - ? t`Starting In` - : isOngoing - ? t`Ending In` - : t`Ended On`} + + {isSelectedCampaignMediaLoaded ? ( + <> + {selectedCampaign.status === CampaignStatus.UPCOMING && ( + + + {selectedCampaign + ? getFormattedTimeFromSecond((selectedCampaign.startTime - now) / 1000) + : '--'} + + + )} + {selectedCampaign.status === CampaignStatus.ONGOING && ( + + + {selectedCampaign ? getFormattedTimeFromSecond((selectedCampaign.endTime - now) / 1000) : '--'} + + + )} + {selectedCampaign.status === CampaignStatus.ENDED && ( + + {dayjs(selectedCampaign.endTime).format('YYYY-MM-DD HH:mm')} + + )} + + ) : ( + + )} + + + + Participants + + {!isMobile && } + {isSelectedCampaignMediaLoaded ? ( + + {selectedCampaignLeaderboard?.totalParticipants + ? formatNumberWithPrecisionRange(selectedCampaignLeaderboard.totalParticipants, 0, 0) + : '--'} - - {isSelectedCampaignMediaLoaded ? ( - <> - {selectedCampaign.status === CampaignStatus.UPCOMING && ( - - - {selectedCampaign - ? getFormattedTimeFromSecond((selectedCampaign.startTime - now) / 1000) - : '--'} - - - )} - {selectedCampaign.status === CampaignStatus.ONGOING && ( - - - {selectedCampaign - ? getFormattedTimeFromSecond((selectedCampaign.endTime - now) / 1000) - : '--'} - - - )} - {selectedCampaign.status === CampaignStatus.ENDED && ( - - {dayjs(selectedCampaign.endTime).format('YYYY-MM-DD HH:mm')} + ) : ( + + )} + + + + Your Rank + {isMobile && } + + {!isMobile && } + {isSelectedCampaignMediaLoaded ? ( + account ? ( + + + + {selectedCampaign?.userInfo?.rankNo + ? formatNumberWithPrecisionRange(selectedCampaign?.userInfo?.rankNo, 0, 2) + : '--'} - )} - - ) : ( - - )} - - - - Participants - - {!isMobile && } - {isSelectedCampaignMediaLoaded ? ( - - {selectedCampaignLeaderboard?.totalParticipants - ? formatNumberWithPrecisionRange(selectedCampaignLeaderboard.totalParticipants, 0, 0) - : '--'} - - ) : ( - - )} - - - - Your Rank - {isMobile && } - - {!isMobile && } - {isSelectedCampaignMediaLoaded ? ( - account ? ( - - - - {selectedCampaign?.userInfo?.rankNo - ? formatNumberWithPrecisionRange(selectedCampaign?.userInfo?.rankNo, 0, 2) - : '--'} - - {!isMobile && } - - - {above768 ? Your Transactions : History} - + {!isMobile && } - ) : ( - - Connect - - ) + + {upToSmall ? Your Transactions : History} + + ) : ( - - )} - - - - - setActiveTab(CampaignTab.HOW_TO_WIN)} - > - How to win - - setActiveTab(CampaignTab.REWARDS)} - > - Rewards - + + Connect + + ) + ) : ( + + )} + + + + + setActiveTab(CampaignTab.HOW_TO_WIN)} + > + How to win + + setActiveTab(CampaignTab.REWARDS)} + > + Rewards + + setActiveTab(CampaignTab.LEADERBOARD)} + > + Leaderboard + + {selectedCampaign && selectedCampaign.campaignState === CampaignState.CampaignStateDistributedRewards && ( setActiveTab(CampaignTab.LEADERBOARD)} + active={activeTab === CampaignTab.LUCKY_WINNER} + onClick={() => setActiveTab(CampaignTab.LUCKY_WINNER)} > - Leaderboard + Lucky Winners - {selectedCampaign && selectedCampaign.campaignState === CampaignState.CampaignStateDistributedRewards && ( - setActiveTab(CampaignTab.LUCKY_WINNER)} - > - Lucky Winners - - )} - + )} + - - {activeTab === CampaignTab.HOW_TO_WIN && } - {activeTab === CampaignTab.REWARDS && } - {activeTab === CampaignTab.LEADERBOARD && ( - - )} - {activeTab === CampaignTab.LUCKY_WINNER && ( - - )} - - - + + {activeTab === CampaignTab.HOW_TO_WIN && } + {activeTab === CampaignTab.REWARDS && } + {activeTab === CampaignTab.LEADERBOARD && ( + + )} + {activeTab === CampaignTab.LUCKY_WINNER && ( + + )} + + @@ -753,7 +721,9 @@ const PageWrapper = styled.div` padding: 32px 24px 50px; width: 100%; max-width: 1500px; - + display: flex; + gap: 24px; + min-height: calc(100vh - 84.34px - 24px - 24px - 62px); ${({ theme }) => theme.mediaWidth.upToSmall` ${css` padding: 24px 16px 100px; @@ -761,13 +731,6 @@ const PageWrapper = styled.div` `} ` -const CampaignContainer = styled.div` - display: flex; - gap: 24px; - min-height: calc(100vh - 84.34px - 24px - 24px - 62px); - overflow: auto; -` - const CampaignDetail = styled.div` flex: 2; overflow: auto; diff --git a/src/pages/Campaign/CampaignListAndSearch.tsx b/src/pages/Campaign/CampaignListAndSearch.tsx index c75ca9c18a..7457b1ccf4 100644 --- a/src/pages/Campaign/CampaignListAndSearch.tsx +++ b/src/pages/Campaign/CampaignListAndSearch.tsx @@ -1,5 +1,5 @@ import { Trans, t } from '@lingui/macro' -import { useCallback, useEffect, useRef, useState } from 'react' +import { memo, useCallback, useEffect, useRef, useState } from 'react' import { useSelector } from 'react-redux' import AutoSizer from 'react-virtualized-auto-sizer' import { VariableSizeList } from 'react-window' @@ -172,4 +172,4 @@ const CampaignListAndSearch = ({ ) } -export default CampaignListAndSearch +export default memo(CampaignListAndSearch) diff --git a/src/pages/Campaign/LeaderboardLayout.tsx b/src/pages/Campaign/LeaderboardLayout.tsx index 80ff77ca21..5e7b669170 100644 --- a/src/pages/Campaign/LeaderboardLayout.tsx +++ b/src/pages/Campaign/LeaderboardLayout.tsx @@ -1,11 +1,12 @@ import { Trans, t } from '@lingui/macro' import dayjs from 'dayjs' import { rgba } from 'polished' -import { useEffect } from 'react' +import { useEffect, useState } from 'react' import { Clock } from 'react-feather' import { useSelector } from 'react-redux' import { useMedia, useSize } from 'react-use' import { Flex, Text } from 'rebass' +import { useGetLuckyWinnersQuery } from 'services/campaign' import styled, { css } from 'styled-components' import Bronze from 'assets/svg/bronze_icon.svg' @@ -14,15 +15,13 @@ import Silver from 'assets/svg/silver_icon.svg' import InfoHelper from 'components/InfoHelper' import Pagination from 'components/Pagination' import Search, { Container as SearchContainer, Wrapper as SearchWrapper } from 'components/Search' -import { BIG_INT_ZERO, CAMPAIGN_LEADERBOARD_ITEM_PER_PAGE, DEFAULT_SIGNIFICANT } from 'constants/index' +import { BIG_INT_ZERO, CAMPAIGN_LEADERBOARD_ITEM_PER_PAGE, DEFAULT_SIGNIFICANT, EMPTY_ARRAY } from 'constants/index' import useTheme from 'hooks/useTheme' import { AppState } from 'state' import { CampaignState, CampaignStatus, RewardRandom } from 'state/campaigns/actions' import { useSelectedCampaignLeaderboardLookupAddressManager, useSelectedCampaignLeaderboardPageNumberManager, - useSelectedCampaignLuckyWinnerPageNumber, - useSelectedCampaignLuckyWinnersLookupAddressManager, } from 'state/campaigns/hooks' import { formatNumberWithPrecisionRange } from 'utils' import getShortenAddress from 'utils/getShortenAddress' @@ -48,35 +47,44 @@ export default function LeaderboardLayout({ )) - const { selectedCampaignLeaderboard, selectedCampaignLuckyWinners, selectedCampaign } = useSelector( - (state: AppState) => state.campaigns, - ) - - const [currentPage, setCurrentPage] = useSelectedCampaignLeaderboardPageNumberManager() - const [currentPageLuckyWinner, setCurrentPageLuckyWinner] = useSelectedCampaignLuckyWinnerPageNumber() + const { selectedCampaignLeaderboard, selectedCampaign } = useSelector((state: AppState) => state.campaigns) const [leaderboardSearchValue, setLeaderboardSearchValue] = useSelectedCampaignLeaderboardLookupAddressManager() - const [luckyWinnersSearchValue, setLuckyWinnersSearchValue] = useSelectedCampaignLuckyWinnersLookupAddressManager() + + const [luckyWinnersSearchValue, setLuckyWinnersSearchValue] = useState('') + const [searchValue, setSearchValue] = type === 'leaderboard' ? [leaderboardSearchValue, setLeaderboardSearchValue] : [luckyWinnersSearchValue, setLuckyWinnersSearchValue] + const [currentPageLuckyWinner, setCurrentPageLuckyWinner] = useState(0) + const { currentData: dataLuckWinners } = useGetLuckyWinnersQuery( + { + pageSize: CAMPAIGN_LEADERBOARD_ITEM_PER_PAGE, + pageNumber: currentPageLuckyWinner, + lookupAddress: luckyWinnersSearchValue, + campaignId: selectedCampaign?.id || 0, + }, + { skip: !selectedCampaign?.id }, + ) + + const luckyWinners = + (selectedCampaign?.campaignState === CampaignState.CampaignStateReady ? EMPTY_ARRAY : dataLuckWinners) || + EMPTY_ARRAY + + const [currentPage, setCurrentPage] = useSelectedCampaignLeaderboardPageNumberManager() let totalItems = 0 - if (type === 'leaderboard') { - if (selectedCampaignLeaderboard) { - totalItems = leaderboardSearchValue ? 1 : selectedCampaignLeaderboard.totalParticipants - } + if (type === 'leaderboard' && selectedCampaignLeaderboard) { + totalItems = leaderboardSearchValue ? 1 : selectedCampaignLeaderboard.totalParticipants } - if (type === 'lucky_winner') { - if (selectedCampaign && selectedCampaignLeaderboard) { - const randomRewards = selectedCampaign.rewardDistribution.filter(reward => reward.type === 'Random') - const totalRandomRewardItems = randomRewards.reduce( - (acc, reward) => acc + ((reward as RewardRandom).nWinners ?? 0), - 0, - ) - - totalItems = searchValue ? 1 : Math.min(totalRandomRewardItems, selectedCampaignLeaderboard.totalParticipants) - } + if (type === 'lucky_winner' && selectedCampaign && selectedCampaignLeaderboard) { + const randomRewards = selectedCampaign.rewardDistribution.filter(reward => reward.type === 'Random') + const totalRandomRewardItems = randomRewards.reduce( + (acc, reward) => acc + ((reward as RewardRandom).nWinners ?? 0), + 0, + ) + + totalItems = searchValue ? 1 : Math.min(totalRandomRewardItems, selectedCampaignLeaderboard.totalParticipants) } const refreshInMinute = Math.floor(refreshIn / 60) @@ -143,7 +151,7 @@ export default function LeaderboardLayout({ ) }) - const luckyWinnersTableBody = selectedCampaignLuckyWinners.map((luckyWinner, index) => { + const luckyWinnersTableBody = luckyWinners.map((luckyWinner, index) => { return ( diff --git a/src/pages/Campaign/ModalRegisterCampaignCaptcha.tsx b/src/pages/Campaign/ModalRegisterCampaignCaptcha.tsx index 49a28fef71..5c1cb04d74 100644 --- a/src/pages/Campaign/ModalRegisterCampaignCaptcha.tsx +++ b/src/pages/Campaign/ModalRegisterCampaignCaptcha.tsx @@ -1,13 +1,12 @@ import { Trans } from '@lingui/macro' -import axios from 'axios' import { createRef, memo, useCallback } from 'react' import ReCAPTCHA from 'react-google-recaptcha' import { Text } from 'rebass' +import { useJoinCampaignMutation } from 'services/campaign' import styled from 'styled-components' import { ModalCenter } from 'components/Modal' import { GOOGLE_RECAPTCHA_KEY } from 'constants/env' -import { CAMPAIGN_BASE_URL } from 'constants/index' import { useActiveWeb3React } from 'hooks' import useTheme from 'hooks/useTheme' import { ApplicationModal } from 'state/application/actions' @@ -44,7 +43,7 @@ const ModalRegisterCampaignCaptcha = ({ refreshListCampaign }: { refreshListCamp const theme = useTheme() const { account } = useActiveWeb3React() - + const [joinCampaign] = useJoinCampaignMutation() // Create an event handler, so you can call the verification on button click event or form submit const handleReCaptchaVerify = useCallback(async () => { if (!recaptchaCampaign.id || !account) return @@ -64,18 +63,13 @@ const ModalRegisterCampaignCaptcha = ({ refreshListCampaign }: { refreshListCamp const token = await recaptchaRef.current.getValue() await new Promise(r => setTimeout(r, 750)) toggleRegisterCampaignCaptchaModal() - const response = await axios({ - method: 'POST', - url: `${CAMPAIGN_BASE_URL}/${recaptchaCampaign.id}/participants`, - data: { - token, - address: account, - }, - }) - if (response.status === 200) { - refreshListCampaign() - toggleRegisterCampaignSuccessModal() - } + await joinCampaign({ + token, + address: account, + recaptchaId: recaptchaCampaign.id, + }).unwrap() + refreshListCampaign() + toggleRegisterCampaignSuccessModal() } catch (err) { console.error(err) } finally { @@ -91,6 +85,7 @@ const ModalRegisterCampaignCaptcha = ({ refreshListCampaign }: { refreshListCamp updateRecaptchaCampaignId, updateRecaptchaCampaignLoading, refreshListCampaign, + joinCampaign, ]) return ( diff --git a/src/pages/Campaign/ModalSelectCampaign.tsx b/src/pages/Campaign/ModalSelectCampaign.tsx index 6d5d8cb6f0..52510faf5e 100644 --- a/src/pages/Campaign/ModalSelectCampaign.tsx +++ b/src/pages/Campaign/ModalSelectCampaign.tsx @@ -27,7 +27,7 @@ const ModalSelectCampaign = (props: { }, 200) } return ( - +
diff --git a/src/pages/Campaign/index.tsx b/src/pages/Campaign/index.tsx index 77057cdc1f..7f073f2521 100644 --- a/src/pages/Campaign/index.tsx +++ b/src/pages/Campaign/index.tsx @@ -1,113 +1,28 @@ -import { ZERO } from '@kyberswap/ks-sdk-classic' -import { Fraction } from '@kyberswap/ks-sdk-core' -import axios from 'axios' -import { parseUnits } from 'ethers/lib/utils' -import JSBI from 'jsbi' -import { stringify } from 'querystring' import { useCallback, useEffect, useState } from 'react' import { useDispatch, useSelector } from 'react-redux' import { useLocation, useNavigate } from 'react-router-dom' -import useSWR, { mutate } from 'swr' -import useSWRImmutable from 'swr/immutable' +import { useGetCampaignsQuery, useGetLeaderboardQuery } from 'services/campaign' -import { APP_PATHS, CAMPAIGN_LEADERBOARD_ITEM_PER_PAGE, RESERVE_USD_DECIMALS, SWR_KEYS } from 'constants/index' +import { APP_PATHS, CAMPAIGN_LEADERBOARD_ITEM_PER_PAGE, EMPTY_ARRAY } from 'constants/index' import { useActiveWeb3React } from 'hooks' import useParsedQueryString from 'hooks/useParsedQueryString' import { - CampaignData, CampaignLeaderboard, - CampaignLeaderboardRanking, - CampaignLeaderboardReward, - CampaignLuckyWinner, - CampaignState, - CampaignStatus, - RewardDistribution, setCampaignDataByPage, setLastTimeRefreshData, setLoadingCampaignData, setLoadingCampaignDataError, setLoadingSelectedCampaignLeaderboard, - setLoadingSelectedCampaignLuckyWinners, setSelectedCampaign, setSelectedCampaignLeaderboard, - setSelectedCampaignLuckyWinners, } from 'state/campaigns/actions' import { AppState } from 'state/index' -import { SerializedToken } from 'state/user/actions' import { getCampaignIdFromSlug, getSlugUrlCampaign } from 'utils/campaign' -import CampaignContent from './CampaignContent' +import CampaignContent, { MINUTE_TO_REFRESH } from './CampaignContent' const MAXIMUM_ITEMS_PER_REQUEST = 10 -const getCampaignStatus = ({ endTime, startTime }: CampaignData) => { - const now = Date.now() - return endTime <= now ? CampaignStatus.ENDED : startTime >= now ? CampaignStatus.UPCOMING : CampaignStatus.ONGOING -} - -const formatRewards = (rewards: CampaignLeaderboardReward[]) => - rewards?.map( - (item: any): CampaignLeaderboardReward => ({ - rewardAmount: new Fraction( - item.RewardAmount, - JSBI.exponentiate(JSBI.BigInt(10), JSBI.BigInt(item?.Token?.decimals ?? 18)), - ), - ref: item.Ref, - claimed: item.Claimed, - token: item.Token, - }), - ) || [] - -const formatLeaderboardData = (data: CampaignLeaderboard) => { - const leaderboard: CampaignLeaderboard = { - ...data, - rankings: data.rankings - ? data.rankings.map( - (item: any): CampaignLeaderboardRanking => ({ - userAddress: item.userAddress, - totalPoint: item.totalPoint, - rankNo: item.rankNo, - rewardAmount: new Fraction( - item.rewardAmount || ZERO, - JSBI.exponentiate(JSBI.BigInt(10), JSBI.BigInt(item?.token?.decimals ?? 18)), - ), - rewardAmountUsd: new Fraction( - parseUnits(item?.rewardAmountUSD?.toString() || '0', RESERVE_USD_DECIMALS).toString(), - JSBI.exponentiate(JSBI.BigInt(10), JSBI.BigInt(RESERVE_USD_DECIMALS)), - ), - rewardInUSD: item.rewardInUSD, - token: item.token, - }), - ) - : [], - rewards: formatRewards(data.rewards), - } - return leaderboard -} - -const fetchLeaderBoard = ({ - pageNumber, - userAddress, - lookupAddress, - campaignId, -}: { - pageNumber: number - userAddress: string - lookupAddress: string - campaignId: number -}) => { - return axios({ - method: 'GET', - url: SWR_KEYS.getLeaderboard(campaignId), - params: { - pageSize: CAMPAIGN_LEADERBOARD_ITEM_PER_PAGE, - pageNumber, - userAddress, - lookupAddress, - }, - }).then(({ data }) => formatLeaderboardData(data.data)) -} - const LEADERBOARD_DEFAULT: CampaignLeaderboard = { finalizedAt: 0, distributedRewardsAt: 0, @@ -117,115 +32,6 @@ const LEADERBOARD_DEFAULT: CampaignLeaderboard = { rewards: [], } -const formatListCampaign = (response: CampaignData[]) => { - const campaigns: CampaignData[] = response.map((item: CampaignData) => ({ - ...item, - startTime: item.startTime * 1000, - endTime: item.endTime * 1000, - })) - const formattedCampaigns: CampaignData[] = campaigns.map((campaign: any) => { - const rewardDistribution: RewardDistribution[] = [] - if (campaign.rewardDistribution.single) { - campaign.rewardDistribution.single.forEach( - ({ - amount, - rank, - token, - rewardInUSD, - }: { - amount: string - rank: number - token: SerializedToken - rewardInUSD: boolean - }) => { - rewardDistribution.push({ - type: 'Single', - amount, - rank, - token, - rewardInUSD, - }) - }, - ) - } - if (campaign.rewardDistribution.range) { - campaign.rewardDistribution.range.forEach( - ({ - from, - to, - amount, - token, - rewardInUSD, - }: { - from: number - to: number - amount: string - token: SerializedToken - rewardInUSD: boolean - }) => { - rewardDistribution.push({ - type: 'Range', - from, - to, - amount, - token, - rewardInUSD, - }) - }, - ) - } - if (campaign.rewardDistribution.random) { - campaign.rewardDistribution.random.forEach( - ({ - from, - to, - amount, - numberOfWinners, - token, - rewardInUSD, - }: { - from: number - to: number - amount: string - numberOfWinners: number - token: SerializedToken - rewardInUSD: boolean - }) => { - rewardDistribution.push({ - type: 'Random', - from, - to, - amount, - nWinners: numberOfWinners, - token, - rewardInUSD, - }) - }, - ) - } - if (campaign?.userInfo?.tradingVolume) campaign.userInfo.tradingVolume = Number(campaign.userInfo.tradingVolume) - if (campaign.userInfo) campaign.userInfo.rewards = formatRewards(campaign.userInfo.rewards) - return { - ...campaign, - rewardDistribution, - status: getCampaignStatus(campaign), - eligibleTokens: campaign.eligibleTokens.map( - ({ chainId, name, symbol, address, logoURI, decimals }: SerializedToken) => { - return { - chainId, - name, - symbol, - address, - logoURI, - decimals, - } - }, - ), - } - }) - return formattedCampaigns -} - const getQueryDefault = (userAddress: string | undefined) => ({ campaignName: '', userAddress, @@ -247,7 +53,6 @@ export default function CampaignsUpdater() { }, []) const { data: currentCampaigns } = useSelector((state: AppState) => state.campaigns) - const getCampaignUrl = useCallback(() => `${SWR_KEYS.getListCampaign}?${stringify(queryParams)}`, [queryParams]) const loadMoreCampaign = useCallback(() => { if (!currentCampaigns.length) return @@ -259,24 +64,22 @@ export default function CampaignsUpdater() { }, [account, setQueryParams]) const { - data: campaignData, - isValidating: isLoadingCampaignData, + data: campaignData = EMPTY_ARRAY, + isFetching: isLoadingCampaignData, error: loadingCampaignDataError, - } = useSWR(getCampaignUrl(), async url => { - try { - const { data: response } = await axios.get(url) - const campaigns: CampaignData[] = response.data - setHasMoreCampaign(campaigns.length === MAXIMUM_ITEMS_PER_REQUEST) - return formatListCampaign(campaigns) - } catch (error) { - return [] - } - }) + refetch, + } = useGetCampaignsQuery(queryParams) + + useEffect(() => { + setHasMoreCampaign(campaignData.length === MAXIMUM_ITEMS_PER_REQUEST) + }, [campaignData]) const refreshListCampaign = useCallback(async () => { - await mutate(getCampaignUrl()) - dispatch(setLastTimeRefreshData()) - }, [getCampaignUrl, dispatch]) + try { + await refetch().unwrap() + dispatch(setLastTimeRefreshData()) + } catch (error) {} + }, [refetch, dispatch]) const slug = pathname.replace(APP_PATHS.CAMPAIGN, '') const { selectedCampaignId = getCampaignIdFromSlug(slug) } = useParsedQueryString<{ selectedCampaignId: string }>() @@ -294,7 +97,7 @@ export default function CampaignsUpdater() { replace: true, }) } - if (selectedCampaignId === undefined) { + if (!selectedCampaignId) { navigateFirsOne() return } @@ -311,7 +114,7 @@ export default function CampaignsUpdater() { }, [dispatch, isLoadingCampaignData]) useEffect(() => { - dispatch(setLoadingCampaignDataError(loadingCampaignDataError)) + dispatch(setLoadingCampaignDataError(!!loadingCampaignDataError)) }, [dispatch, loadingCampaignDataError]) /**********************CAMPAIGN LEADERBOARD**********************/ @@ -319,33 +122,15 @@ export default function CampaignsUpdater() { const { selectedCampaignLeaderboardPageNumber, selectedCampaignLeaderboardLookupAddress, selectedCampaign } = useSelector((state: AppState) => state.campaigns) - const { data: leaderboard, isValidating: isLoadingLeaderboard } = useSWRImmutable( - selectedCampaign - ? [ - selectedCampaign, - SWR_KEYS.getLeaderboard(selectedCampaign.id), - selectedCampaignLeaderboardPageNumber, - selectedCampaignLeaderboardLookupAddress, - account, - ] - : null, - async () => { - if (!selectedCampaign) { - return LEADERBOARD_DEFAULT - } - - try { - return fetchLeaderBoard({ - campaignId: selectedCampaign.id, - pageNumber: selectedCampaignLeaderboardPageNumber, - userAddress: account ?? '', - lookupAddress: selectedCampaignLeaderboardLookupAddress, - }) - } catch (err) { - console.error(err) - return LEADERBOARD_DEFAULT - } + const { currentData: leaderboard = LEADERBOARD_DEFAULT, isFetching: isLoadingLeaderboard } = useGetLeaderboardQuery( + { + campaignId: selectedCampaign?.id || 0, + pageNumber: selectedCampaignLeaderboardPageNumber, + userAddress: account ?? '', + lookupAddress: selectedCampaignLeaderboardLookupAddress, + pageSize: CAMPAIGN_LEADERBOARD_ITEM_PER_PAGE, }, + { skip: !selectedCampaign?.id, pollingInterval: MINUTE_TO_REFRESH * 1000 }, ) useEffect(() => { @@ -358,63 +143,6 @@ export default function CampaignsUpdater() { dispatch(setLoadingSelectedCampaignLeaderboard(isLoadingLeaderboard)) }, [dispatch, isLoadingLeaderboard]) - /**********************CAMPAIGN LUCKY WINNERS**********************/ - - const { selectedCampaignLuckyWinnersPageNumber, selectedCampaignLuckyWinnersLookupAddress } = useSelector( - (state: AppState) => state.campaigns, - ) - - const { data: luckyWinners, isValidating: isLoadingLuckyWinners } = useSWRImmutable( - selectedCampaign - ? [ - selectedCampaign, - SWR_KEYS.getLuckyWinners(selectedCampaign.id), - selectedCampaignLuckyWinnersPageNumber, - selectedCampaignLuckyWinnersLookupAddress, - ] - : null, - async () => { - if (!selectedCampaign || selectedCampaign.campaignState === CampaignState.CampaignStateReady) return [] - - try { - const response = await axios({ - method: 'GET', - url: SWR_KEYS.getLuckyWinners(selectedCampaign.id), - params: { - pageSize: CAMPAIGN_LEADERBOARD_ITEM_PER_PAGE, - pageNumber: selectedCampaignLuckyWinnersPageNumber, - lookupAddress: selectedCampaignLuckyWinnersLookupAddress, - }, - }) - const data = response.data.data - const luckyWinners: CampaignLuckyWinner[] = data.map( - (item: any): CampaignLuckyWinner => ({ - userAddress: item.userAddress, - rewardAmount: new Fraction( - item.rewardAmount, - JSBI.exponentiate(JSBI.BigInt(10), JSBI.BigInt(item?.token?.decimals ?? 18)), - ), - token: item.token, - }), - ) - return luckyWinners - } catch (err) { - console.error(err) - return [] - } - }, - ) - - useEffect(() => { - if (luckyWinners !== undefined) { - dispatch(setSelectedCampaignLuckyWinners({ luckyWinners: luckyWinners })) - } - }, [dispatch, luckyWinners]) - - useEffect(() => { - dispatch(setLoadingSelectedCampaignLuckyWinners(isLoadingLuckyWinners)) - }, [dispatch, isLoadingLuckyWinners]) - return ( -
+
These Terms and Conditions should be read in conjunction with the KyberSwap{' '} - Terms of Use, which lay out the terms and conditions - that apply to all KyberSwap activities. + Terms of Use, which lay out + the terms and conditions that apply to all KyberSwap activities. @@ -290,7 +290,7 @@ export default function KNCUtility() { By visiting KyberSwap and participating in the program, the User is deemed to have read, understood, and agreed to these Terms and Conditions and the KyberSwap{' '} - Terms of Use. + Terms of Use. @@ -308,9 +308,10 @@ export default function KNCUtility() { KyberSwap maintains the right, at its sole discretion, to take action or remove rewards against - the User who violates the KyberSwap Terms of Use{' '} - and/or violates, cheats, or exploits the program, including but not limited to, any suspicious - activities, or any attempts to circumvent these Terms and Conditions. + the User who violates the KyberSwap{' '} + Terms of Use and/or violates, + cheats, or exploits the program, including but not limited to, any suspicious activities, or any + attempts to circumvent these Terms and Conditions. diff --git a/src/pages/KyberDAO/Vote/ProposalItem/VoteInformation.tsx b/src/pages/KyberDAO/Vote/ProposalItem/VoteInformation.tsx index 4611e32bb1..02181dc345 100644 --- a/src/pages/KyberDAO/Vote/ProposalItem/VoteInformation.tsx +++ b/src/pages/KyberDAO/Vote/ProposalItem/VoteInformation.tsx @@ -1,4 +1,4 @@ -import { Trans } from '@lingui/macro' +import { Trans, t } from '@lingui/macro' import dayjs from 'dayjs' import { useMemo } from 'react' import { Text } from 'rebass' @@ -74,6 +74,12 @@ export default function VoteInformation({ proposal }: { proposal: ProposalDetail {Math.floor(proposal.vote_stats.total_vote_count).toLocaleString()} + + + Quorum Status + + {proposal.vote_stats.quorum_status === 1 ? t`Reached` : t`Not Reached`} + Your KIP Voting Power{' '} diff --git a/src/pages/KyberDAO/Vote/index.tsx b/src/pages/KyberDAO/Vote/index.tsx index c0c671a9fd..48cf4090b6 100644 --- a/src/pages/KyberDAO/Vote/index.tsx +++ b/src/pages/KyberDAO/Vote/index.tsx @@ -117,7 +117,7 @@ export default function Vote() { claimedRewardAmount, stakerInfo, stakerInfoNextEpoch, - rewardStats: { knc, usd }, + rewardStats: { knc, usd, apr }, } = useVotingInfo() const kncPrice = useKNCPrice() @@ -237,12 +237,23 @@ export default function Vote() { - - Total Voting Rewards - - - {(+knc?.toFixed(0)).toLocaleString() ?? '--'} KNC - + + + Total Voting Rewards + + + APR + + + + + {(+knc?.toFixed(0)).toLocaleString() ?? '--'} KNC + + + {apr.toFixed(2) ?? '--'}% + + + ~{(+usd?.toFixed(0)).toLocaleString() ?? '--'} USD diff --git a/src/pages/NotificationCenter/PrivateAnnouncement.tsx b/src/pages/NotificationCenter/PrivateAnnouncement.tsx index 92e0f9c352..3fab236c2e 100644 --- a/src/pages/NotificationCenter/PrivateAnnouncement.tsx +++ b/src/pages/NotificationCenter/PrivateAnnouncement.tsx @@ -11,10 +11,10 @@ import styled from 'styled-components' import { PRIVATE_ANN_TITLE } from 'components/Announcement/PrivateAnnoucement' import InboxItemNotificationCenter from 'components/Announcement/PrivateAnnoucement/NotificationCenter' -import { useInvalidateTagAnnouncement } from 'components/Announcement/helper' import { PrivateAnnouncement, PrivateAnnouncementType } from 'components/Announcement/type' import { getAnnouncementsTemplateIds } from 'constants/env' import { useActiveWeb3React } from 'hooks' +import { useInvalidateTagAnnouncement } from 'hooks/useInvalidateTags' import DeleteAllAlertsButton from 'pages/NotificationCenter/DeleteAllAlertsButton' import NoData from 'pages/NotificationCenter/NoData' import CommonPagination from 'pages/NotificationCenter/PriceAlerts/CommonPagination' diff --git a/src/pages/Oauth/Login.tsx b/src/pages/Oauth/Login.tsx index ed807e4f62..4b0a288308 100644 --- a/src/pages/Oauth/Login.tsx +++ b/src/pages/Oauth/Login.tsx @@ -6,6 +6,7 @@ import Loader from 'components/Loader' import { didUserReject } from 'constants/connectors/utils' import { ENV_KEY } from 'constants/env' import { useActiveWeb3React, useWeb3React } from 'hooks' +import { initializeOauthKyberSwap } from 'hooks/useLogin' import useParsedQueryString from 'hooks/useParsedQueryString' import { Container, Content, KyberLogo, TextDesc } from 'pages/Oauth/styled' import getShortenAddress from 'utils/getShortenAddress' @@ -134,6 +135,11 @@ export function Login() { getFlowLogin() }, []) + useEffect(() => { + // user click to others page of kyberswap => reset config + return () => initializeOauthKyberSwap() + }, []) + const appName = authFormConfig?.oauth_client?.client_name || authFormConfig?.oauth_client?.client_id const renderEthMsg = () => diff --git a/src/pages/SwapV3/Tabs/LimitTab.tsx b/src/pages/SwapV3/Tabs/LimitTab.tsx index c46bd4b04c..59fe4c6cce 100644 --- a/src/pages/SwapV3/Tabs/LimitTab.tsx +++ b/src/pages/SwapV3/Tabs/LimitTab.tsx @@ -1,7 +1,6 @@ import { Trans } from '@lingui/macro' import { rgba } from 'polished' import { useLocation } from 'react-router-dom' -import { Text } from 'rebass' import { useGetNumberOfInsufficientFundOrdersQuery } from 'services/limitOrder' import styled from 'styled-components' @@ -45,22 +44,24 @@ export default function LimitTab({ onClick }: Props) { } return ( - - - Limit{' '} - {numberOfInsufficientFundOrders ? ( - - You have {numberOfInsufficientFundOrders} active orders that don't have sufficient funds - - } - > - {numberOfInsufficientFundOrders} - - ) : null} - + + Limit{' '} + {!!numberOfInsufficientFundOrders && ( + You have {numberOfInsufficientFundOrders} active orders that don't have sufficient funds + } + > + {numberOfInsufficientFundOrders} + + )} ) } diff --git a/src/pages/TrueSightV2/components/TokenFilter/WatchlistSelect.tsx b/src/pages/TrueSightV2/components/TokenFilter/WatchlistSelect.tsx index 769c363bb6..f2d040cef9 100644 --- a/src/pages/TrueSightV2/components/TokenFilter/WatchlistSelect.tsx +++ b/src/pages/TrueSightV2/components/TokenFilter/WatchlistSelect.tsx @@ -16,6 +16,7 @@ const Divider = styled.div` ` const CustomOption = styled(Row)` + cursor: pointer; :hover { background-color: ${({ theme }) => theme.background}; } diff --git a/src/pages/TrueSightV2/components/chart/index.tsx b/src/pages/TrueSightV2/components/chart/index.tsx index bada9126fa..935c25bc02 100644 --- a/src/pages/TrueSightV2/components/chart/index.tsx +++ b/src/pages/TrueSightV2/components/chart/index.tsx @@ -2781,9 +2781,8 @@ export const Prochart = ({ const subscriptionDataLoaded = tvWidget?.activeChart()?.onDataLoaded() subscriptionDataLoaded?.subscribe(null, handleDataLoaded, true) - if (!showSRLevels) { - removeSRLevels() - } else { + removeSRLevels() + if (showSRLevels) { addSRLevels() } } catch (error) {} diff --git a/src/pages/TrueSightV2/pages/RegisterWhitelist/index.tsx b/src/pages/TrueSightV2/pages/RegisterWhitelist/index.tsx index b7dfeaeb18..28d4245171 100644 --- a/src/pages/TrueSightV2/pages/RegisterWhitelist/index.tsx +++ b/src/pages/TrueSightV2/pages/RegisterWhitelist/index.tsx @@ -10,7 +10,6 @@ import Column from 'components/Column' import DownloadWalletModal from 'components/DownloadWalletModal' import Row from 'components/Row' import { APP_PATHS } from 'constants/index' -import { useActiveWeb3React } from 'hooks' import useLogin from 'hooks/useLogin' import { MIXPANEL_TYPE, useMixpanelKyberAI } from 'hooks/useMixpanel' import useTheme from 'hooks/useTheme' @@ -18,7 +17,7 @@ import SubscribeForm from 'pages/TrueSightV2/pages/RegisterWhitelist/SubscribeFo import WaitListForm from 'pages/TrueSightV2/pages/RegisterWhitelist/WaitListForm' import VerifyCodeModal from 'pages/Verify/VerifyCodeModal' import { ApplicationModal } from 'state/application/actions' -import { useOpenModal, useWalletModalToggle } from 'state/application/hooks' +import { useOpenModal } from 'state/application/hooks' import { useSessionInfo } from 'state/authen/hooks' import { useIsWhiteListKyberAI } from 'state/user/hooks' import { ButtonText } from 'theme' @@ -32,8 +31,6 @@ export default function RegisterWhitelist({ showForm = true }: { showForm?: bool const navigate = useNavigate() const theme = useTheme() const mixpanelHandler = useMixpanelKyberAI() - const { account } = useActiveWeb3React() - const toggleWalletModal = useWalletModalToggle() const { isLogin } = useSessionInfo() const { signIn } = useLogin() @@ -67,7 +64,7 @@ export default function RegisterWhitelist({ showForm = true }: { showForm?: bool <> @@ -99,11 +96,11 @@ export default function RegisterWhitelist({ showForm = true }: { showForm?: bool ) - if (!account) + if (!isLogin) return ( - - Sign in with wallet + signIn()}> + Sign-In to Continue Don't have a wallet? @@ -115,13 +112,6 @@ export default function RegisterWhitelist({ showForm = true }: { showForm?: bool ) - if (!isLogin) - return ( - signIn()}> - Sign-In to Continue - - ) - const btnGetStart = ( { diff --git a/src/pages/TrueSightV2/pages/TechnicalAnalysis.tsx b/src/pages/TrueSightV2/pages/TechnicalAnalysis.tsx index 5be2aa2547..1686aa0557 100644 --- a/src/pages/TrueSightV2/pages/TechnicalAnalysis.tsx +++ b/src/pages/TrueSightV2/pages/TechnicalAnalysis.tsx @@ -96,7 +96,7 @@ export default function TechnicalAnalysis() { candleSize: priceChartResolution, currency: liveChartTab === ChartTab.First ? 'USD' : 'BTC', }, - { skip: !chain || !address }, + { skip: !chain || !address, pollingInterval: 60000 }, ) const SRLevels: ISRLevel[] = useMemo(() => { diff --git a/src/services/campaign.ts b/src/services/campaign.ts new file mode 100644 index 0000000000..e7440c4ffa --- /dev/null +++ b/src/services/campaign.ts @@ -0,0 +1,260 @@ +import { ZERO } from '@kyberswap/ks-sdk-classic' +import { Fraction } from '@kyberswap/ks-sdk-core' +import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query/react' +import { parseUnits } from 'ethers/lib/utils' +import JSBI from 'jsbi' + +import { CAMPAIGN_BASE_URL } from 'constants/env' +import { RESERVE_USD_DECIMALS } from 'constants/index' +import { + CampaignData, + CampaignLeaderboard, + CampaignLeaderboardRanking, + CampaignLeaderboardReward, + CampaignLuckyWinner, + CampaignProofData, + CampaignStatus, + RewardDistribution, +} from 'state/campaigns/actions' +import { SerializedToken } from 'state/user/actions' + +const getCampaignStatus = ({ endTime, startTime }: CampaignData) => { + const now = Date.now() + return endTime <= now ? CampaignStatus.ENDED : startTime >= now ? CampaignStatus.UPCOMING : CampaignStatus.ONGOING +} + +const formatRewards = (rewards: CampaignLeaderboardReward[]) => + rewards?.map( + (item: any): CampaignLeaderboardReward => ({ + rewardAmount: new Fraction( + item.RewardAmount, + JSBI.exponentiate(JSBI.BigInt(10), JSBI.BigInt(item?.Token?.decimals ?? 18)), + ), + ref: item.Ref, + claimed: item.Claimed, + token: item.Token, + }), + ) || [] + +const formatListCampaign = (response: CampaignData[]) => { + const campaigns: CampaignData[] = response.map((item: CampaignData) => ({ + ...item, + startTime: item.startTime * 1000, + endTime: item.endTime * 1000, + })) + const formattedCampaigns: CampaignData[] = campaigns.map((campaign: any) => { + const rewardDistribution: RewardDistribution[] = [] + if (campaign.rewardDistribution.single) { + campaign.rewardDistribution.single.forEach( + ({ + amount, + rank, + token, + rewardInUSD, + }: { + amount: string + rank: number + token: SerializedToken + rewardInUSD: boolean + }) => { + rewardDistribution.push({ + type: 'Single', + amount, + rank, + token, + rewardInUSD, + }) + }, + ) + } + if (campaign.rewardDistribution.range) { + campaign.rewardDistribution.range.forEach( + ({ + from, + to, + amount, + token, + rewardInUSD, + }: { + from: number + to: number + amount: string + token: SerializedToken + rewardInUSD: boolean + }) => { + rewardDistribution.push({ + type: 'Range', + from, + to, + amount, + token, + rewardInUSD, + }) + }, + ) + } + if (campaign.rewardDistribution.random) { + campaign.rewardDistribution.random.forEach( + ({ + from, + to, + amount, + numberOfWinners, + token, + rewardInUSD, + }: { + from: number + to: number + amount: string + numberOfWinners: number + token: SerializedToken + rewardInUSD: boolean + }) => { + rewardDistribution.push({ + type: 'Random', + from, + to, + amount, + nWinners: numberOfWinners, + token, + rewardInUSD, + }) + }, + ) + } + if (campaign?.userInfo?.tradingVolume) campaign.userInfo.tradingVolume = Number(campaign.userInfo.tradingVolume) + if (campaign.userInfo) campaign.userInfo.rewards = formatRewards(campaign.userInfo.rewards) + return { + ...campaign, + rewardDistribution, + status: getCampaignStatus(campaign), + eligibleTokens: campaign.eligibleTokens.map( + ({ chainId, name, symbol, address, logoURI, decimals }: SerializedToken) => { + return { + chainId, + name, + symbol, + address, + logoURI, + decimals, + } + }, + ), + } + }) + return formattedCampaigns +} + +const formatLeaderboardData = (data: CampaignLeaderboard) => { + const leaderboard: CampaignLeaderboard = { + ...data, + rankings: data.rankings + ? data.rankings.map( + (item: any): CampaignLeaderboardRanking => ({ + userAddress: item.userAddress, + totalPoint: item.totalPoint, + rankNo: item.rankNo, + rewardAmount: new Fraction( + item.rewardAmount || ZERO, + JSBI.exponentiate(JSBI.BigInt(10), JSBI.BigInt(item?.token?.decimals ?? 18)), + ), + rewardAmountUsd: new Fraction( + parseUnits(item?.rewardAmountUSD?.toString() || '0', RESERVE_USD_DECIMALS).toString(), + JSBI.exponentiate(JSBI.BigInt(10), JSBI.BigInt(RESERVE_USD_DECIMALS)), + ), + rewardInUSD: item.rewardInUSD, + token: item.token, + }), + ) + : [], + rewards: formatRewards(data.rewards), + } + return leaderboard +} + +const formatLuckyWinners = (data: any[]) => { + const luckyWinners: CampaignLuckyWinner[] = data.map( + (item: any): CampaignLuckyWinner => ({ + userAddress: item.userAddress, + rewardAmount: new Fraction( + item.rewardAmount, + JSBI.exponentiate(JSBI.BigInt(10), JSBI.BigInt(item?.token?.decimals ?? 18)), + ), + token: item.token, + }), + ) + return luckyWinners +} + +const formatTxs = (data: any[]) => { + return data.map( + (item: any): CampaignProofData => ({ + id: item.id, + chainId: parseInt(item.chainId), + utcTimestamp: new Date(item.time).getTime(), + txPoint: item.txPoint, + txHash: item.tx, + }), + ) +} + +const campaignApi = createApi({ + reducerPath: 'campaignApi', + baseQuery: fetchBaseQuery({ baseUrl: `${CAMPAIGN_BASE_URL}/api/v1/campaigns` }), + endpoints: builder => ({ + getCampaigns: builder.query({ + query: params => ({ + params, + url: '', + }), + transformResponse: (data: any) => formatListCampaign(data?.data || []), + }), + getLeaderboard: builder.query< + any, + { pageSize: number; pageNumber: number; userAddress: string; lookupAddress: string; campaignId: number } + >({ + query: ({ campaignId, ...params }) => ({ + params, + url: `/${campaignId}/leaderboard`, + }), + transformResponse: (data: any) => formatLeaderboardData(data?.data), + }), + getLuckyWinners: builder.query< + CampaignLuckyWinner[], + { pageSize: number; pageNumber: number; lookupAddress: string; campaignId: number } + >({ + query: ({ campaignId, ...params }) => ({ + params, + url: `/${campaignId}/lucky-winners`, + }), + transformResponse: (data: any) => formatLuckyWinners(data?.data || []), + }), + getTxsCampaign: builder.query< + CampaignProofData[], + { limit: number; offset: number; userAddress: string; campaignId: number } + >({ + query: ({ campaignId, ...params }) => ({ + params, + url: `/${campaignId}/proofs`, + }), + transformResponse: (data: any) => formatTxs(data?.data || []), + }), + joinCampaign: builder.mutation({ + query: ({ recaptchaId, ...body }) => ({ + body, + method: 'POST', + url: `/${recaptchaId}/participants`, + }), + }), + }), +}) + +export const { + useGetCampaignsQuery, + useGetLeaderboardQuery, + useGetLuckyWinnersQuery, + useJoinCampaignMutation, + useGetTxsCampaignQuery, +} = campaignApi + +export default campaignApi diff --git a/src/state/campaigns/actions.ts b/src/state/campaigns/actions.ts index d8c3013db9..79e77b3f85 100644 --- a/src/state/campaigns/actions.ts +++ b/src/state/campaigns/actions.ts @@ -145,7 +145,7 @@ export const setLoadingCampaignData = createAction('campaigns/setLoadin export const setLastTimeRefreshData = createAction('campaigns/setLastTimeRefreshData') -export const setLoadingCampaignDataError = createAction('campaigns/setLoadingCampaignDataError') +export const setLoadingCampaignDataError = createAction('campaigns/setLoadingCampaignDataError') export const setSelectedCampaign = createAction<{ campaign: CampaignData }>('campaigns/setSelectedCampaign') @@ -164,18 +164,5 @@ export const setSelectedCampaignLeaderboardLookupAddress = createAction( export const setClaimingCampaignRewardId = createAction('campaigns/setClaimingCampaignRewardId') -export const setSelectedCampaignLuckyWinners = createAction<{ luckyWinners: CampaignLuckyWinner[] }>( - 'campaigns/setSelectedCampaignLuckyWinners', -) -export const setLoadingSelectedCampaignLuckyWinners = createAction( - 'campaigns/setLoadingSelectedCampaignLuckyWinners', -) -export const setSelectedCampaignLuckyWinnersPageNumber = createAction( - 'campaigns/setSelectedCampaignLuckyWinnersPageNumber', -) -export const setSelectedCampaignLuckyWinnersLookupAddress = createAction( - 'campaigns/setSelectedCampaignLuckyWinnersLookupAddress', -) - export const setRecaptchaCampaignId = createAction('campaigns/setRecaptchaCampaignId') export const setRecaptchaCampaignLoading = createAction('campaigns/setRecaptchaCampaignLoading') diff --git a/src/state/campaigns/hooks.ts b/src/state/campaigns/hooks.ts index b38df444a7..2151d9f883 100644 --- a/src/state/campaigns/hooks.ts +++ b/src/state/campaigns/hooks.ts @@ -10,8 +10,6 @@ import { setRecaptchaCampaignLoading, setSelectedCampaignLeaderboardLookupAddress, setSelectedCampaignLeaderboardPageNumber, - setSelectedCampaignLuckyWinnersLookupAddress, - setSelectedCampaignLuckyWinnersPageNumber, } from 'state/campaigns/actions' import { AppState } from 'state/index' @@ -31,20 +29,6 @@ export function useSelectedCampaignLeaderboardPageNumberManager(): [number, (pag return [selectedCampaignLeaderboardPageNumber, updateSelectedCampaignLeaderboardPageNumberCallback] } -export function useSelectedCampaignLuckyWinnerPageNumber(): [number, (page: number) => void] { - const page = useSelector((state: AppState) => state.campaigns.selectedCampaignLuckyWinnersPageNumber) - const dispatch = useDispatch() - - const setPage = useCallback( - (newPageNumber: number) => { - dispatch(setSelectedCampaignLuckyWinnersPageNumber(newPageNumber)) - }, - [dispatch], - ) - - return [page, setPage] -} - export function useSelectedCampaignLeaderboardLookupAddressManager() { const selectedCampaignLeaderboardLookupAddress = useSelector( (state: AppState) => state.campaigns.selectedCampaignLeaderboardLookupAddress, @@ -64,25 +48,6 @@ export function useSelectedCampaignLeaderboardLookupAddressManager() { ) } -export function useSelectedCampaignLuckyWinnersLookupAddressManager() { - const selectedCampaignLuckyWinnersLookupAddress = useSelector( - (state: AppState) => state.campaigns.selectedCampaignLuckyWinnersLookupAddress, - ) - const dispatch = useDispatch() - - const updateSelectedCampaignLuckyWinnersLookupAddressCallback = useCallback( - (newLookupAddress: string) => { - dispatch(setSelectedCampaignLuckyWinnersLookupAddress(newLookupAddress)) - }, - [dispatch], - ) - - return useMemo( - () => [selectedCampaignLuckyWinnersLookupAddress, updateSelectedCampaignLuckyWinnersLookupAddressCallback] as const, - [selectedCampaignLuckyWinnersLookupAddress, updateSelectedCampaignLuckyWinnersLookupAddressCallback], - ) -} - export function useRecaptchaCampaignManager() { const recaptchaCampaign = useSelector((state: AppState) => state.campaigns.recaptchaCampaign) const dispatch = useDispatch() diff --git a/src/state/campaigns/reducer.ts b/src/state/campaigns/reducer.ts index 35c921bb91..e9d12693dc 100644 --- a/src/state/campaigns/reducer.ts +++ b/src/state/campaigns/reducer.ts @@ -3,7 +3,6 @@ import { createReducer } from '@reduxjs/toolkit' import { CampaignData, CampaignLeaderboard, - CampaignLuckyWinner, setCampaignData, setCampaignDataByPage, setClaimingCampaignRewardId, @@ -11,35 +10,25 @@ import { setLoadingCampaignData, setLoadingCampaignDataError, setLoadingSelectedCampaignLeaderboard, - setLoadingSelectedCampaignLuckyWinners, setRecaptchaCampaignId, setRecaptchaCampaignLoading, setSelectedCampaign, setSelectedCampaignLeaderboard, setSelectedCampaignLeaderboardLookupAddress, setSelectedCampaignLeaderboardPageNumber, - setSelectedCampaignLuckyWinners, - setSelectedCampaignLuckyWinnersLookupAddress, - setSelectedCampaignLuckyWinnersPageNumber, } from './actions' interface CampaignsState { readonly data: CampaignData[] readonly loadingCampaignData: boolean - readonly loadingCampaignDataError: Error | undefined + readonly loadingCampaignDataError: boolean readonly selectedCampaign: CampaignData | undefined readonly selectedCampaignLeaderboard: CampaignLeaderboard | undefined - readonly loadingCampaignLeaderboard: boolean readonly selectedCampaignLeaderboardPageNumber: number readonly selectedCampaignLeaderboardLookupAddress: string - readonly selectedCampaignLuckyWinners: CampaignLuckyWinner[] - readonly loadingCampaignLuckyWinners: boolean - readonly selectedCampaignLuckyWinnersPageNumber: number - readonly selectedCampaignLuckyWinnersLookupAddress: string - readonly claimingCampaignRewardId: number | null // id that is being claimed readonly recaptchaCampaign: { @@ -53,20 +42,14 @@ interface CampaignsState { const initialState: CampaignsState = { data: [], loadingCampaignData: true, - loadingCampaignDataError: undefined, + loadingCampaignDataError: false, selectedCampaign: undefined, selectedCampaignLeaderboard: undefined, - loadingCampaignLeaderboard: false, selectedCampaignLeaderboardPageNumber: 0, selectedCampaignLeaderboardLookupAddress: '', - selectedCampaignLuckyWinners: [], - loadingCampaignLuckyWinners: false, - selectedCampaignLuckyWinnersPageNumber: 0, - selectedCampaignLuckyWinnersLookupAddress: '', - claimingCampaignRewardId: null, recaptchaCampaign: { @@ -136,30 +119,7 @@ export default createReducer(initialState, builder => selectedCampaignLeaderboardLookupAddress: lookupAddress, } }) - .addCase(setSelectedCampaignLuckyWinners, (state, { payload: { luckyWinners } }) => { - return { - ...state, - selectedCampaignLuckyWinners: luckyWinners, - } - }) - .addCase(setLoadingSelectedCampaignLuckyWinners, (state, { payload: loading }) => { - return { - ...state, - loadingCampaignLuckyWinners: loading, - } - }) - .addCase(setSelectedCampaignLuckyWinnersPageNumber, (state, { payload: pageNumber }) => { - return { - ...state, - selectedCampaignLuckyWinnersPageNumber: pageNumber, - } - }) - .addCase(setSelectedCampaignLuckyWinnersLookupAddress, (state, { payload: lookupAddress }) => { - return { - ...state, - selectedCampaignLuckyWinnersLookupAddress: lookupAddress, - } - }) + .addCase(setRecaptchaCampaignId, (state, { payload: id }) => { return { ...state, diff --git a/src/state/index.ts b/src/state/index.ts index caffdcdc0c..337177cb2d 100644 --- a/src/state/index.ts +++ b/src/state/index.ts @@ -1,26 +1,27 @@ import { configureStore } from '@reduxjs/toolkit' import { load, save } from 'redux-localstorage-simple' +import announcementApi, { publicAnnouncementApi } from 'services/announcement' import blockServiceApi from 'services/blockService' +import campaignApi from 'services/campaign' import coingeckoApi from 'services/coingecko' +import crosschainApi from 'services/crossChain' +import earningApi from 'services/earning' +import geckoTerminalApi from 'services/geckoTermial' +import identifyApi from 'services/identity' +import knProtocolApi from 'services/knprotocol' +import ksSettingApi from 'services/ksSetting' import kyberAISubscriptionApi from 'services/kyberAISubscription' +import kyberDAO from 'services/kyberDAO' +import limitOrderApi from 'services/limitOrder' import priceAlertApi from 'services/priceAlert' import routeApi from 'services/route' +import socialApi from 'services/social' import tokenApi from 'services/token' import { ENV_LEVEL } from 'constants/env' import { ENV_TYPE } from 'constants/type' import kyberAIApi from 'pages/TrueSightV2/hooks/useKyberAIData' -import announcementApi, { publicAnnouncementApi } from '../services/announcement' -import crosschainApi from '../services/crossChain' -import earningApi from '../services/earning' -import geckoTerminalApi from '../services/geckoTermial' -import identifyApi from '../services/identity' -import knProtocolApi from '../services/knprotocol' -import ksSettingApi from '../services/ksSetting' -import kyberDAO from '../services/kyberDAO' -import limitOrderApi from '../services/limitOrder' -import socialApi from '../services/social' import application from './application/reducer' import authen from './authen/reducer' import burnProAmm from './burn/proamm/reducer' @@ -97,6 +98,7 @@ const store = configureStore({ [coingeckoApi.reducerPath]: coingeckoApi.reducer, [limitOrderApi.reducerPath]: limitOrderApi.reducer, + [campaignApi.reducerPath]: campaignApi.reducer, [kyberAIApi.reducerPath]: kyberAIApi.reducer, [kyberAISubscriptionApi.reducerPath]: kyberAISubscriptionApi.reducer, [kyberDAO.reducerPath]: kyberDAO.reducer, @@ -128,6 +130,7 @@ const store = configureStore({ .concat(coingeckoApi.middleware) .concat(limitOrderApi.middleware) .concat(kyberAIApi.middleware) + .concat(campaignApi.middleware) .concat(kyberAISubscriptionApi.middleware) .concat(announcementApi.middleware) .concat(publicAnnouncementApi.middleware) diff --git a/src/theme/components.tsx b/src/theme/components.tsx index 5fb445e175..7afcfc381a 100644 --- a/src/theme/components.tsx +++ b/src/theme/components.tsx @@ -193,7 +193,7 @@ export function ExternalLink({ }: Omit, 'as' | 'ref'> & { href: string }) { const handleClick = useCallback( (event: React.MouseEvent) => { - onClick && onClick(event) + onClick?.(event) // don't prevent default, don't redirect if it's a new tab if (target === '_blank' || event.ctrlKey || event.metaKey) { } else { @@ -203,7 +203,13 @@ export function ExternalLink({ [target, onClick], ) return ( - + ) } @@ -221,13 +227,19 @@ export function ExternalLinkIcon({ console.debug('Fired outbound link event', href) } else { event.preventDefault() - navigateToUrl(href, false) + navigateToUrl(href, { _dangerousSkipCheckWhitelist: true, allowRelativePath: true }) } }, [href, target], ) return ( - + ) diff --git a/src/utils/redirect.ts b/src/utils/redirect.ts index 4dec7f623a..d472a54b66 100644 --- a/src/utils/redirect.ts +++ b/src/utils/redirect.ts @@ -6,15 +6,19 @@ import { useActiveWeb3React } from 'hooks' import { useChangeNetwork } from 'hooks/web3/useChangeNetwork' const whiteListDomains = [/https:\/\/(.+?\.)?kyberswap\.com$/, /https:\/\/(.+)\.kyberengineering\.io$/] -export const validateRedirectURL = (url: string | undefined, whitelistKyberSwap = true) => { + +type Options = { _dangerousSkipCheckWhitelist?: boolean; allowRelativePath?: boolean } +export const validateRedirectURL = ( + url: string | undefined, + { _dangerousSkipCheckWhitelist = false, allowRelativePath = false }: Options = {}, +) => { try { - if (!url) throw new Error() - const newUrl = new URL(url) // valid url + if (!url || url.endsWith('.js')) throw new Error() + const newUrl = allowRelativePath && url.startsWith('/') ? new URL(`${window.location.origin}${url}`) : new URL(url) if ( - url.endsWith('.js') || newUrl.pathname.endsWith('.js') || !['https:', 'http:'].includes(newUrl.protocol) || - (whitelistKyberSwap && !whiteListDomains.some(regex => newUrl.origin.match(regex))) + (!_dangerousSkipCheckWhitelist && !whiteListDomains.some(regex => newUrl.origin.match(regex))) ) { throw new Error() } @@ -24,8 +28,8 @@ export const validateRedirectURL = (url: string | undefined, whitelistKyberSwap } } -export const navigateToUrl = (url: string | undefined, whitelistKyberSwap = true) => { - const urlFormatted = validateRedirectURL(url, whitelistKyberSwap) +export const navigateToUrl = (url: string | undefined, options?: Options) => { + const urlFormatted = validateRedirectURL(url, options) if (urlFormatted) window.location.href = urlFormatted } @@ -46,7 +50,7 @@ export const useNavigateToUrl = () => { return } const { pathname, host, search } = new URL(actionURL) - if (!validateRedirectURL(actionURL, false)) return + if (!validateRedirectURL(actionURL, { _dangerousSkipCheckWhitelist: true })) return if (window.location.host === host) { navigate(`${pathname}${search}`) } else { diff --git a/yarn.lock b/yarn.lock index a4e14a88d9..35100ef88a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2293,10 +2293,10 @@ tiny-warning "^1.0.3" toformat "^2.0.0" -"@kyberswap/ks-sdk-core@1.0.11", "@kyberswap/ks-sdk-core@^1.0.5": - version "1.0.11" - resolved "https://registry.yarnpkg.com/@kyberswap/ks-sdk-core/-/ks-sdk-core-1.0.11.tgz#59362240147001ccabcb49ed77991b2f78b0e440" - integrity sha512-A7pPRqr0lFeSYOsuitsld+WglV4G8Tl5FsKZpx9mBjOrSFKGLOtCE0oMwAeD4+Jjo8VyLJppkBINQYY7wAq8Xg== +"@kyberswap/ks-sdk-core@1.0.13", "@kyberswap/ks-sdk-core@^1.0.5": + version "1.0.13" + resolved "https://registry.yarnpkg.com/@kyberswap/ks-sdk-core/-/ks-sdk-core-1.0.13.tgz#31a67aa88edb6968366192f53f829d74ca329031" + integrity sha512-o6jXdZdX00gKQ5RE/G4iQ5oGoReue8ZQFGr0JVCvGxRf/ZLjjAHW+tZfyuxrktk5bWKQjMN43PX7AKZ2+KyHtQ== dependencies: "@ethersproject/address" "^5.0.2" "@solana/web3.js" "^1.66.2"