Skip to content

Commit

Permalink
Fix user yield logic (#87)
Browse files Browse the repository at this point in the history
* fix user yield logic

* fix prop filter

* some refactoring and fixes

* typings

---------

Co-authored-by: Sorizen <[email protected]>
  • Loading branch information
FedokDL and Sorizen authored Aug 22, 2024
1 parent 6b69eeb commit 86d3f2e
Show file tree
Hide file tree
Showing 12 changed files with 167 additions and 107 deletions.
3 changes: 2 additions & 1 deletion .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ VITE_PORT=8095
VITE_APP_NAME='Morpheus Dashboard'
VITE_APP_DESCRIPTION='Morpheus Dashboard: capital, community, coders, compute'
VITE_APP_URL='https://morpheus.206.189.243.3.sslip.io'
VITE_APP_GRAPHQL_API_URL='https://api.thegraph.com/subgraphs/name/ruslanprogrammer/morpheus-dashboard'
VITE_APP_TESTNET_GRAPHQL_API_URL='https://api.studio.thegraph.com/query/73688/kkk/version/latest'
VITE_APP_MAINNET_GRAPHQL_API_URL='https://api.studio.thegraph.com/query/67225/morpheus-dashboard/version/latest'
VITE_APP_WALLET_CONNECT_PROJECT_ID='abcdefghijklmnopqrstuvwxyz'
#VITE_APP_BUILD_VERSION='1.0.0'

Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@
"postcss-html": "^1.5.0",
"prettier": "^2.8.1",
"rollup-plugin-visualizer": "^5.9.0",
"sass": "^1.57.1",
"sass": "1.57.1",
"stylelint": "^15.6.1",
"stylelint-config-recommended-vue": "^1.4.0",
"stylelint-config-standard-scss": "^9.0.0",
Expand Down
4 changes: 2 additions & 2 deletions src/common/InfoBar.vue
Original file line number Diff line number Diff line change
Expand Up @@ -52,11 +52,11 @@ withDefaults(
subtitle: string
status: 'public' | 'private'
title: string
description: string
indicators: InfoBarType.Indicator[]
isLoading?: boolean
description?: string
}>(),
{ isLoading: false },
{ isLoading: false, description: '' },
)
</script>

Expand Down
6 changes: 5 additions & 1 deletion src/common/InfoDashboard/const.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,11 @@ export const CHART_CONFIG: Readonly<ChartConfig> = Object.freeze({
},
ticks: {
color: '#ffffff',
callback: (val: unknown) => String(val).replace(/000$/, 'K'),
callback: (val: unknown) => {
let fixedVal = Number(val).toFixed(3)
fixedVal = parseFloat(fixedVal).toString()
return fixedVal.replace(/000$/, 'K')
},
stepSize: 5000,
},
},
Expand Down
200 changes: 111 additions & 89 deletions src/common/InfoDashboard/helpers.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
import { Time, hexlify, BigNumber } from '@/utils'
import { BigNumber, hexlify, Time } from '@/utils'
import { gql } from '@apollo/client'
import { config } from '@config'
import { config, NETWORK_IDS } from '@config'
import { mapKeys, mapValues } from 'lodash'

type ChartData = Record<number, BigNumber>
import {
PoolInteraction,
YieldQueryData,
ChartQueryData,
ChartData,
} from '@/types'

