@pancakeswap/pools 4.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (101) hide show
  1. package/.turbo/turbo-build.log +18 -0
  2. package/CHANGELOG.md +91 -0
  3. package/LICENSE +674 -0
  4. package/dist/abis/ICake.d.ts +92 -0
  5. package/dist/abis/ICake.d.ts.map +1 -0
  6. package/dist/abis/ICakeFlexibleSideVaultV2.d.ts +378 -0
  7. package/dist/abis/ICakeFlexibleSideVaultV2.d.ts.map +1 -0
  8. package/dist/abis/ICakeVaultV2.d.ts +750 -0
  9. package/dist/abis/ICakeVaultV2.d.ts.map +1 -0
  10. package/dist/abis/ISmartChef.d.ts +523 -0
  11. package/dist/abis/ISmartChef.d.ts.map +1 -0
  12. package/dist/abis/ISousChef.d.ts +212 -0
  13. package/dist/abis/ISousChef.d.ts.map +1 -0
  14. package/dist/abis/ISousChefBNB.d.ts +279 -0
  15. package/dist/abis/ISousChefBNB.d.ts.map +1 -0
  16. package/dist/abis/ISousChefV2.d.ts +264 -0
  17. package/dist/abis/ISousChefV2.d.ts.map +1 -0
  18. package/dist/abis/ISousChefV3.d.ts +523 -0
  19. package/dist/abis/ISousChefV3.d.ts.map +1 -0
  20. package/dist/constants/contracts.d.ts +22 -0
  21. package/dist/constants/contracts.d.ts.map +1 -0
  22. package/dist/constants/index.d.ts +8 -0
  23. package/dist/constants/index.d.ts.map +1 -0
  24. package/dist/constants/pools/1.d.ts +5 -0
  25. package/dist/constants/pools/1.d.ts.map +1 -0
  26. package/dist/constants/pools/56.d.ts +4 -0
  27. package/dist/constants/pools/56.d.ts.map +1 -0
  28. package/dist/constants/pools/97.d.ts +5 -0
  29. package/dist/constants/pools/97.d.ts.map +1 -0
  30. package/dist/constants/pools/index.d.ts +15 -0
  31. package/dist/constants/pools/index.d.ts.map +1 -0
  32. package/dist/constants/supportedChains.d.ts +4 -0
  33. package/dist/constants/supportedChains.d.ts.map +1 -0
  34. package/dist/index.d.ts +13 -0
  35. package/dist/index.d.ts.map +1 -0
  36. package/dist/index.js +6288 -0
  37. package/dist/index.js.map +1 -0
  38. package/dist/index.mjs +6224 -0
  39. package/dist/index.mjs.map +1 -0
  40. package/dist/queries/fetchPools.d.ts +37 -0
  41. package/dist/queries/fetchPools.d.ts.map +1 -0
  42. package/dist/queries/fetchUserIfo.d.ts +16 -0
  43. package/dist/queries/fetchUserIfo.d.ts.map +1 -0
  44. package/dist/queries/fetchUserPoolsData.d.ts +16 -0
  45. package/dist/queries/fetchUserPoolsData.d.ts.map +1 -0
  46. package/dist/queries/fetchVaultPublic.d.ts +39 -0
  47. package/dist/queries/fetchVaultPublic.d.ts.map +1 -0
  48. package/dist/queries/fetchVaultUser.d.ts +12 -0
  49. package/dist/queries/fetchVaultUser.d.ts.map +1 -0
  50. package/dist/queries/getAddresses.d.ts +4 -0
  51. package/dist/queries/getAddresses.d.ts.map +1 -0
  52. package/dist/queries/index.d.ts +7 -0
  53. package/dist/queries/index.d.ts.map +1 -0
  54. package/dist/types.d.ts +176 -0
  55. package/dist/types.d.ts.map +1 -0
  56. package/dist/utils/apr.d.ts +11 -0
  57. package/dist/utils/apr.d.ts.map +1 -0
  58. package/dist/utils/getContractAddress.d.ts +4 -0
  59. package/dist/utils/getContractAddress.d.ts.map +1 -0
  60. package/dist/utils/getPoolContractBySousId.d.ts +35 -0
  61. package/dist/utils/getPoolContractBySousId.d.ts.map +1 -0
  62. package/dist/utils/index.d.ts +6 -0
  63. package/dist/utils/index.d.ts.map +1 -0
  64. package/dist/utils/isLegacyPool.d.ts +4 -0
  65. package/dist/utils/isLegacyPool.d.ts.map +1 -0
  66. package/dist/utils/isPoolsSupported.d.ts +3 -0
  67. package/dist/utils/isPoolsSupported.d.ts.map +1 -0
  68. package/package.json +40 -0
  69. package/src/abis/ICake.ts +59 -0
  70. package/src/abis/ICakeFlexibleSideVaultV2.ts +487 -0
  71. package/src/abis/ICakeVaultV2.ts +487 -0
  72. package/src/abis/ISmartChef.ts +326 -0
  73. package/src/abis/ISousChef.ts +122 -0
  74. package/src/abis/ISousChefBNB.ts +166 -0
  75. package/src/abis/ISousChefV2.ts +341 -0
  76. package/src/abis/ISousChefV3.ts +326 -0
  77. package/src/constants/contracts.ts +26 -0
  78. package/src/constants/index.ts +10 -0
  79. package/src/constants/pools/1.ts +80 -0
  80. package/src/constants/pools/56.ts +2933 -0
  81. package/src/constants/pools/97.ts +74 -0
  82. package/src/constants/pools/index.ts +44 -0
  83. package/src/constants/supportedChains.ts +5 -0
  84. package/src/index.ts +14 -0
  85. package/src/queries/fetchPools.ts +350 -0
  86. package/src/queries/fetchUserIfo.ts +53 -0
  87. package/src/queries/fetchUserPoolsData.ts +143 -0
  88. package/src/queries/fetchVaultPublic.ts +175 -0
  89. package/src/queries/fetchVaultUser.ts +106 -0
  90. package/src/queries/getAddresses.ts +12 -0
  91. package/src/queries/index.ts +6 -0
  92. package/src/types.ts +207 -0
  93. package/src/utils/apr.ts +35 -0
  94. package/src/utils/getContractAddress.ts +11 -0
  95. package/src/utils/getPoolContractBySousId.ts +111 -0
  96. package/src/utils/index.ts +5 -0
  97. package/src/utils/isLegacyPool.ts +15 -0
  98. package/src/utils/isPoolsSupported.ts +5 -0
  99. package/tsconfig.json +14 -0
  100. package/tsup.config.ts +26 -0
  101. package/vitest.config.ts +9 -0
