@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.
- package/.turbo/turbo-build.log +18 -0
- package/CHANGELOG.md +91 -0
- package/LICENSE +674 -0
- package/dist/abis/ICake.d.ts +92 -0
- package/dist/abis/ICake.d.ts.map +1 -0
- package/dist/abis/ICakeFlexibleSideVaultV2.d.ts +378 -0
- package/dist/abis/ICakeFlexibleSideVaultV2.d.ts.map +1 -0
- package/dist/abis/ICakeVaultV2.d.ts +750 -0
- package/dist/abis/ICakeVaultV2.d.ts.map +1 -0
- package/dist/abis/ISmartChef.d.ts +523 -0
- package/dist/abis/ISmartChef.d.ts.map +1 -0
- package/dist/abis/ISousChef.d.ts +212 -0
- package/dist/abis/ISousChef.d.ts.map +1 -0
- package/dist/abis/ISousChefBNB.d.ts +279 -0
- package/dist/abis/ISousChefBNB.d.ts.map +1 -0
- package/dist/abis/ISousChefV2.d.ts +264 -0
- package/dist/abis/ISousChefV2.d.ts.map +1 -0
- package/dist/abis/ISousChefV3.d.ts +523 -0
- package/dist/abis/ISousChefV3.d.ts.map +1 -0
- package/dist/constants/contracts.d.ts +22 -0
- package/dist/constants/contracts.d.ts.map +1 -0
- package/dist/constants/index.d.ts +8 -0
- package/dist/constants/index.d.ts.map +1 -0
- package/dist/constants/pools/1.d.ts +5 -0
- package/dist/constants/pools/1.d.ts.map +1 -0
- package/dist/constants/pools/56.d.ts +4 -0
- package/dist/constants/pools/56.d.ts.map +1 -0
- package/dist/constants/pools/97.d.ts +5 -0
- package/dist/constants/pools/97.d.ts.map +1 -0
- package/dist/constants/pools/index.d.ts +15 -0
- package/dist/constants/pools/index.d.ts.map +1 -0
- package/dist/constants/supportedChains.d.ts +4 -0
- package/dist/constants/supportedChains.d.ts.map +1 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +6288 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +6224 -0
- package/dist/index.mjs.map +1 -0
- package/dist/queries/fetchPools.d.ts +37 -0
- package/dist/queries/fetchPools.d.ts.map +1 -0
- package/dist/queries/fetchUserIfo.d.ts +16 -0
- package/dist/queries/fetchUserIfo.d.ts.map +1 -0
- package/dist/queries/fetchUserPoolsData.d.ts +16 -0
- package/dist/queries/fetchUserPoolsData.d.ts.map +1 -0
- package/dist/queries/fetchVaultPublic.d.ts +39 -0
- package/dist/queries/fetchVaultPublic.d.ts.map +1 -0
- package/dist/queries/fetchVaultUser.d.ts +12 -0
- package/dist/queries/fetchVaultUser.d.ts.map +1 -0
- package/dist/queries/getAddresses.d.ts +4 -0
- package/dist/queries/getAddresses.d.ts.map +1 -0
- package/dist/queries/index.d.ts +7 -0
- package/dist/queries/index.d.ts.map +1 -0
- package/dist/types.d.ts +176 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/utils/apr.d.ts +11 -0
- package/dist/utils/apr.d.ts.map +1 -0
- package/dist/utils/getContractAddress.d.ts +4 -0
- package/dist/utils/getContractAddress.d.ts.map +1 -0
- package/dist/utils/getPoolContractBySousId.d.ts +35 -0
- package/dist/utils/getPoolContractBySousId.d.ts.map +1 -0
- package/dist/utils/index.d.ts +6 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/isLegacyPool.d.ts +4 -0
- package/dist/utils/isLegacyPool.d.ts.map +1 -0
- package/dist/utils/isPoolsSupported.d.ts +3 -0
- package/dist/utils/isPoolsSupported.d.ts.map +1 -0
- package/package.json +40 -0
- package/src/abis/ICake.ts +59 -0
- package/src/abis/ICakeFlexibleSideVaultV2.ts +487 -0
- package/src/abis/ICakeVaultV2.ts +487 -0
- package/src/abis/ISmartChef.ts +326 -0
- package/src/abis/ISousChef.ts +122 -0
- package/src/abis/ISousChefBNB.ts +166 -0
- package/src/abis/ISousChefV2.ts +341 -0
- package/src/abis/ISousChefV3.ts +326 -0
- package/src/constants/contracts.ts +26 -0
- package/src/constants/index.ts +10 -0
- package/src/constants/pools/1.ts +80 -0
- package/src/constants/pools/56.ts +2933 -0
- package/src/constants/pools/97.ts +74 -0
- package/src/constants/pools/index.ts +44 -0
- package/src/constants/supportedChains.ts +5 -0
- package/src/index.ts +14 -0
- package/src/queries/fetchPools.ts +350 -0
- package/src/queries/fetchUserIfo.ts +53 -0
- package/src/queries/fetchUserPoolsData.ts +143 -0
- package/src/queries/fetchVaultPublic.ts +175 -0
- package/src/queries/fetchVaultUser.ts +106 -0
- package/src/queries/getAddresses.ts +12 -0
- package/src/queries/index.ts +6 -0
- package/src/types.ts +207 -0
- package/src/utils/apr.ts +35 -0
- package/src/utils/getContractAddress.ts +11 -0
- package/src/utils/getPoolContractBySousId.ts +111 -0
- package/src/utils/index.ts +5 -0
- package/src/utils/isLegacyPool.ts +15 -0
- package/src/utils/isPoolsSupported.ts +5 -0
- package/tsconfig.json +14 -0
- package/tsup.config.ts +26 -0
- 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
|
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
|
+
}
|