const ONE_DAY_TIMESTAMP = 24 * 60 * 60
const DECIMAL = BigNumber.from(10).pow(25)
Expand All @@ -12,11 +16,18 @@ export async function getChartData(
poolId: number,
poolStartedAt: BigNumber,
month: number,
type: NETWORK_IDS,
): Promise<ChartData> {
type QueryData = Record<`r${number}`, { totalStaked?: string }[]>
const { data } = await config.apolloClient.query<QueryData>({
const query = {
query: _generateTotalStakedPerDayGraphqlQuery(poolId, poolStartedAt, month),
})
}

const apolloClient =
type === NETWORK_IDS.mainnet
? config.mainnetApolloClient
: config.testnetApolloClient

const { data } = await apolloClient.query<ChartQueryData>(query)

return mapValues(
mapKeys(data, (_, key) => key.slice(1)),
Expand Down Expand Up @@ -55,11 +66,10 @@ function _generateTotalStakedPerDayGraphqlQuery(
for (let date = startDate; date <= endDate; date++) {
const timestamp = monthTime.timestamp + date * ONE_DAY_TIMESTAMP

// eslint-disable-next-line prettier/prettier
const request = REQUEST_PATTERN
.replace('{{date}}', date.toString())
// eslint-disable-next-line prettier/prettier
.replace('{{timestamp}}', timestamp.toString())
const request = REQUEST_PATTERN.replace(
'{{date}}',
date.toString(),
).replace('{{timestamp}}', timestamp.toString())

requests.push(request)
}
Expand All @@ -73,82 +83,64 @@ export async function getUserYieldPerDayChartData(
poolId: number,
user: string,
month: number,
type: NETWORK_IDS,
): Promise<ChartData> {
type PoolIntercation = {
timestamp: string
rate: string
const query = {
query: _generateUserYieldPerDayGraphqlQuery(poolId, user, month),
}

type QueryData = {
userInteractions: {
timestamp: string
rate: string
deposited: string
claimedRewards: string
pendingRewards: string
}[]
poolInteractions: PoolIntercation[]
}
const apolloClient =
type === NETWORK_IDS.mainnet
? config.mainnetApolloClient
: config.testnetApolloClient

// Get data from TheGraph
const { data } = await config.apolloClient.query<QueryData>({
query: _generateUserYieldPerDayGraphqlQuery(poolId, user, month),
})
const { data } = await apolloClient.query<YieldQueryData>(query)

// START leave yields only at the end of the calculation day
const poolInteractionsMap = new Map<string, PoolIntercation>()
data.poolInteractions.forEach(interaction => {
const { timestamp } = interaction
const date = new Date(Number(timestamp) * 1000)
const day = date.toISOString().split('T')[0]
const poolInteractions: PoolInteraction[] = Object.keys(data)
.filter(prop => prop.includes('day') && data[prop].length > 0)
.map(prop => data[prop][0])

if (
!poolInteractionsMap.has(day) ||
Number(timestamp) > Number(poolInteractionsMap.get(day)!.timestamp)
) {
poolInteractionsMap.set(day, interaction)
}
})
const poolInteractions = Array.from(poolInteractionsMap.values())
// END
const userInteractions = [
...data.initialUserInteractions.slice(0, 1),
...data.userInteractions,
]

const fromDate = new Time(String(month + 1), 'M').toDate()
const fromTimestamp = fromDate.getTime() / 1000

// START calculate rewards
const yields: ChartData = {}
for (let i = 0; i < data.userInteractions.length; i++) {
const ui = data.userInteractions[i]
const nextUserIntercation =
i < data.userInteractions.length - 1
? data.userInteractions[i + 1]
: undefined

// Get `poolInteractions` periods between `userIntercationsYield`
// When `userInteraction` is last, get all periods that greater then current
const periodPoolInteractions = poolInteractions.filter(e => {
return (
Number(e.timestamp) > Number(ui.timestamp) &&
(nextUserIntercation
? Number(e.timestamp) < Number(nextUserIntercation.timestamp)
: true)
)
})

// Calculate current yield from the `userIntercations` and push
const uiv = BigNumber.from(ui.claimedRewards).add(ui.pendingRewards)
yields[Number(ui.timestamp)] = uiv
userInteractions.forEach((userInteraction, index) => {
const nextUserInteraction = userInteractions[index + 1]

const userInteractionValue = BigNumber.from(
userInteraction.claimedRewards,
).add(userInteraction.pendingRewards)

// Calculate nex period yields from the `poolIntercations` and push
periodPoolInteractions.forEach(pi => {
const rateDiff = BigNumber.from(pi.rate).sub(ui.rate)
const periodReward = BigNumber.from(ui.deposited)
if (Number(userInteraction.timestamp) > fromTimestamp) {
yields[Number(userInteraction.timestamp)] = userInteractionValue
}

const periodPoolInteractions = poolInteractions.filter(
poolInteraction =>
Number(poolInteraction.timestamp) > Number(userInteraction.timestamp) &&
(!nextUserInteraction ||
Number(poolInteraction.timestamp) <
Number(nextUserInteraction.timestamp)),
)

periodPoolInteractions.forEach(poolInteraction => {
const rateDiff = BigNumber.from(poolInteraction.rate).sub(
userInteraction.rate,
)
const periodReward = BigNumber.from(userInteraction.deposited)
.mul(rateDiff)
.div(DECIMAL)

const value = uiv.add(periodReward)

yields[Number(pi.timestamp)] = value
yields[Number(poolInteraction.timestamp)] =
userInteractionValue.add(periodReward)
})
}
// END
})

return yields
}
Expand All @@ -159,46 +151,76 @@ function _generateUserYieldPerDayGraphqlQuery(
// TODO: add month
month: number,
) {
const fromTimestamp =
new Time(String(month + 1), 'M').toDate().getTime() / 1000
const toTimestamp = new Time(String(month + 2), 'M').toDate().getTime() / 1000
const fromDate = new Time(String(month + 1), 'M').toDate()
const toDate = new Time(String(month + 2), 'M').toDate()
const fromTimestamp = fromDate.getTime() / 1000
const toTimestamp = toDate.getTime() / 1000

const REQUEST_PATTERN = `
userInteractions (
const userInteractionsPattern = `
initialUserInteractions: userInteractions (
orderBy: timestamp
orderDirection: asc
orderDirection: desc
where: {
user: "${user}"
poolId: "${poolId.toString()}"
timestamp_gt: ${fromTimestamp}
timestamp_lt: ${toTimestamp}
timestamp_lt: ${fromTimestamp}
}
first: 1
) {
timestamp
rate
deposited
claimedRewards
pendingRewards
}
poolInteractions (
userInteractions (
orderBy: timestamp
orderDirection: asc
where: {
rate_gt: 0
user: "${user}"
poolId: "${poolId.toString()}"
timestamp_gt: ${fromTimestamp}
timestamp_lt: ${toTimestamp}
pool_: {
id: "${hexlify(poolId)}"
}
}
first: 1000
) {
timestamp
rate
deposited
claimedRewards
pendingRewards
}
`

const requests = [REQUEST_PATTERN]
const year = new Date().getFullYear()
const currentMonth = new Date().getMonth()

const dateInMonth =
currentMonth === month
? new Date().getDate()
: new Date(year, month + 1, 0).getDate()

let poolInteractionsPattern = ''
for (let i = 1; i <= dateInMonth; i++) {
poolInteractionsPattern += `
day${i}: poolInteractions (
orderBy: timestamp
orderDirection: desc
where: {
rate_gt: 0
timestamp_lt: ${fromTimestamp + i * 86400}
pool_: {
id: "${hexlify(poolId)}"
}
}
first: 1
) {
timestamp
rate
}
`
}

const requests = [userInteractionsPattern, poolInteractionsPattern]

return gql`
${'{\n' + requests.join('\n') + '\n}'}
Expand Down
3 changes: 3 additions & 0 deletions src/common/InfoDashboard/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,7 @@ const updateSupplyChartData = async (month: number) => {
props.poolId,
props.poolData!.payoutStart,
month,
route.query.network,
)
const monthTime = new Time(String(month + 1), 'M')
Expand All @@ -217,11 +218,13 @@ const updateEarnedMorChartData = async (month: number) => {
props.poolId,
web3ProvidersStore.address,
month,
route.query.network,
)
chartConfig.data.labels = Object.keys(chartData).map(timestamp => {
return new Time(Number(timestamp)).format('DD MMMM')
})
chartConfig.data.datasets[0].data = Object.values(chartData).map(amount =>
Number(formatEther(amount)),
)
Expand Down
15 changes: 11 additions & 4 deletions src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,6 @@ export const config = {
NAME: import.meta.env.VITE_APP_NAME,
DESCRIPTION: import.meta.env.VITE_APP_DESCRIPTION,
URL: import.meta.env.VITE_APP_URL,
GRAPHQL_API_URL: import.meta.env.VITE_APP_GRAPHQL_API_URL,
WALLET_CONNECT_PROJECT_ID: import.meta.env.VITE_APP_WALLET_CONNECT_PROJECT_ID,
BUILD_VERSION: packageJson.version || import.meta.env.VITE_APP_BUILD_VERSION,
LOG_LEVEL: 'trace' as LogLevelDesc,
Expand Down Expand Up @@ -85,6 +84,7 @@ export const config = {
.VITE_APP_L1_FACTORY_TESTNET_CONTRACT_ADDRESS,
L2_FACTORY_TESTNET_CONTRACT_ADDRESS: import.meta.env
.VITE_APP_L2_FACTORY_TESTNET_CONTRACT_ADDRESS,
TESTNET_GRAPHQL_API_URL: import.meta.env.VITE_APP_TESTNET_GRAPHQL_API_URL,

// Mainnet
ERC1967_PROXY_MAINNET_CONTRACT_ADDRESS: import.meta.env
Expand All @@ -99,14 +99,16 @@ export const config = {
.VITE_APP_L1_FACTORY_MAINNET_CONTRACT_ADDRESS,
L2_FACTORY_MAINNET_CONTRACT_ADDRESS: import.meta.env
.VITE_APP_L2_FACTORY_MAINNET_CONTRACT_ADDRESS,
MAINNET_GRAPHQL_API_URL: import.meta.env.VITE_APP_MAINNET_GRAPHQL_API_URL,

metadata: {} as Metadata,

networksMap: {} as Record<NETWORK_IDS, Network>,

chainsMap: {} as Record<ETHEREUM_CHAIN_IDS, EthereumType.Chain>,

apolloClient: {} as ApolloClient<NormalizedCacheObject>,
mainnetApolloClient: {} as ApolloClient<NormalizedCacheObject>,
testnetApolloClient: {} as ApolloClient<NormalizedCacheObject>,
}

Object.assign(config, _mapEnvCfg(import.meta.env))
Expand Down Expand Up @@ -240,8 +242,13 @@ config.chainsMap = {
},
}

config.apolloClient = new ApolloClient({
link: createHttpLink({ uri: config.GRAPHQL_API_URL }),
config.mainnetApolloClient = new ApolloClient({
link: createHttpLink({ uri: config.MAINNET_GRAPHQL_API_URL }),
cache: new InMemoryCache(),
})

config.testnetApolloClient = new ApolloClient({
link: createHttpLink({ uri: config.TESTNET_GRAPHQL_API_URL }),
cache: new InMemoryCache(),
})

Expand Down
Loading

0 comments on commit 86d3f2e

Please sign in to comment.