@@ -0,0 +1,74 @@
1
+ import { bscTestnetTokens } from '@pancakeswap/tokens'
2
+ import { getAddress } from 'viem'
3
+
4
+ import { PoolCategory, SerializedPool } from '../../types'
5
+
6
+ export const livePools: SerializedPool[] = [
7
+ // {
8
+ // sousId: 0,
9
+ // stakingToken: bscTestnetTokens.cake2,
10
+ // earningToken: bscTestnetTokens.cake2,
11
+ // contractAddress: '0x4c650FB471fe4e0f476fD3437C3411B1122c4e3B',
12
+ // poolCategory: PoolCategory.CORE,
13
+ // tokenPerBlock: '0.01',
14
+ // isFinished: false,
15
+ // },
16
+ {
17
+ sousId: 1,
18
+ stakingToken: bscTestnetTokens.cake2,
19
+ earningToken: bscTestnetTokens.mockA,
20
+ contractAddress: '0xe7080E3afDfF2322080B5ba85700FE41287D864B',
21
+ poolCategory: PoolCategory.CORE,
22
+ tokenPerSecond: '0.01',
23
+ },
24
+ {
25
+ sousId: 2,
26
+ stakingToken: bscTestnetTokens.mockA,
27
+ earningToken: bscTestnetTokens.mockB,
28
+ contractAddress: '0x31a069925fb770202b302c7911af1acbe0395420',
29
+ poolCategory: PoolCategory.CORE,
30
+ tokenPerSecond: '0.01',
31
+ },
32
+ {
33
+ sousId: 3,
34
+ stakingToken: bscTestnetTokens.wbnb,
35
+ earningToken: bscTestnetTokens.cake2,
36
+ contractAddress: '0x550d3a43D5CB57E70dD1F53699CEaA0f371ADbBb',
37
+ poolCategory: PoolCategory.CORE,
38
+ tokenPerSecond: '0.01',
39
+ },
40
+ {
41
+ sousId: 5,
42
+ stakingToken: bscTestnetTokens.msix,
43
+ earningToken: bscTestnetTokens.cake2,
44
+ contractAddress: '0xf45c9e61318006Dc31CA4993b8ab75E611fe0792',
45
+ poolCategory: PoolCategory.CORE,
46
+ tokenPerSecond: '0.0001',
47
+ },
48
+ {
49
+ sousId: 6,
50
+ stakingToken: bscTestnetTokens.cake2,
51
+ earningToken: bscTestnetTokens.msix,
52
+ contractAddress: '0xeB019927EB2d79b6A03B728a6f7A9020f3e2E25f',
53
+ poolCategory: PoolCategory.CORE,
54
+ tokenPerSecond: '1',
55
+ },
56
+ {
57
+ sousId: 7,
58
+ stakingToken: bscTestnetTokens.cake2,
59
+ earningToken: bscTestnetTokens.msix,
60
+ contractAddress: '0xd41F619f2f2E91F77054877Ed1a47661f290d19e',
61
+ poolCategory: PoolCategory.CORE,
62
+ tokenPerSecond: '0.1',
63
+ },
64
+ ].map((p) => ({
65
+ ...p,
66
+ contractAddress: getAddress(p.contractAddress, 97),
67
+ stakingToken: p.stakingToken.serialize,
68
+ earningToken: p.earningToken.serialize,
69
+ }))
70
+
71
+ // known finished pools
72
+ export const finishedPools: SerializedPool[] = []
73
+
74
+ export const pools: SerializedPool[] = [...livePools, ...finishedPools]
@@ -0,0 +1,44 @@
1
+ import { ChainId } from '@pancakeswap/sdk'
2
+
3
+ import { pools as ethPools, livePools as ethLivePools } from './1'
4
+ import { pools as bscPools, livePools as bscLivePools } from './56'
5
+ import { pools as bscTestnetPools, livePools as bscTestnetLivePools } from './97'
6
+ import { SerializedPool } from '../../types'
7
+ import { SupportedChainId } from '../supportedChains'
8
+ import { isPoolsSupported } from '../../utils/isPoolsSupported'
9
+
10
+ export type PoolsConfigByChain<TChainId extends ChainId> = {
11
+ [chainId in TChainId]: SerializedPool[]
12
+ }
13
+
14
+ export const POOLS_CONFIG_BY_CHAIN = {
15
+ [ChainId.ETHEREUM]: ethPools,
16
+ [ChainId.BSC]: bscPools,
17
+ [ChainId.BSC_TESTNET]: bscTestnetPools,
18
+ } as PoolsConfigByChain<SupportedChainId>
19
+
20
+ export const LIVE_POOLS_CONFIG_BY_CHAIN = {
21
+ [ChainId.ETHEREUM]: ethLivePools,
22
+ [ChainId.BSC]: bscLivePools,
23
+ [ChainId.BSC_TESTNET]: bscTestnetLivePools,
24
+ } as PoolsConfigByChain<SupportedChainId>
25
+
26
+ export const getPoolsConfig = (chainId: ChainId) => {
27
+ if (!isPoolsSupported(chainId)) {
28
+ return undefined
29
+ }
30
+ return POOLS_CONFIG_BY_CHAIN[chainId]
31
+ }
32
+
33
+ export const getLivePoolsConfig = (chainId: ChainId) => {
34
+ if (!isPoolsSupported(chainId)) {
35
+ return undefined
36
+ }
37
+ return LIVE_POOLS_CONFIG_BY_CHAIN[chainId]
38
+ }
39
+
40
+ export const MAX_LOCK_DURATION = 31536000
41
+ export const UNLOCK_FREE_DURATION = 604800
42
+ export const ONE_WEEK_DEFAULT = 604800
43
+ export const BOOST_WEIGHT = 20000000000000n
44
+ export const DURATION_FACTOR = 31536000n
@@ -0,0 +1,5 @@
1
+ import { ChainId } from '@pancakeswap/sdk'
2
+
3
+ export const SUPPORTED_CHAIN_IDS = [ChainId.BSC, ChainId.BSC_TESTNET, ChainId.ETHEREUM] as const
4
+
5
+ export type SupportedChainId = (typeof SUPPORTED_CHAIN_IDS)[number]
package/src/index.ts ADDED
@@ -0,0 +1,14 @@
1
+ export * from './constants'
2
+ export * from './types'
3
+ export * from './queries'
4
+ export * from './utils'
5
+
6
+ // abi
7
+ export * from './abis/ICake'
8
+ export * from './abis/ICakeFlexibleSideVaultV2'
9
+ export * from './abis/ICakeVaultV2'
10
+ export * from './abis/ISmartChef'
11
+ export * from './abis/ISousChef'
12
+ export * from './abis/ISousChefBNB'
13
+ export * from './abis/ISousChefV2'
14
+ export * from './abis/ISousChefV3'
@@ -0,0 +1,350 @@
1
+ import BigNumber from 'bignumber.js'
2
+ import fromPairs from 'lodash/fromPairs'
3
+ import chunk from 'lodash/chunk'
4
+ import { BIG_ZERO } from '@pancakeswap/utils/bigNumber'
5
+ import { ChainId } from '@pancakeswap/sdk'
6
+ import { erc20ABI } from 'wagmi'
7
+
8
+ import { BSC_BLOCK_TIME, getPoolsConfig } from '../constants'
9
+ import { sousChefABI } from '../abis/ISousChef'
10
+ import { sousChefV2ABI } from '../abis/ISousChefV2'
11
+ import { smartChefABI } from '../abis/ISmartChef'
12
+ import { sousChefV3ABI } from '../abis/ISousChefV3'
13
+ import { LegacySerializedPool, OnChainProvider, UpgradedSerializedPool } from '../types'
14
+ import { isLegacyPool, isUpgradedPool } from '../utils'
15
+
16
+ const getLivePoolsWithEnd = async (chainId: ChainId) => {
17
+ const poolsConfig = getPoolsConfig(chainId)
18
+ if (!poolsConfig) {
19
+ return null
20
+ }
21
+ return poolsConfig.filter((p) => p.sousId !== 0 && !p.isFinished)
22
+ }
23
+
24
+ async function fetchUpgradedPoolsTimeLimits(
25
+ pools: UpgradedSerializedPool[],
26
+ chainId: ChainId,
27
+ provider: OnChainProvider,
28
+ ) {
29
+ if (!pools.length) {
30
+ return []
31
+ }
32
+
33
+ const calls = pools.flatMap(({ contractAddress }) => {
34
+ return [
35
+ {
36
+ abi: smartChefABI,
37
+ address: contractAddress,
38
+ functionName: 'startTimestamp',
39
+ },
40
+ {
41
+ abi: smartChefABI,
42
+ address: contractAddress,
43
+ functionName: 'endTimestamp',
44
+ },
45
+ ] as const
46
+ })
47
+
48
+ const client = provider({ chainId })
49
+ const startEndRaw = await client.multicall({
50
+ contracts: calls,
51
+ allowFailure: false,
52
+ })
53
+
54
+ const startEndResult = startEndRaw.reduce<bigint[][]>((resultArray, item, index) => {
55
+ const chunkIndex = Math.floor(index / 2)
56
+
57
+ if (!resultArray[chunkIndex]) {
58
+ // eslint-disable-next-line no-param-reassign
59
+ resultArray[chunkIndex] = [] // start a new chunk
60
+ }
61
+
62
+ resultArray[chunkIndex].push(item)
63
+
64
+ return resultArray
65
+ }, [])
66
+
67
+ return pools.map((cakePoolConfig, index) => {
68
+ const [startTimestamp, endTimestamp] = startEndResult[index]
69
+ return {
70
+ sousId: cakePoolConfig.sousId,
71
+ startTimestamp: Number(startTimestamp),
72
+ endTimestamp: Number(endTimestamp),
73
+ }
74
+ })
75
+ }
76
+
77
+ const fetchLegacyPoolsBlockLimits = async (
78
+ pools: LegacySerializedPool[],
79
+ chainId: ChainId,
80
+ provider: OnChainProvider,
81
+ ) => {
82
+ if (!pools.length) {
83
+ return []
84
+ }
85
+ const startEndBlockCalls = pools.flatMap(({ contractAddress }) => {
86
+ return [
87
+ {
88
+ abi: sousChefABI,
89
+ address: contractAddress,
90
+ functionName: 'startBlock',
91
+ },
92
+ {
93
+ abi: sousChefABI,
94
+ address: contractAddress,
95
+ functionName: 'bonusEndBlock',
96
+ },
97
+ ] as const
98
+ })
99
+
100
+ const client = provider({ chainId })
101
+
102
+ const [block, startEndBlockRaw] = await Promise.all([
103
+ client.getBlock({ blockTag: 'latest' }),
104
+ client.multicall({
105
+ contracts: startEndBlockCalls,
106
+ allowFailure: false,
107
+ }),
108
+ ])
109
+
110
+ const startEndBlockResult = startEndBlockRaw.reduce<bigint[][]>((resultArray, item, index) => {
111
+ const chunkIndex = Math.floor(index / 2)
112
+
113
+ if (!resultArray[chunkIndex]) {
114
+ // eslint-disable-next-line no-param-reassign
115
+ resultArray[chunkIndex] = [] // start a new chunk
116
+ }
117
+
118
+ resultArray[chunkIndex].push(item)
119
+
120
+ return resultArray
121
+ }, [])
122
+
123
+ const getTimestampFromBlock = (targetBlock: number) => {
124
+ return Number(block.timestamp) + (targetBlock - Number(block.number)) * BSC_BLOCK_TIME
125
+ }
126
+ return pools.map((cakePoolConfig, index) => {
127
+ const [startBlock, endBlock] = startEndBlockResult[index]
128
+ return {
129
+ sousId: cakePoolConfig.sousId,
130
+ startTimestamp: getTimestampFromBlock(Number(startBlock)),
131
+ endTimestamp: getTimestampFromBlock(Number(endBlock)),
132
+ }
133
+ })
134
+ }
135
+
136
+ export const fetchPoolsTimeLimits = async (chainId: ChainId, provider: OnChainProvider) => {
137
+ const livedPools = await getLivePoolsWithEnd(chainId)
138
+ if (!livedPools) {
139
+ return null
140
+ }
141
+ const upgradedPools = livedPools.filter(isUpgradedPool)
142
+ const legacyPools = livedPools.filter(isLegacyPool)
143
+ const [upgradePoolLimits, legacyPoolLimits] = await Promise.all([
144
+ fetchUpgradedPoolsTimeLimits(upgradedPools, chainId, provider),
145
+ fetchLegacyPoolsBlockLimits(legacyPools, chainId, provider),
146
+ ])
147
+ return [...upgradePoolLimits, ...legacyPoolLimits]
148
+ }
149
+
150
+ export const fetchPoolsTotalStaking = async (chainId: ChainId, provider: OnChainProvider) => {
151
+ const poolsConfig = getPoolsConfig(chainId)
152
+ if (!poolsConfig) {
153
+ return null
154
+ }
155
+ const poolsBalanceOf = poolsConfig.map(({ contractAddress, stakingToken }) => {
156
+ return {
157
+ abi: erc20ABI,
158
+ address: stakingToken.address,
159
+ functionName: 'balanceOf',
160
+ args: [contractAddress],
161
+ } as const
162
+ })
163
+
164
+ const client = provider({ chainId })
165
+ const poolsTotalStaked = await client.multicall({
166
+ contracts: poolsBalanceOf,
167
+ allowFailure: false,
168
+ })
169
+
170
+ return poolsConfig.map((p, index) => ({
171
+ sousId: p.sousId,
172
+ totalStaked: new BigNumber(poolsTotalStaked[index].toString()).toJSON(),
173
+ }))
174
+ }
175
+
176
+ interface FetchingPoolsStakingLimitsParams {
177
+ poolsWithStakingLimit: number[]
178
+ chainId: ChainId
179
+ provider: OnChainProvider
180
+ }
181
+
182
+ export const fetchPoolsStakingLimitsByBlock = async ({
183
+ poolsWithStakingLimit,
184
+ chainId,
185
+ provider,
186
+ }: FetchingPoolsStakingLimitsParams): Promise<{
187
+ [key: string]: { stakingLimit: BigNumber; numberSecondsForUserLimit: number }
188
+ }> => {
189
+ const poolsConfig = getPoolsConfig(chainId)
190
+ if (!poolsConfig) {
191
+ throw new Error(`No pools found on chain ${chainId}`)
192
+ }
193
+
194
+ const validPools = poolsConfig
195
+ .filter(isLegacyPool)
196
+ .filter((p) => p.stakingToken.symbol !== 'BNB' && !p.isFinished)
197
+ .filter((p) => !poolsWithStakingLimit.includes(p.sousId))
198
+
199
+ // Get the staking limit for each valid pool
200
+ const poolStakingCalls = validPools
201
+ .map(({ contractAddress }) => {
202
+ return (['hasUserLimit', 'poolLimitPerUser', 'numberBlocksForUserLimit'] as const).map(
203
+ (method) =>
204
+ ({
205
+ address: contractAddress,
206
+ functionName: method,
207
+ abi: sousChefV2ABI,
208
+ } as const),
209
+ )
210
+ })
211
+ .flat()
212
+
213
+ const client = provider({ chainId })
214
+
215
+ const poolStakingResultRaw = await client.multicall({
216
+ contracts: poolStakingCalls,
217
+ allowFailure: true,
218
+ })
219
+
220
+ const chunkSize = poolStakingCalls.length / validPools.length
221
+ const poolStakingChunkedResultRaw = chunk(poolStakingResultRaw.flat(), chunkSize)
222
+ return fromPairs(
223
+ poolStakingChunkedResultRaw.map((stakingLimitRaw, index) => {
224
+ const hasUserLimit = stakingLimitRaw[0]?.result as boolean
225
+ const stakingLimit =
226
+ hasUserLimit && stakingLimitRaw[1].result ? new BigNumber(stakingLimitRaw[1].result.toString()) : BIG_ZERO
227
+ const numberBlocksForUserLimit = stakingLimitRaw[2].result ? Number(stakingLimitRaw[2].result) : 0
228
+ const numberSecondsForUserLimit = numberBlocksForUserLimit * BSC_BLOCK_TIME
229
+ return [validPools[index].sousId, { stakingLimit, numberSecondsForUserLimit }]
230
+ }),
231
+ )
232
+ }
233
+
234
+ const fetchPoolsStakingLimitsByTime = async ({
235
+ poolsWithStakingLimit,
236
+ chainId,
237
+ provider,
238
+ }: FetchingPoolsStakingLimitsParams): Promise<{
239
+ [key: string]: { stakingLimit: BigNumber; numberSecondsForUserLimit: number }
240
+ }> => {
241
+ const poolsConfig = getPoolsConfig(chainId)
242
+ if (!poolsConfig) {
243
+ throw new Error(`No pools found on chain ${chainId}`)
244
+ }
245
+
246
+ const validPools = poolsConfig
247
+ .filter(isUpgradedPool)
248
+ .filter((p) => p.stakingToken.symbol !== 'BNB' && !p.isFinished)
249
+ .filter((p) => !poolsWithStakingLimit.includes(p.sousId))
250
+
251
+ // Get the staking limit for each valid pool
252
+ const poolStakingCalls = validPools
253
+ .map(({ contractAddress }) => {
254
+ return (['hasUserLimit', 'poolLimitPerUser', 'numberSecondsForUserLimit'] as const).map(
255
+ (method) =>
256
+ ({
257
+ abi: smartChefABI,
258
+ address: contractAddress,
259
+ functionName: method,
260
+ } as const),
261
+ )
262
+ })
263
+ .flat()
264
+
265
+ const client = provider({ chainId })
266
+ const poolStakingResultRaw = await client.multicall({
267
+ contracts: poolStakingCalls,
268
+ allowFailure: true,
269
+ })
270
+ const chunkSize = poolStakingCalls.length / validPools.length
271
+ const poolStakingChunkedResultRaw = chunk(poolStakingResultRaw.flat(), chunkSize)
272
+ return fromPairs(
273
+ poolStakingChunkedResultRaw.map((stakingLimitRaw, index) => {
274
+ const hasUserLimit = stakingLimitRaw[0].result
275
+ const stakingLimit =
276
+ hasUserLimit && stakingLimitRaw[1].result ? new BigNumber(stakingLimitRaw[1].result.toString()) : BIG_ZERO
277
+ const numberSecondsForUserLimit = stakingLimitRaw[2].result ? Number(stakingLimitRaw[2].result) : 0
278
+ return [validPools[index].sousId, { stakingLimit, numberSecondsForUserLimit }]
279
+ }),
280
+ )
281
+ }
282
+
283
+ export const fetchPoolsStakingLimits = async (
284
+ params: FetchingPoolsStakingLimitsParams,
285
+ ): Promise<{
286
+ [key: string]: { stakingLimit: BigNumber; numberSecondsForUserLimit: number }
287
+ }> => {
288
+ const [limitsByTime, limitsByBlock] = await Promise.all([
289
+ fetchPoolsStakingLimitsByTime(params),
290
+ fetchPoolsStakingLimitsByBlock(params),
291
+ ])
292
+ return {
293
+ ...limitsByTime,
294
+ ...limitsByBlock,
295
+ }
296
+ }
297
+
298
+ export const fetchPoolsProfileRequirement = async (
299
+ chainId: ChainId,
300
+ provider: OnChainProvider,
301
+ ): Promise<{
302
+ [key: string]: {
303
+ required: boolean
304
+ thresholdPoints: string
305
+ }
306
+ }> => {
307
+ const poolsConfig = getPoolsConfig(chainId)
308
+ if (!poolsConfig) {
309
+ throw new Error(`No pools found on chain ${chainId}`)
310
+ }
311
+
312
+ const livePoolsWithV3 = poolsConfig.filter(
313
+ (pool) => (isUpgradedPool(pool) || (isLegacyPool(pool) && pool?.version === 3)) && !pool?.isFinished,
314
+ )
315
+ const poolProfileRequireCalls = livePoolsWithV3
316
+ .map(({ contractAddress }) => {
317
+ return (['pancakeProfileIsRequested', 'pancakeProfileThresholdPoints'] as const).map(
318
+ (method) =>
319
+ ({
320
+ abi: sousChefV3ABI,
321
+ address: contractAddress,
322
+ functionName: method,
323
+ } as const),
324
+ )
325
+ })
326
+ .flat()
327
+
328
+ const client = provider({ chainId })
329
+ const poolProfileRequireResultRaw = await client.multicall({
330
+ contracts: poolProfileRequireCalls,
331
+ })
332
+
333
+ const chunkSize = poolProfileRequireCalls.length / livePoolsWithV3.length
334
+ const poolStakingChunkedResultRaw = chunk(poolProfileRequireResultRaw.flat(), chunkSize)
335
+ return fromPairs(
336
+ poolStakingChunkedResultRaw.map((poolProfileRequireRaw, index) => {
337
+ const hasProfileRequired = poolProfileRequireRaw[0].result
338
+ const profileThresholdPoints = poolProfileRequireRaw[1].result
339
+ ? new BigNumber(poolProfileRequireRaw[1].result.toString())
340
+ : BIG_ZERO
341
+ return [
342
+ livePoolsWithV3[index].sousId,
343
+ {
344
+ required: !!hasProfileRequired,
345
+ thresholdPoints: profileThresholdPoints.toJSON(),
346
+ },
347
+ ]
348
+ }),
349
+ )
350
+ }
@@ -0,0 +1,53 @@
1
+ import BigNumber from 'bignumber.js'
2
+ import { BIG_ZERO } from '@pancakeswap/utils/bigNumber'
3
+ import { ChainId } from '@pancakeswap/sdk'
4
+ import { Address, getContract, WalletClient, GetContractReturnType, PublicClient } from 'viem'
5
+
6
+ import { iCakeABI } from '../abis/ICake'
7
+ import { ICAKE } from '../constants/contracts'
8
+ import { OnChainProvider } from '../types'
9
+ import { getContractAddress } from '../utils'
10
+
11
+ export const getIfoCreditAddressContract = (
12
+ chainId: ChainId,
13
+ provider: OnChainProvider,
14
+ walletClient?: WalletClient,
15
+ ): GetContractReturnType<typeof iCakeABI, PublicClient, WalletClient> => {
16
+ const address = getContractAddress(ICAKE, chainId)
17
+ if (!address || address === '0x') {
18
+ throw new Error(`ICAKE not supported on chain ${chainId}`)
19
+ }
20
+
21
+ return getContract({ abi: iCakeABI, address, publicClient: provider({ chainId }), walletClient })
22
+ }
23
+
24
+ export const fetchPublicIfoData = async (chainId: ChainId, provider: OnChainProvider) => {
25
+ try {
26
+ const ifoCreditAddressContract = getIfoCreditAddressContract(chainId, provider)
27
+ const ceiling = await ifoCreditAddressContract.read.ceiling()
28
+ return {
29
+ ceiling: new BigNumber(ceiling.toString()).toJSON(),
30
+ }
31
+ } catch (error) {
32
+ return {
33
+ ceiling: BIG_ZERO.toJSON(),
34
+ }
35
+ }
36
+ }
37
+
38
+ interface Params {
39
+ account: Address
40
+ chainId: ChainId
41
+ provider: OnChainProvider
42
+ }
43
+
44
+ export const fetchUserIfoCredit = async ({ account, chainId, provider }: Params) => {
45
+ try {
46
+ const ifoCreditAddressContract = getIfoCreditAddressContract(chainId, provider)
47
+ const credit = await ifoCreditAddressContract.read.getUserCredit([account])
48
+ return new BigNumber(credit.toString()).toJSON()
49
+ } catch (error) {
50
+ console.error(error)
51
+ return BIG_ZERO.toJSON()
52
+ }
53
+ }
@@ -0,0 +1,143 @@
1
+ import { ChainId } from '@pancakeswap/sdk'
2
+ import BigNumber from 'bignumber.js'
3
+ import uniq from 'lodash/uniq'
4
+ import fromPairs from 'lodash/fromPairs'
5
+ import { erc20ABI } from 'wagmi'
6
+ import { Address } from 'viem'
7
+ import { getPoolsConfig } from '../constants'
8
+ import { sousChefABI } from '../abis/ISousChef'
9
+ import { OnChainProvider, SerializedPool } from '../types'
10
+
11
+ // Pool 0, Cake / Cake is a different kind of contract (master chef)
12
+ // BNB pools use the native BNB token (wrapping ? unwrapping is done at the contract level)
13
+ const getPoolsFactory = (filter: (pool: SerializedPool) => boolean) => (chainId: ChainId) => {
14
+ const poolsConfig = getPoolsConfig(chainId)
15
+ if (!poolsConfig) {
16
+ throw new Error(`Unable to get pools config on chain ${chainId}`)
17
+ }
18
+ return poolsConfig.filter(filter)
19
+ }
20
+ const getNonBnbPools = getPoolsFactory((pool) => pool.stakingToken.symbol !== 'BNB')
21
+ const getBnbPools = getPoolsFactory((pool) => pool.stakingToken.symbol === 'BNB')
22
+ const getNonMasterPools = getPoolsFactory((pool) => pool.sousId !== 0)
23
+
24
+ interface FetchUserDataParams {
25
+ account: string
26
+ chainId: ChainId
27
+ provider: OnChainProvider
28
+ }
29
+
30
+ export const fetchPoolsAllowance = async ({ account, chainId, provider }: FetchUserDataParams) => {
31
+ const nonBnbPools = getNonBnbPools(chainId)
32
+
33
+ const client = provider({ chainId })
34
+ const allowances = await client.multicall({
35
+ contracts: nonBnbPools.map(
36
+ ({ contractAddress, stakingToken }) =>
37
+ ({
38
+ address: stakingToken.address,
39
+ abi: erc20ABI,
40
+ functionName: 'allowance',
41
+ args: [account as Address, contractAddress] as const,
42
+ } as const),
43
+ ),
44
+ allowFailure: false,
45
+ })
46
+ return fromPairs(
47
+ nonBnbPools.map((pool, index) => [pool.sousId, new BigNumber(allowances[index].toString()).toJSON()]),
48
+ )
49
+ }
50
+
51
+ export const fetchUserBalances = async ({ account, chainId, provider }: FetchUserDataParams) => {
52
+ const nonBnbPools = getNonBnbPools(chainId)
53
+ const bnbPools = getBnbPools(chainId)
54
+ // Non BNB pools
55
+ const tokens = uniq(nonBnbPools.map((pool) => pool.stakingToken.address))
56
+ const client = provider({ chainId })
57
+ const tokenBalance = await client.multicall({
58
+ contracts: [
59
+ {
60
+ abi: [
61
+ {
62
+ inputs: [{ internalType: 'address', name: 'addr', type: 'address' }],
63
+ name: 'getEthBalance',
64
+ outputs: [{ internalType: 'uint256', name: 'balance', type: 'uint256' }],
65
+ stateMutability: 'view',
66
+ type: 'function',
67
+ },
68
+ ] as const,
69
+ address: '0xcA11bde05977b3631167028862bE2a173976CA11', // TODO: Here is multicall address, should extract addresses to a package for multi chain
70
+ functionName: 'getEthBalance',
71
+ args: [account as Address] as const,
72
+ } as const,
73
+ ...tokens.map(
74
+ (token) =>
75
+ ({
76
+ abi: erc20ABI,
77
+ address: token,
78
+ functionName: 'balanceOf',
79
+ args: [account] as const,
80
+ } as const),
81
+ ),
82
+ ],
83
+ })
84
+ const [bnbBalance, ...tokenBalancesResults] = tokenBalance
85
+
86
+ const tokenBalances = fromPairs(tokens.map((token, index) => [token, tokenBalancesResults[index].result as bigint]))
87
+
88
+ const poolTokenBalances = fromPairs(
89
+ nonBnbPools
90
+ .map<[number, string] | null>((pool) => {
91
+ if (!tokenBalances[pool.stakingToken.address]) return null
92
+ return [pool.sousId, new BigNumber(tokenBalances[pool.stakingToken.address].toString()).toJSON()]
93
+ })
94
+ .filter((p): p is [number, string] => Boolean(p)),
95
+ )
96
+
97
+ // BNB pools
98
+ const bnbBalanceJson = new BigNumber((bnbBalance.result as bigint).toString()).toJSON()
99
+ const bnbBalances = fromPairs(bnbPools.map((pool) => [pool.sousId, bnbBalanceJson]))
100
+
101
+ return { ...poolTokenBalances, ...bnbBalances }
102
+ }
103
+
104
+ export const fetchUserStakeBalances = async ({ account, chainId, provider }: FetchUserDataParams) => {
105
+ const nonMasterPools = getNonMasterPools(chainId)
106
+
107
+ const client = provider({ chainId })
108
+ const userInfo = await client.multicall({
109
+ contracts: nonMasterPools.map(
110
+ ({ contractAddress }) =>
111
+ ({
112
+ abi: sousChefABI.filter((r) => r.name === 'userInfo'),
113
+ address: contractAddress,
114
+ functionName: 'userInfo',
115
+ args: [account as Address] as const,
116
+ } as const),
117
+ ),
118
+ allowFailure: false,
119
+ })
120
+
121
+ return fromPairs(
122
+ nonMasterPools.map((pool, index) => [pool.sousId, new BigNumber(userInfo[index][0].toString()).toJSON()]),
123
+ )
124
+ }
125
+
126
+ export const fetchUserPendingRewards = async ({ account, chainId, provider }: FetchUserDataParams) => {
127
+ const nonMasterPools = getNonMasterPools(chainId)
128
+
129
+ const client = provider({ chainId })
130
+ const res = await client.multicall({
131
+ contracts: nonMasterPools.map(
132
+ ({ contractAddress }) =>
133
+ ({
134
+ abi: sousChefABI.filter((r) => r.name === 'pendingReward'),
135
+ address: contractAddress,
136
+ functionName: 'pendingReward',
137
+ args: [account as Address] as const,
138
+ } as const),
139
+ ),
140
+ allowFailure: false,
141
+ })
142
+ return fromPairs(nonMasterPools.map((pool, index) => [pool.sousId, new BigNumber(res[index].toString()).toJSON()]))
143
+ }