This repository was archived by the owner on Oct 15, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 13
/
Copy pathusePoolEnrichWithOnChainData.tsx
185 lines (165 loc) · 5.45 KB
/
usePoolEnrichWithOnChainData.tsx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
import { cloneDeep } from 'lodash'
import { Address, formatUnits } from 'viem'
import { useReadContracts } from 'wagmi'
import { useTokens } from '../../tokens/TokensProvider'
import { balancerV3ExtensionVaultAbi } from '../../web3/contracts/abi/balancerV3ExtensionVaultAbi'
import { weightedPoolV3Abi } from '../../web3/contracts/abi/weightedPoolV3Abi'
import { Pool } from '../PoolProvider'
import { BPT_DECIMALS } from '../pool.constants'
import { GqlChain } from '@/lib/shared/services/api/generated/graphql'
import { bn, safeSum } from '@/lib/shared/utils/numbers'
import { getVaultConfig, isCowAmmPool, isV1Pool, isV2Pool, isV3Pool } from '../pool.helpers'
import { getChainId } from '@/lib/config/app.config'
import {
balancerV2ComposableStablePoolV5Abi,
balancerV2VaultAbi,
} from '../../web3/contracts/abi/generated'
import { isComposableStablePool } from '../pool.utils'
import { cowAmmPoolAbi } from '../../web3/contracts/abi/cowAmmAbi'
export function usePoolEnrichWithOnChainData(pool: Pool) {
const { priceFor } = useTokens()
const { isLoading, poolTokenBalances, totalSupply, refetch } = usePoolOnchainData(pool)
const clone = enrichPool({ isLoading, pool, priceFor, poolTokenBalances, totalSupply })
return { isLoading, pool: clone, refetch }
}
/*
We call all queries to avoid breaking the rules of react hooks
but only one query will be executed (the one with enabled: true)
*/
function usePoolOnchainData(pool: Pool) {
const cowAmmResult = useCowPoolOnchainData(pool)
const v2Result = useV2PoolOnchainData(pool)
const v3Result = useV3PoolOnchainData(pool)
if (isCowAmmPool(pool.type)) return cowAmmResult
if (isV2Pool(pool)) return v2Result
if (isV3Pool(pool)) return v3Result
throw new Error(`Unsupported pool: protocolVersion ${pool.protocolVersion}, type ${pool.type}`)
}
function useV3PoolOnchainData(pool: Pool) {
const { vaultAddress } = getVaultConfig(pool)
const chainId = getChainId(pool.chain)
const v3Query = useReadContracts({
query: {
enabled: isV3Pool(pool),
},
allowFailure: false,
contracts: [
{
chainId,
abi: balancerV3ExtensionVaultAbi,
address: vaultAddress,
functionName: 'getPoolTokenInfo',
args: [pool.address as Address],
},
{
chainId,
abi: weightedPoolV3Abi,
address: pool.address as Address,
functionName: 'totalSupply',
args: [],
},
],
})
return {
...v3Query,
poolTokenBalances: v3Query.data?.[0][2],
totalSupply: v3Query.data?.[1],
}
}
function useV2PoolOnchainData(pool: Pool) {
const { vaultAddress } = getVaultConfig(pool)
const chainId = getChainId(pool.chain)
const isComposableStable = isComposableStablePool(pool)
const v2Query = useReadContracts({
query: {
enabled: isV2Pool(pool),
},
allowFailure: false,
contracts: [
{
chainId,
abi: balancerV2VaultAbi,
address: vaultAddress,
functionName: 'getPoolTokens',
args: [pool.id as Address],
},
{
chainId,
// composable stable pool has actual and total supply functions exposed
abi: balancerV2ComposableStablePoolV5Abi,
address: pool.address as Address,
functionName: isComposableStable ? 'getActualSupply' : 'totalSupply',
} as const,
],
})
return {
...v2Query,
poolTokenBalances: v2Query.data?.[0][1],
totalSupply: v2Query.data?.[1],
}
}
/*
We need a custom useReadContracts for cow AMM pools because they are v1 pools
There's no vault in V1 so we get the balances from the pool contract)
*/
function useCowPoolOnchainData(pool: Pool) {
const chainId = getChainId(pool.chain)
const balanceContracts = pool.poolTokens.map(token => {
return {
chainId,
address: pool.address as Address,
abi: cowAmmPoolAbi,
functionName: 'getBalance',
args: [token.address as Address],
} as const
})
const cowQuery = useReadContracts({
query: {
enabled: isV1Pool(pool),
},
allowFailure: false,
contracts: [
...balanceContracts,
{
chainId,
abi: cowAmmPoolAbi,
address: pool.address as Address,
functionName: 'totalSupply',
} as const,
],
})
return {
...cowQuery,
totalSupply: cowQuery.data?.at(-1),
poolTokenBalances: cowQuery.data?.slice(0, -1),
}
}
type Params = {
isLoading: boolean
pool: Pool
priceFor: (address: string, chain: GqlChain) => number
poolTokenBalances: readonly bigint[] | undefined
totalSupply: bigint | undefined
}
function enrichPool({ isLoading, pool, priceFor, poolTokenBalances, totalSupply }: Params) {
if (isLoading || !poolTokenBalances) return pool
const clone = cloneDeep(pool)
const filteredTokens = clone.poolTokens.filter(token =>
pool.displayTokens.find(displayToken => token.address === displayToken.address)
)
clone.poolTokens.forEach((token, index) => {
if (!poolTokenBalances) return
const poolTokenBalance = poolTokenBalances[index]
if (!poolTokenBalance) return
const tokenBalance = formatUnits(poolTokenBalance, token.decimals)
token.balance = tokenBalance
token.balanceUSD = bn(tokenBalance).times(priceFor(token.address, pool.chain)).toString()
})
clone.dynamicData.totalLiquidity = safeSum(
filteredTokens.map(
token => (priceFor(token.address, pool.chain) || 0) * parseFloat(token.balance)
)
)
clone.dynamicData.totalShares = formatUnits(totalSupply || 0n, BPT_DECIMALS)
return clone
}