From 1fd4b1c8506644cbba9cbfec3142d14ecfafab58 Mon Sep 17 00:00:00 2001 From: UsamaSaleem14 Date: Mon, 24 Oct 2022 22:26:55 +0500 Subject: [PATCH 1/3] Mock data for pools --- next.config.js | 3 + package.json | 6 +- pages/pools/index.tsx | 5 +- src/components/Pools/PoolTableRow.tsx | 103 ++++++++++++++------ src/components/Pools/PoolsOverviewTable.tsx | 82 ++++++++-------- src/hooks/useCreatePoolHandler.tsx | 8 +- src/hooks/usePoolsHandler.tsx | 47 +++++++-- src/queries/mockQueries.tsx | 18 ++++ src/utils/getMockData.tsx | 39 ++++++++ 9 files changed, 224 insertions(+), 87 deletions(-) create mode 100644 src/queries/mockQueries.tsx create mode 100644 src/utils/getMockData.tsx diff --git a/next.config.js b/next.config.js index 0562dde..ff03b34 100644 --- a/next.config.js +++ b/next.config.js @@ -10,4 +10,7 @@ module.exports = { }, ] }, + images: { + domains: ['cloudflare-ipfs.com'] + } } diff --git a/package.json b/package.json index 2595d33..d978ec7 100644 --- a/package.json +++ b/package.json @@ -12,15 +12,19 @@ "@emotion/react": "11", "@emotion/styled": "11", "@ethersproject/providers": "^5.6.8", + "@faker-js/faker": "^7.6.0", "@gammaswap/v1-core": "^0.1.12", - "@gammaswap/v1-periphery": "^0.1.9", + "@gammaswap/v1-periphery": "^0.1.10", "@graphprotocol/client-cli": "^2.2.12", + "@graphql-tools/mock": "^8.7.6", + "@graphql-tools/schema": "^9.0.4", "@headlessui/react": "^1.6.4", "@heroicons/react": "^1.0.6", "@uniswap/v2-core": "^1.0.1", "@uniswap/v2-periphery": "^1.1.0-beta.0", "@walletconnect/web3-provider": "^1.7.8", "axios": "^1.1.2", + "casual": "^1.6.2", "dotenv": "^16.0.1", "erc-20-abi": "^1.0.0", "ethers": "^5.6.8", diff --git a/pages/pools/index.tsx b/pages/pools/index.tsx index 6638f7c..2c758e4 100644 --- a/pages/pools/index.tsx +++ b/pages/pools/index.tsx @@ -8,8 +8,9 @@ import { usePoolsHandler } from "../../src/hooks/usePoolsHandler" import { PoolsOverviewTable } from "../../src/components/Pools/PoolsOverviewTable" const Pools: NextPage = () => { - const { pools, latestPoolsData } = usePoolsHandler() + const { pools, latestPoolsData, mockData } = usePoolsHandler() const [selectedPoolData, setSelectedPoolData] = useState() + console.log(mockData) const style = { wrapper: "w-full h-full flex justify-center text-neutrals-100", @@ -74,7 +75,7 @@ const Pools: NextPage = () => { ))} - + ) diff --git a/src/components/Pools/PoolTableRow.tsx b/src/components/Pools/PoolTableRow.tsx index 54b039f..d2d82a4 100644 --- a/src/components/Pools/PoolTableRow.tsx +++ b/src/components/Pools/PoolTableRow.tsx @@ -1,44 +1,83 @@ -import React from "react" -import Image from "next/image" -import { usePoolsData } from "../../context/PoolsDataContext" +import React from 'react' +import Image from 'next/image' +import { usePoolsData } from '../../context/PoolsDataContext' -export const PoolTableRow = () => { +export const PoolTableRow = ({ poolData, mockData }: any) => { const { selectedPoolData } = usePoolsData() - + console.log(mockData) const style = { - poolsOverviewTableRow: "pt-4 px-2 rounded-lg hover:bg-neutrals-300 hover:bg-opacity-30 cursor-pointer", - poolsOverviewTableContent: "flex space-x-32", - poolsOverviewTableRowPrimary: "flex space-x-6", - poolsOverviewTableRowItem: "", - poolsOverviewTableRowPool: "flex space-x-2", - poolsOverviewTableRowPoolIcons: "", - poolsOverviewTableRowPoolIcon: "", - poolsOverviewTableRowSecondary: "flex space-x-20 ml-auto", - poolsOverviewTableLine: "w-full h-[0.10rem] bg-neutrals-700 opacity-40 mt-4", + poolsOverviewTableRow: 'pt-4 px-2 rounded-lg hover:bg-neutrals-300 hover:bg-opacity-30 cursor-pointer', + poolsOverviewTableContent: 'flex space-x-32', + poolsOverviewTableRowPrimary: 'flex space-x-6', + poolsOverviewTableRowItem: '', + poolsOverviewTableRowPool: 'flex space-x-2', + poolsOverviewTableRowPoolIcons: '', + poolsOverviewTableRowPoolIcon: '', + poolsOverviewTableRowSecondary: 'flex space-x-20 ml-auto', + poolsOverviewTableLine: 'w-full h-[0.10rem] bg-neutrals-700 opacity-40 mt-4', } return ( -
-
-
-

1

-
-
- - + <> + {poolData ? ( +
+
+
+

1

+
+
+ + +
+

USDC/ETH

+
+
+ +
+

1.34m

+

3.34%

+

432k

+

2.22%

-

USDC/ETH

+
- -
-

1.34m

-

3.34%

-

432k

-

2.22%

+ ) : mockData ? ( +
+
+
+

{mockData.id}

+
+
+ + +
+

+ {mockData.token1}/{mockData.token2} +

+
+
+ +
+

{mockData.totalSupply}

+

{mockData.supplyAPY}

+

{mockData.totalBorrowed}

+

{mockData.borrowAPY}

+
+
+
-
-
-
+ ) : null} + ) } diff --git a/src/components/Pools/PoolsOverviewTable.tsx b/src/components/Pools/PoolsOverviewTable.tsx index dac1381..b2aea0f 100644 --- a/src/components/Pools/PoolsOverviewTable.tsx +++ b/src/components/Pools/PoolsOverviewTable.tsx @@ -1,38 +1,38 @@ -import { NextPage } from "next" -import Link from "next/link" -import { ArrowLeftIcon, ArrowRightIcon } from "@heroicons/react/outline" -import { PoolTableRow } from "./PoolTableRow" +import { NextPage } from 'next' +import Link from 'next/link' +import { ArrowLeftIcon, ArrowRightIcon } from '@heroicons/react/outline' +import { PoolTableRow } from './PoolTableRow' import { Pool, PoolData } from '../../../.graphclient' -import { BigNumber } from "ethers" +import { BigNumber } from 'ethers' import { LinkWrapper } from '../../components/LinkWrapper' interface PoolsOverviewTableProps { poolsData: Array + mockData: Array } -export const PoolsOverviewTable = ({ poolsData }: PoolsOverviewTableProps) => { +export const PoolsOverviewTable = ({ poolsData, mockData }: PoolsOverviewTableProps) => { const style = { - poolsOverviewContainer: "font-normal flex flex-col space-y-2", - poolsOverviewHeader: "text-neutrals-600 font-medium", - poolsOverviewTable: "flex flex-col bg-neutrals-800 pt-4 px-3 rounded-lg drop-shadow-md", - poolsOverviewTableHeader: "", - poolsOverviewTableHeaderContent: "flex", - poolsOverviewTableHeaderPrimary: "flex space-x-6", - poolsOverviewTableHeaderItem: "text-neutrals-300", - poolsOverviewTableHeaderSecondary: "flex space-x-6 ml-auto", - poolsOverviewTableLine: "w-full h-[0.10rem] bg-neutrals-700 opacity-40 mt-2", - poolsOverviewPagination: "py-4 flex justify-center items-center space-x-5 text-neutrals-400", - poolsOverviewPaginationPreviousArrow: "", - arrow: "w-4 h-4", - poolsOverviewPaginationPage: "text-neutrals-100 text-sm", - poolsOverviewPaginationNextArrow: "", + poolsOverviewContainer: 'font-normal flex flex-col space-y-2', + poolsOverviewHeader: 'text-neutrals-600 font-medium', + poolsOverviewTable: 'flex flex-col bg-neutrals-800 pt-4 px-3 rounded-lg drop-shadow-md', + poolsOverviewTableHeader: '', + poolsOverviewTableHeaderContent: 'flex', + poolsOverviewTableHeaderPrimary: 'flex space-x-6', + poolsOverviewTableHeaderItem: 'text-neutrals-300', + poolsOverviewTableHeaderSecondary: 'flex space-x-6 ml-auto', + poolsOverviewTableLine: 'w-full h-[0.10rem] bg-neutrals-700 opacity-40 mt-2', + poolsOverviewPagination: 'py-4 flex justify-center items-center space-x-5 text-neutrals-400', + poolsOverviewPaginationPreviousArrow: '', + arrow: 'w-4 h-4', + poolsOverviewPaginationPage: 'text-neutrals-100 text-sm', + poolsOverviewPaginationNextArrow: '', } return (

Top Pools

- {/* Table Header */}
@@ -40,7 +40,7 @@ export const PoolsOverviewTable = ({ poolsData }: PoolsOverviewTableProps) => {

#

Pool

- +

Total Supply

Supply APY

@@ -52,33 +52,37 @@ export const PoolsOverviewTable = ({ poolsData }: PoolsOverviewTableProps) => {
{/* Table Row */} - {poolsData.map((poolData, idx) => { - return ( - - - - ) - })} - + {poolsData.length > 0 + ? poolsData.map((poolData, idx) => { + return ( + + + + ) + }) + : mockData + ? mockData.map((mock, idx) => { + return ( + + + + ) + }) + : null} + {/* TODO: Pagination Section */}
-
- +
Page 1 of 5
- +
-
) -} \ No newline at end of file +} diff --git a/src/hooks/useCreatePoolHandler.tsx b/src/hooks/useCreatePoolHandler.tsx index ce4b41e..2496320 100644 --- a/src/hooks/useCreatePoolHandler.tsx +++ b/src/hooks/useCreatePoolHandler.tsx @@ -4,7 +4,7 @@ import { WalletContext } from '../../src/context/WalletContext' import GammaPoolFactory from '@gammaswap/v1-core/artifacts/contracts/GammaPoolFactory.sol/GammaPoolFactory.json' import { calcPoolKey } from '../../src/utils/getSmartContract' import Protocols, { Protocol } from '../components/Protocols' -import {notifySuccess, notifyError} from '../../src/hooks/useNotification' +import { notifySuccess, notifyError } from '../../src/hooks/useNotification' export const useCreatePoolHandler = () => { const [gammaPoolFactory, setGammaPoolFactory] = useState(null) @@ -38,7 +38,7 @@ export const useCreatePoolHandler = () => { const createPool = async () => { try { if (!accountInfo || !gammaPoolFactory) { - notifyError("Please connect your wallet.") + notifyError('Please connect your wallet.') return } @@ -64,7 +64,7 @@ export const useCreatePoolHandler = () => { notifySuccess(msg) resetParameters() } catch (e) { - let errorMsg = "Pool not created: " + let errorMsg = 'Pool not created: ' if (typeof e === 'string') { notifyError(errorMsg + e) } else if (e instanceof Error) { @@ -88,6 +88,6 @@ export const useCreatePoolHandler = () => { cfmmAddr, setCfmmAddr, protocol, - setProtocol + setProtocol, } } diff --git a/src/hooks/usePoolsHandler.tsx b/src/hooks/usePoolsHandler.tsx index 4df6c19..fd8da0b 100644 --- a/src/hooks/usePoolsHandler.tsx +++ b/src/hooks/usePoolsHandler.tsx @@ -3,31 +3,36 @@ import { notifyError } from './useNotification' import { ExecutionResult } from 'graphql' import { PoolsDocument, Pool, PoolsQuery, LatestPoolDataDocument, execute, PoolData } from '../../.graphclient' import { usePoolsData } from '../context/PoolsDataContext' +import { makeExecutableSchema } from '@graphql-tools/schema' +import { addMocksToSchema } from '@graphql-tools/mock' +import { graphql } from 'graphql' +import { getGraphQlMockData } from '../utils/getMockData' export const usePoolsHandler = () => { const [pools, setPools] = useState>() const { latestPoolsData, setLatestPoolsData } = usePoolsData() - + const [mockData, setMockData] = useState([]) + // fetches all pool entities const fetchPoolsData = useCallback(async () => { const res = await execute(PoolsDocument, {}) if (res?.data) { setPools(res.data.pools) } else { - console.log("NO RESPONSE") + console.log('NO RESPONSE') } }, []) - + // fetches pool's latest data by pool address const fetchLatestPoolData = async (address: string): Promise => { const res = await execute(LatestPoolDataDocument, { address }) if (res?.data.poolDatas[0]) { return res.data.poolDatas[0] } - + return 0 } - + // iterates through all pool addresses and fetches latest pool data for it const fetchLatestPoolsData = useCallback(async (pools: Array) => { const newPoolsData: Array = [] @@ -38,17 +43,41 @@ export const usePoolsHandler = () => { newPoolsData.push(latestPoolData as PoolData) } } - + setLatestPoolsData(newPoolsData) }, []) - + useEffect(() => { fetchPoolsData() }, [fetchPoolsData]) useEffect(() => { - if (pools) fetchLatestPoolsData(pools as Array) + if (process.env.NEXT_PUBLIC_SUBGRAPH_URL) { + if (pools) fetchLatestPoolsData(pools as Array) + } else { + const query = /* GraphQL */ ` + query Query { + posts { + id + address + tokenAvatar1 + tokenAvatar2 + token1 + token2 + totalSupply + supplyAPY + totalBorrowed + borrowAPY + } + } + ` + getGraphQlMockData(query).then((res: any) => { + if (res) { + setMockData(res) + } + }) + } }, [pools]) - return { pools, latestPoolsData } + return { pools, latestPoolsData, mockData } } diff --git a/src/queries/mockQueries.tsx b/src/queries/mockQueries.tsx new file mode 100644 index 0000000..fba7aac --- /dev/null +++ b/src/queries/mockQueries.tsx @@ -0,0 +1,18 @@ +export const schemaString = /* GraphQL */ ` + type Post { + id: ID! + address: String! + tokenAvatar1: String! + tokenAvatar2: String! + token1: String! + token2: String! + totalSupply: String! + supplyAPY: String! + totalBorrowed: String! + borrowAPY: String! + } + + type Query { + posts: [Post]! + } +` diff --git a/src/utils/getMockData.tsx b/src/utils/getMockData.tsx new file mode 100644 index 0000000..b052ec4 --- /dev/null +++ b/src/utils/getMockData.tsx @@ -0,0 +1,39 @@ +import { makeExecutableSchema } from '@graphql-tools/schema' +import { addMocksToSchema } from '@graphql-tools/mock' +import { graphql } from 'graphql' +import { schemaString } from '../queries/mockQueries' +import { faker } from '@faker-js/faker' + +export const getGraphQlMockData = (query: string) => { + const schema = makeExecutableSchema({ typeDefs: schemaString }) + + // Create a new schema with mocks + const schemaWithMocks = addMocksToSchema({ + schema, + mocks: { + Post: () => ({ + id: faker.datatype.number(), + address: faker.finance.ethereumAddress(), + tokenAvatar1: faker.image.avatar(), + tokenAvatar2: faker.image.avatar(), + token1: faker.random.alpha({ count: 3, casing: 'upper' }), + token2: faker.random.alpha({ count: 3, casing: 'upper' }), + totalSupply: faker.finance.amount(1000, 4000, 2, '$'), + supplyAPY: faker.finance.amount(0, 100), + totalBorrowed: faker.finance.amount(1000, 4000, 2, '$'), + borrowAPY: faker.finance.amount(0, 100), + }), + }, + }) + + return graphql({ + schema: schemaWithMocks, + source: query, + }) + .then((result) => { + if (result && result.data && result.data.posts) { + return result.data.posts + } + }) + .catch((err) => console.log('Error', err)) +} From b85411c1c5bb0562c02a712b2e949cfd301b9aa1 Mon Sep 17 00:00:00 2001 From: UsamaSaleem14 Date: Tue, 25 Oct 2022 10:29:06 +0500 Subject: [PATCH 2/3] Added logic to get multiple mock data with reasonable token symbols --- src/utils/getMockData.tsx | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/utils/getMockData.tsx b/src/utils/getMockData.tsx index b052ec4..4182dca 100644 --- a/src/utils/getMockData.tsx +++ b/src/utils/getMockData.tsx @@ -1,5 +1,5 @@ import { makeExecutableSchema } from '@graphql-tools/schema' -import { addMocksToSchema } from '@graphql-tools/mock' +import { addMocksToSchema, MockList } from '@graphql-tools/mock' import { graphql } from 'graphql' import { schemaString } from '../queries/mockQueries' import { faker } from '@faker-js/faker' @@ -11,13 +11,16 @@ export const getGraphQlMockData = (query: string) => { const schemaWithMocks = addMocksToSchema({ schema, mocks: { + Query: () => ({ + posts: () => new MockList(10), + }), Post: () => ({ id: faker.datatype.number(), address: faker.finance.ethereumAddress(), tokenAvatar1: faker.image.avatar(), tokenAvatar2: faker.image.avatar(), - token1: faker.random.alpha({ count: 3, casing: 'upper' }), - token2: faker.random.alpha({ count: 3, casing: 'upper' }), + token1: faker.helpers.arrayElement(['BTC', 'ETH', 'USDT', 'BNB', 'USDC', 'XRP', 'BUSD', 'ADA', 'SOL', 'DOT', 'NEO', 'GRT', 'HNT', 'FTM', 'BAT', 'STX', 'ZIL']), + token2: faker.helpers.arrayElement(['BTC', 'ETH', 'USDT', 'BNB', 'USDC', 'XRP', 'BUSD', 'ADA', 'SOL', 'DOT', 'NEO', 'GRT', 'HNT', 'FTM', 'BAT', 'STX', 'ZIL']), totalSupply: faker.finance.amount(1000, 4000, 2, '$'), supplyAPY: faker.finance.amount(0, 100), totalBorrowed: faker.finance.amount(1000, 4000, 2, '$'), From 753ec10543c69f78910dc0e41724a8c1290b15d5 Mon Sep 17 00:00:00 2001 From: UsamaSaleem14 Date: Tue, 25 Oct 2022 17:14:07 +0500 Subject: [PATCH 3/3] Added json file to get pools mock data --- src/hooks/usePoolsHandler.tsx | 46 +++++----- src/utils/mockdata/PoolsMockData.tsx | 122 +++++++++++++++++++++++++++ 2 files changed, 146 insertions(+), 22 deletions(-) create mode 100644 src/utils/mockdata/PoolsMockData.tsx diff --git a/src/hooks/usePoolsHandler.tsx b/src/hooks/usePoolsHandler.tsx index fd8da0b..472a570 100644 --- a/src/hooks/usePoolsHandler.tsx +++ b/src/hooks/usePoolsHandler.tsx @@ -7,11 +7,12 @@ import { makeExecutableSchema } from '@graphql-tools/schema' import { addMocksToSchema } from '@graphql-tools/mock' import { graphql } from 'graphql' import { getGraphQlMockData } from '../utils/getMockData' +import { PoolsMockData } from '../utils/mockdata/PoolsMockData' export const usePoolsHandler = () => { const [pools, setPools] = useState>() const { latestPoolsData, setLatestPoolsData } = usePoolsData() - const [mockData, setMockData] = useState([]) + const [mockData, setMockData] = useState([]) // fetches all pool entities const fetchPoolsData = useCallback(async () => { @@ -55,27 +56,28 @@ export const usePoolsHandler = () => { if (process.env.NEXT_PUBLIC_SUBGRAPH_URL) { if (pools) fetchLatestPoolsData(pools as Array) } else { - const query = /* GraphQL */ ` - query Query { - posts { - id - address - tokenAvatar1 - tokenAvatar2 - token1 - token2 - totalSupply - supplyAPY - totalBorrowed - borrowAPY - } - } - ` - getGraphQlMockData(query).then((res: any) => { - if (res) { - setMockData(res) - } - }) + setMockData(PoolsMockData) + // const query = /* GraphQL */ ` + // query Query { + // posts { + // id + // address + // tokenAvatar1 + // tokenAvatar2 + // token1 + // token2 + // totalSupply + // supplyAPY + // totalBorrowed + // borrowAPY + // } + // } + // ` + // getGraphQlMockData(query).then((res: any) => { + // if (res) { + // setMockData(res) + // } + // }) } }, [pools]) diff --git a/src/utils/mockdata/PoolsMockData.tsx b/src/utils/mockdata/PoolsMockData.tsx new file mode 100644 index 0000000..d573e25 --- /dev/null +++ b/src/utils/mockdata/PoolsMockData.tsx @@ -0,0 +1,122 @@ +export const PoolsMockData = [ + { + id: 1, + address: '0xA1dA358C499e90711c7aFd49763b23D0382Ac1af', + tokenAvatar1: '/crypto/eth.svg', + tokenAvatar2: '/crypto/comp.svg', + token1: 'ETH', + token2: 'COMP', + totalSupply: '$1245', + supplyAPY: '79.13%', + totalBorrowed: '$1200', + borrowAPY: '14.08%', + }, + { + id: 2, + address: '0x5FbDB2315678afecb367f032d93F642f64180aa3', + tokenAvatar1: '/crypto/bat.svg', + tokenAvatar2: '/crypto/dai.svg', + token1: 'BAT', + token2: 'DAI', + totalSupply: '$7546', + supplyAPY: '55.04%', + totalBorrowed: '$8766', + borrowAPY: '84.55%', + }, + { + id: 3, + address: '0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512', + tokenAvatar1: '/crypto/uni.svg', + tokenAvatar2: '/crypto/eth.svg', + token1: 'UNI', + token2: 'ETH', + totalSupply: '$4315', + supplyAPY: '75.05%', + totalBorrowed: '$4610', + borrowAPY: '12.33%', + }, + { + id: 4, + address: '0x9fE46736679d2D9a65F0992F2272dE9f3c7fa6e0', + tokenAvatar1: '/crypto/usdt.svg', + tokenAvatar2: '/crypto/link.svg', + token1: 'USDT', + token2: 'LINK', + totalSupply: '$7461', + supplyAPY: '11.11%', + totalBorrowed: '$2317', + borrowAPY: '12.88%', + }, + { + id: 5, + address: '0xDc64a140Aa3E981100a9becA4E685f962f0cF6C9', + tokenAvatar1: '/crypto/usdc.svg', + tokenAvatar2: '/crypto/matic.svg', + token1: 'USDC', + token2: 'MATIC', + totalSupply: '$8765', + supplyAPY: '44.56%', + totalBorrowed: '$8456', + borrowAPY: '11.99%', + }, + { + id: 6, + address: '0x5FC8d32690cc91D4c39d9d3abcBD16989F875707', + tokenAvatar1: '/crypto/link.svg', + tokenAvatar2: '/crypto/uni.svg', + token1: 'LINK', + token2: 'UNI', + totalSupply: '$7961', + supplyAPY: '11.79%', + totalBorrowed: '$1794', + borrowAPY: '71.49%', + }, + { + id: 7, + address: '0xa513E6E4b8f2a923D98304ec87F64353C4D5C853', + tokenAvatar1: '/crypto/wbtc.svg', + tokenAvatar2: '/crypto/usdc.svg', + token1: 'WBTC', + token2: 'USDC', + totalSupply: '$7641', + supplyAPY: '11.79%', + totalBorrowed: '$4655', + borrowAPY: '62.65%', + }, + { + id: 8, + address: '0xD1f1bbbF65CceB5cAf1691a76c17D4E75213B69c', + tokenAvatar1: '/crypto/comp.svg', + tokenAvatar2: '/crypto/usdt.svg', + token1: 'COMP', + token2: 'USDT', + totalSupply: '$1377', + supplyAPY: '79.55%', + totalBorrowed: '$1379', + borrowAPY: '55.66%', + }, + { + id: 9, + address: '0x9fE46736679d2D9a65F0992F2272dE9f3c7fa6e0', + tokenAvatar1: '/crypto/dai.svg', + tokenAvatar2: '/crypto/wbtc.svg', + token1: 'DAI', + token2: 'WBTC', + totalSupply: '$7931', + supplyAPY: '12.07%', + totalBorrowed: '$7974', + borrowAPY: '36.33%', + }, + { + id: 10, + address: '0xD1f1bbbF65CceB5cAf1691a76c17D4E75213B69c', + tokenAvatar1: '/crypto/bat.svg', + tokenAvatar2: '/crypto/aave.svg', + token1: 'BAT', + token2: 'AAVE', + totalSupply: '$9778', + supplyAPY: '12.79%', + totalBorrowed: '$7913', + borrowAPY: '17.88%', + }, +]