diff --git a/.env b/.env
index 1a752e7625..f56ab031b2 100644
--- a/.env
+++ b/.env
@@ -47,3 +47,4 @@ VITE_CAMPAIGN_URL=https://kyberswap-arbitrum-stip.kyberengineering.io/api
VITE_REFERRAL_URL=https://referral.kyberswap.com/api
VITE_TOKEN_API_URL=https://pre-token-api.kyberengineering.io/api
+VITE_ZAP_EARN_URL=https://pre-zap-earn-service.kyberengineering.io/api
diff --git a/.env.dev b/.env.dev
index 1aa6773ffa..74ea22a571 100644
--- a/.env.dev
+++ b/.env.dev
@@ -48,3 +48,4 @@ VITE_CAMPAIGN_URL=https://kyberswap-arbitrum-stip.kyberengineering.io/api
VITE_REFERRAL_URL=https://referral.kyberswap.com/api
VITE_TOKEN_API_URL=https://pre-token-api.kyberengineering.io/api
+VITE_ZAP_EARN_URL=https://pre-zap-earn-service.kyberengineering.io/api
diff --git a/.env.production b/.env.production
index 474c13ba1a..7bf1468f11 100644
--- a/.env.production
+++ b/.env.production
@@ -47,3 +47,4 @@ VITE_CAMPAIGN_URL=https://kyberswap-arbitrum-stip.kyberengineering.io/api
VITE_REFERRAL_URL=https://referral.kyberswap.com/api
VITE_TOKEN_API_URL=https://token-api.kyberengineering.io/api
+VITE_ZAP_EARN_URL=https://pre-zap-earn-service.kyberengineering.io/api
diff --git a/.env.stg b/.env.stg
index eebf91f8ec..324cedd5db 100644
--- a/.env.stg
+++ b/.env.stg
@@ -45,3 +45,4 @@ VITE_CAMPAIGN_URL=https://kyberswap-arbitrum-stip.kyberengineering.io/api
VITE_REFERRAL_URL=https://referral.kyberswap.com/api
VITE_TOKEN_API_URL=https://pre-token-api.kyberengineering.io/api
+VITE_ZAP_EARN_URL=https://pre-zap-earn-service.kyberengineering.io/api
diff --git a/src/assets/svg/fire.svg b/src/assets/svg/fire.svg
new file mode 100644
index 0000000000..6553da38b9
--- /dev/null
+++ b/src/assets/svg/fire.svg
@@ -0,0 +1,3 @@
+
diff --git a/src/assets/svg/low-volatility.svg b/src/assets/svg/low-volatility.svg
new file mode 100644
index 0000000000..75a48cfbba
--- /dev/null
+++ b/src/assets/svg/low-volatility.svg
@@ -0,0 +1,11 @@
+
diff --git a/src/assets/svg/play-icon.svg b/src/assets/svg/play-icon.svg
new file mode 100644
index 0000000000..496aec879e
--- /dev/null
+++ b/src/assets/svg/play-icon.svg
@@ -0,0 +1,19 @@
+
+
diff --git a/src/assets/svg/solid-earning.svg b/src/assets/svg/solid-earning.svg
new file mode 100644
index 0000000000..d3b6facf36
--- /dev/null
+++ b/src/assets/svg/solid-earning.svg
@@ -0,0 +1,4 @@
+
diff --git a/src/pages/Earns/index.tsx b/src/pages/Earns/index.tsx
index 8bea6a50b0..b0e2fa63da 100644
--- a/src/pages/Earns/index.tsx
+++ b/src/pages/Earns/index.tsx
@@ -1,12 +1,21 @@
+import { ChainId } from '@kyberswap/ks-sdk-core'
+import { rgba } from 'polished'
import { Box, Flex, Text } from 'rebass'
-import styled from 'styled-components'
+import { EarnPool, useExplorerLandingQuery } from 'services/zapEarn'
+import styled, { keyframes } from 'styled-components'
import bg from 'assets/images/earn-bg.png'
import CursorIcon from 'assets/svg/cursor.svg'
+import FireIcon from 'assets/svg/fire.svg'
import LiquidityPoolIcon from 'assets/svg/liquidity-pools.svg'
import LiquidityPosIcon from 'assets/svg/liquidity-positions.svg'
+import LowVolatilityIcon from 'assets/svg/low-volatility.svg'
+import PlayIcon from 'assets/svg/play-icon.svg'
+import RocketIcon from 'assets/svg/rocket.svg'
+import SolidEarningIcon from 'assets/svg/solid-earning.svg'
import StakingIcon from 'assets/svg/staking.svg'
import { ButtonPrimary } from 'components/Button'
+import { NETWORKS_INFO } from 'hooks/useChainsConfig'
import useTheme from 'hooks/useTheme'
const WrapperBg = styled.div`
@@ -23,18 +32,92 @@ const Container = styled.div`
text-align: center;
`
+/* Spin animation */
+const spin = keyframes`
+ from {
+ transform: rotate(0deg);
+ }
+ to {
+ transform: rotate(360deg);
+ }
+`
+
+const BorderWrapper = styled.div`
+ padding: 1px;
+ position: relative;
+ background-clip: padding-box;
+ border-radius: 20px;
+ overflow: hidden;
+
+ ::before {
+ content: '';
+ position: absolute;
+ top: 0;
+ left: 0;
+ right: 0;
+ bottom: 0;
+ padding: 1px; /* Border width */
+ background: linear-gradient(306.9deg, #262525 38.35%, rgba(49, 203, 158, 0.06) 104.02%),
+ radial-gradient(58.61% 54.58% at 30.56% 0%, rgba(49, 203, 158, 0.6) 0%, rgba(0, 0, 0, 0) 100%);
+ -webkit-mask: linear-gradient(#fff 0 0) padding-box, linear-gradient(#fff 0 0); /* Mask to avoid background bleed */
+ z-index: -1;
+ }
+
+ :hover::before {
+ top: -20%;
+ left: -20%;
+ right: -20%;
+ bottom: -20%;
+ padding: 1px; /* Border width */
+ background: linear-gradient(306.9deg, #262525 38.35%, rgba(49, 203, 158, 0.6) 104.02%),
+ radial-gradient(58.61% 54.58% at 30.56% 0%, rgba(49, 203, 158, 1) 0%, rgba(0, 0, 0, 0) 100%);
+
+ animation: ${spin} 2s linear infinite; /* Spin animation */
+ }
+`
+const PoolWrapper = styled.div`
+ border-radius: 20px;
+ position: relative;
+ overflow: hidden;
+ padding: 1px;
+ transition: box-shadow 0.3s ease, transform 0.3s ease, background 0.3s ease;
+
+ :hover {
+ box-shadow: 0px 12px 64px 0px rgba(71, 32, 139, 0.8);
+ ::before {
+ background: linear-gradient(215.58deg, #262525 -9.03%, rgba(148, 115, 221, 0.6) 59.21%),
+ radial-gradient(58.61% 54.58% at 30.56% 0%, rgba(130, 71, 229, 1) 0%, rgba(0, 0, 0, 0) 100%);
+ }
+ }
+
+ /* Create the gradient border effect using ::before */
+ ::before {
+ content: '';
+ position: absolute;
+ top: 0;
+ left: 0;
+ right: 0;
+ bottom: 0;
+ border-radius: 20px;
+ padding: 1px;
+
+ background: linear-gradient(215.58deg, #262525 -9.03%, rgba(148, 115, 221, 0.2) 59.21%),
+ radial-gradient(58.61% 54.58% at 30.56% 0%, rgba(130, 71, 229, 0.6) 0%, rgba(0, 0, 0, 0) 100%);
+ -webkit-mask-composite: destination-out;
+ z-index: -1; /* Position behind the content */
+ }
+`
+
const CardWrapper = styled.div`
border-radius: 20px;
- border: 1px solid;
- border-image-source: linear-gradient(306.9deg, #262525 38.35%, rgba(49, 203, 158, 0.06) 104.02%),
- radial-gradient(58.61% 54.58% at 30.56% 0%, rgba(49, 203, 158, 0.6) 0%, rgba(0, 0, 0, 0) 100%);
- background: linear-gradient(119.08deg, rgba(20, 29, 27, 0.8) -0.89%, rgba(14, 14, 14, 0.8) 132.3%);
- padding-left: 36px;
- padding-bottom: 44px;
+
+ background: linear-gradient(119.08deg, rgba(20, 29, 27, 1) -0.89%, rgba(14, 14, 14, 1) 132.3%);
+ padding: 0 36px 44px 50px;
text-align: left;
min-height: 360px;
display: flex;
flex-direction: column;
+ overflow: hidden;
cursor: url(${CursorIcon}), auto;
button {
@@ -42,6 +125,56 @@ const CardWrapper = styled.div`
}
`
+const ListPoolWrapper = styled.div`
+ padding: 20px;
+ border-radius: 20px;
+ background: linear-gradient(119.08deg, rgba(20, 29, 27, 1) -0.89%, rgba(14, 14, 14, 1) 132.3%);
+ cursor: url(${CursorIcon}), auto;
+`
+
+const PoolRow = styled(Flex)`
+ gap: 12px;
+ align-items: center;
+ border-radius: 999px;
+ padding: 8px 16px;
+
+ :hover {
+ background: #31cb9e1a;
+ }
+`
+
+const Tag = styled.div`
+ border-radius: 999px;
+ background: ${({ theme }) => rgba(theme.text, 0.1)};
+ color: ${({ theme }) => theme.subText};
+ padding: 4px 8px;
+ font-size: 12px;
+`
+
+const Icon = ({ icon, size = 'medium' }: { icon: string; size: 'small' | 'medium' }) => {
+ return (
+
+
+
+
+
+ )
+}
+
const Card = ({
title,
icon,
@@ -55,40 +188,48 @@ const Card = ({
}) => {
const theme = useTheme()
return (
-
-
-
-
-
-
-
+
+
+
+
+
-
-
- {title}
-
-
- {desc}
-
-
- {action.text}
-
-
+
+ {title}
+
+
+ {desc}
+
+
+ {action.text}
+
+
+
)
}
export default function Earns() {
const theme = useTheme()
+ const { data } = useExplorerLandingQuery()
+ console.log(data)
+
+ const title = (_title: string, icon: string) => (
+ <>
+
+
+ {_title}
+
+
+ >
+ )
return (
@@ -138,7 +279,164 @@ export default function Earns() {
}}
/>
+
+
+ {
+ // TODO:: go to explorer page
+ }}
+ >
+ {title('Highlighted Pools', FireIcon)}
+
+ {data?.data?.highlightedPools.map(pool => (
+
+ ))}
+
+
+
+
+
+
+ {
+ // TODO:: go to explorer page
+ }}
+ >
+ {title('High APR', RocketIcon)}
+
+ {data?.data?.highAPR.map(pool => (
+
+ ))}
+
+
+
+
+
+ {
+ // TODO:: go to explorer page
+ }}
+ >
+ {title('Low Volatility', LowVolatilityIcon)}
+
+ {data?.data?.lowVolatility.map(pool => (
+
+ ))}
+
+
+
+
+
+ {
+ // TODO:: go to explorer page
+ }}
+ >
+ {title('Solid Earning', SolidEarningIcon)}
+
+ {data?.data?.solidEarning.map(pool => (
+
+ ))}
+
+
+
+
+
+ {
+ // TODO: go to explorer page
+ }}
+ sx={{
+ cursor: 'pointer',
+ border: `1px solid ${theme.primary}`,
+ margin: 'auto',
+ marginTop: '40px',
+ borderRadius: '999px',
+ height: '56px',
+ background: rgba(theme.primary, 0.2),
+ fontSize: '16px',
+ fontWeight: 500,
+ color: theme.primary,
+ alignItems: 'center',
+ padding: '1rem 2rem',
+ width: 'fit-content',
+ }}
+ >
+ EXPLORE POOLS
+
+
)
}
+
+const PoolItem = ({ pool }: { pool: EarnPool }) => {
+ const theme = useTheme()
+ return (
+ {
+ e.stopPropagation()
+ // TODO: open zap in widget
+ }}
+ >
+
+
+
+
+
+ {pool.tokens[0].symbol} /{' '}
+
+ {pool.tokens[1].symbol}
+
+
+ {pool.feeTier * 100}%
+
+ {pool.apr}%
+
+ )
+}
diff --git a/src/services/zapEarn.ts b/src/services/zapEarn.ts
new file mode 100644
index 0000000000..fe9386b08e
--- /dev/null
+++ b/src/services/zapEarn.ts
@@ -0,0 +1,43 @@
+import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query/react'
+
+export interface EarnPool {
+ exchange: string
+ address: string
+ type: string
+ feeTier: number // need mulpliple with 100 to percent
+ chainId: number
+ apr: number
+ tokens: Array<{
+ address: string
+ logoURI: string
+ symbol: string
+ }>
+}
+
+interface Response {
+ data: {
+ highlightedPools: Array
+ solidEarning: Array
+ highAPR: Array
+ lowVolatility: Array
+ }
+}
+
+const zapEarnServiceApi = createApi({
+ reducerPath: 'zapEarnServiceApi ',
+ baseQuery: fetchBaseQuery({
+ baseUrl: import.meta.env.VITE_ZAP_EARN_URL,
+ }),
+ keepUnusedDataFor: 1,
+ endpoints: builder => ({
+ explorerLanding: builder.query({
+ query: () => ({
+ url: `/v1/explorer/landing-page`,
+ }),
+ }),
+ }),
+})
+
+export const { useExplorerLandingQuery } = zapEarnServiceApi
+
+export default zapEarnServiceApi
diff --git a/src/state/index.ts b/src/state/index.ts
index d7a9ab8863..3b54ed47ba 100644
--- a/src/state/index.ts
+++ b/src/state/index.ts
@@ -20,6 +20,7 @@ import referralApi from 'services/referral'
import routeApi from 'services/route'
import socialApi from 'services/social'
import tokenApi from 'services/token'
+import zapEarnServiceApi from 'services/zapEarn'
import { ENV_LEVEL } from 'constants/env'
import { ENV_TYPE } from 'constants/type'
@@ -108,6 +109,7 @@ const store = configureStore({
topTokens,
[routeApi.reducerPath]: routeApi.reducer,
[tokenApi.reducerPath]: tokenApi.reducer,
+ [zapEarnServiceApi.reducerPath]: zapEarnServiceApi.reducer,
[referralApi.reducerPath]: referralApi.reducer,
[campaignApi.reducerPath]: campaignApi.reducer,
[commonServiceApi.reducerPath]: commonServiceApi.reducer,
@@ -133,6 +135,7 @@ const store = configureStore({
.concat(routeApi.middleware)
.concat(socialApi.middleware)
.concat(tokenApi.middleware)
+ .concat(zapEarnServiceApi.middleware)
.concat(referralApi.middleware)
.concat(campaignApi.middleware)
.concat(commonServiceApi.middleware)