@stake-dao/reader 0.5.3 → 0.5.5

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 (65) hide show
  1. package/dist/esm/abis/lockersMulticall.js +27 -4
  2. package/dist/esm/abis/lockersMulticall.js.map +1 -1
  3. package/dist/esm/bytecodes/votemarket/batchYbUserVotes.js +39 -0
  4. package/dist/esm/bytecodes/votemarket/batchYbUserVotes.js.map +1 -0
  5. package/dist/esm/bytecodes/votemarket/batchYbVotes.js +13 -0
  6. package/dist/esm/bytecodes/votemarket/batchYbVotes.js.map +1 -0
  7. package/dist/esm/index.js +5 -1
  8. package/dist/esm/index.js.map +1 -1
  9. package/dist/esm/lockers/fetch/parse.js +1 -0
  10. package/dist/esm/lockers/fetch/parse.js.map +1 -1
  11. package/dist/esm/lockers/fetch/protocols/balancer.js +3 -0
  12. package/dist/esm/lockers/fetch/protocols/balancer.js.map +1 -1
  13. package/dist/esm/lockers/fetch/protocols/pendle.js +11 -1
  14. package/dist/esm/lockers/fetch/protocols/pendle.js.map +1 -1
  15. package/dist/esm/prices.js +4 -0
  16. package/dist/esm/prices.js.map +1 -1
  17. package/dist/esm/strategies/v2/parse.js +51 -1
  18. package/dist/esm/strategies/v2/parse.js.map +1 -1
  19. package/dist/esm/votemarket/fetchClaimableData.js +1 -1
  20. package/dist/esm/votemarket/fetchEpochVotes.js +13 -4
  21. package/dist/esm/votemarket/fetchEpochVotes.js.map +1 -1
  22. package/dist/esm/votemarket/generateProofs/config.js +6 -0
  23. package/dist/esm/votemarket/generateProofs/config.js.map +1 -1
  24. package/dist/esm/votemarket/generateProofs/getGaugeProof.js +5 -0
  25. package/dist/esm/votemarket/generateProofs/getGaugeProof.js.map +1 -1
  26. package/dist/esm/votemarket/generateProofs/getUserProof.js +13 -2
  27. package/dist/esm/votemarket/generateProofs/getUserProof.js.map +1 -1
  28. package/dist/esm/votemarket/yb/fetchYbUserVotes.js +42 -0
  29. package/dist/esm/votemarket/yb/fetchYbUserVotes.js.map +1 -0
  30. package/dist/types/abis/lockersMulticall.d.ts.map +1 -1
  31. package/dist/types/bytecodes/votemarket/batchYbUserVotes.d.ts +4 -0
  32. package/dist/types/bytecodes/votemarket/batchYbUserVotes.d.ts.map +1 -0
  33. package/dist/types/bytecodes/votemarket/batchYbVotes.d.ts +4 -0
  34. package/dist/types/bytecodes/votemarket/batchYbVotes.d.ts.map +1 -0
  35. package/dist/types/index.d.ts +4 -1
  36. package/dist/types/index.d.ts.map +1 -1
  37. package/dist/types/lockers/fetch/parse.d.ts +1 -0
  38. package/dist/types/lockers/fetch/parse.d.ts.map +1 -1
  39. package/dist/types/lockers/fetch/protocols/balancer.d.ts.map +1 -1
  40. package/dist/types/lockers/fetch/protocols/pendle.d.ts.map +1 -1
  41. package/dist/types/prices.d.ts.map +1 -1
  42. package/dist/types/strategies/v2/parse.d.ts.map +1 -1
  43. package/dist/types/votemarket/fetchEpochVotes.d.ts.map +1 -1
  44. package/dist/types/votemarket/generateProofs/config.d.ts +6 -0
  45. package/dist/types/votemarket/generateProofs/config.d.ts.map +1 -1
  46. package/dist/types/votemarket/generateProofs/getGaugeProof.d.ts.map +1 -1
  47. package/dist/types/votemarket/generateProofs/getUserProof.d.ts.map +1 -1
  48. package/dist/types/votemarket/yb/fetchYbUserVotes.d.ts +16 -0
  49. package/dist/types/votemarket/yb/fetchYbUserVotes.d.ts.map +1 -0
  50. package/package.json +1 -1
  51. package/src/abis/lockersMulticall.ts +27 -4
  52. package/src/bytecodes/votemarket/batchYbUserVotes.ts +41 -0
  53. package/src/bytecodes/votemarket/batchYbVotes.ts +15 -0
  54. package/src/index.ts +6 -1
  55. package/src/lockers/fetch/parse.ts +2 -0
  56. package/src/lockers/fetch/protocols/balancer.ts +3 -0
  57. package/src/lockers/fetch/protocols/pendle.ts +11 -1
  58. package/src/prices.ts +4 -0
  59. package/src/strategies/v2/parse.ts +62 -1
  60. package/src/votemarket/fetchClaimableData.ts +1 -1
  61. package/src/votemarket/fetchEpochVotes.ts +14 -4
  62. package/src/votemarket/generateProofs/config.ts +6 -0
  63. package/src/votemarket/generateProofs/getGaugeProof.ts +8 -0
  64. package/src/votemarket/generateProofs/getUserProof.ts +15 -2
  65. package/src/votemarket/yb/fetchYbUserVotes.ts +61 -0
package/src/prices.ts CHANGED
@@ -35,6 +35,8 @@ export const getLlamaTokenPrefix = (chainId = 1): string => {
35
35
  return 'avax'
36
36
  case 59144:
37
37
  return 'linea'
38
+ case 42793:
39
+ return 'etherlink'
38
40
  default:
39
41
  return 'ethereum'
40
42
  }
@@ -105,6 +107,8 @@ export const getGeckoTerminalTokenPrefix = (chainId = 1): string => {
105
107
  return 'avax'
106
108
  case 59144:
107
109
  return 'linea'
110
+ case 42793:
111
+ return 'etherlink'
108
112
  default:
109
113
  return 'eth'
110
114
  }
@@ -1,3 +1,4 @@
1
+ import { ONE_YEAR } from '@stake-dao/constants'
1
2
  import { getOnlyboostData } from '@stake-dao/reader'
2
3
  import { formatUnits, zeroAddress } from 'viem'
3
4
  import { arbitrum, base, etherlink, fraxtal, gnosis, mainnet, optimism, sonic } from 'viem/chains'
@@ -68,6 +69,61 @@ export const parseV2Strats = (global: any, rawStrats: any[], extra: any) => {
68
69
  yieldType: 'OFFCHAIN',
69
70
  }))
70
71
 
72
+ // Compute rewards from the hook incentive (Votemarket)
73
+ const hookIncentivesPrices = extra?.hookIncentivesPrices || []
74
+ const gaugeUsd = Number(s.gauge.totalSupplyUSD)
75
+
76
+ const incentivesByToken = (extra?.hookIncentives || [])
77
+ .filter((r) => equalTlc(r.vault, s.address))
78
+ .reduce((acc, r) => {
79
+ const rewardAddress = r.reward
80
+ const price = hookIncentivesPrices.find((p) => equalTlc(rewardAddress, p.address))?.usdPrice || 0
81
+
82
+ const amountToken = Number.parseFloat(formatUnits(r.amount, r.rewardDecimals))
83
+ const duration = Number.parseInt(r.end) - Number.parseInt(r.start)
84
+
85
+ if (duration <= 0) return acc
86
+
87
+ const tokensPerSecond = amountToken / duration
88
+ const yearlyTokens = tokensPerSecond * ONE_YEAR
89
+ const yearlyRewardsUsd = yearlyTokens * price
90
+
91
+ if (!acc[rewardAddress]) {
92
+ acc[rewardAddress] = {
93
+ meta: r,
94
+ price: price,
95
+ totalYearlyUsd: 0,
96
+ maxPeriodFinish: Number.parseInt(r.end),
97
+ }
98
+ }
99
+
100
+ acc[rewardAddress].totalYearlyUsd += yearlyRewardsUsd
101
+ acc[rewardAddress].maxPeriodFinish = Math.max(acc[rewardAddress].maxPeriodFinish, Number.parseInt(r.end))
102
+
103
+ return acc
104
+ }, {})
105
+
106
+ const hookIncentives = Object.values(incentivesByToken).map((group: any) => {
107
+ const { meta, price, totalYearlyUsd, maxPeriodFinish } = group
108
+
109
+ const apr = gaugeUsd > 0 ? (totalYearlyUsd / gaugeUsd) * 100 : 0
110
+
111
+ return {
112
+ token: parseAsset({
113
+ id: meta.id.toString(),
114
+ name: meta.rewardSymbol,
115
+ symbol: meta.rewardSymbol,
116
+ address: meta.reward,
117
+ decimals: meta.rewardDecimals,
118
+ }),
119
+ aprInToken: price > 0 ? apr / price : 0,
120
+ apr,
121
+ streaming: true,
122
+ periodFinish: maxPeriodFinish,
123
+ yieldType: 'VOTEMARKET',
124
+ }
125
+ })
126
+
71
127
  const rewards = otherRewards
72
128
  .map((r) => ({
73
129
  token: parseAsset(r.asset),
@@ -78,6 +134,7 @@ export const parseV2Strats = (global: any, rawStrats: any[], extra: any) => {
78
134
  yieldType: r.yieldType,
79
135
  }))
80
136
  .concat(merklRewards)
137
+ .concat(hookIncentives)
81
138
  .sort((a, b) => {
82
139
  if (a.token.address === baseTokens.curve[s.chainId]) return -1
83
140
  if (b.token.address === baseTokens.curve[s.chainId]) return 1
@@ -154,7 +211,11 @@ export const parseV2Strats = (global: any, rawStrats: any[], extra: any) => {
154
211
 
155
212
  baseRewardAdded = true
156
213
  } else {
157
- aprDetails.push({ label: `${r.token.symbol} APR`, value: [r.apr || 0] })
214
+ const label =
215
+ r.yieldType === 'VOTEMARKET'
216
+ ? `${r.token.symbol} APR (Extra Rewards from Votemarket)`
217
+ : `${r.token.symbol} APR`
218
+ aprDetails.push({ label, value: [r.apr || 0] })
158
219
  }
159
220
  }
160
221
 
@@ -4,7 +4,7 @@ import batchClaimableData from '../bytecodes/votemarket/batchClaimableData.js'
4
4
  import { concatBytecode } from '../index.js'
5
5
  import { batchJsonRpc } from '../utils.js'
6
6
 
7
- const MAX_VOTES_PER_CHUNK = 50
7
+ const MAX_VOTES_PER_CHUNK = 25
8
8
  const MAX_CAMPAIGNS_PER_CHUNKS = 5
9
9
 
10
10
  const chunkCampaignsWithVoteLimit = (campaigns: number[], userVotes: any[]) => {
@@ -2,11 +2,13 @@ import { contracts } from '@stake-dao/constants'
2
2
  import { chunk } from 'lodash-es'
3
3
  import { encodeAbiParameters, parseAbiParameters } from 'viem'
4
4
  import { mainnet } from 'viem/chains'
5
+ import type { BatchMetaData } from '../bytecodes/types.js'
5
6
  import batchPendleVotes from '../bytecodes/votemarket/batchPendleVotes.js'
6
7
  import batchVotes from '../bytecodes/votemarket/batchVotes.js'
8
+ import batchYbVotes from '../bytecodes/votemarket/batchYbVotes.js'
7
9
  import { STAKE_DAO_API } from '../endpoints.js'
8
10
  import { concatBytecode } from '../index.js'
9
- import { batchJsonRpcWithBlocks, equalTlc } from '../utils.js'
11
+ import { batchJsonRpcWithBlocks } from '../utils.js'
10
12
 
11
13
  type Rpcs = {
12
14
  [chainId: number]: string
@@ -37,9 +39,17 @@ export const fetchEpochsVotes = async (rpc: Rpcs, gaugeController: string, user:
37
39
  // Merge blocks
38
40
  const blocksForEpoch = [...cachedBlocks, ...missingBlocks]
39
41
 
40
- const batchVotesProtocol = equalTlc(gaugeController, contracts.pendleGaugeController?.[1] || '')
41
- ? batchPendleVotes
42
- : batchVotes
42
+ let batchVotesProtocol: BatchMetaData = batchVotes
43
+ switch (gaugeController.toLowerCase()) {
44
+ case (contracts.pendleGaugeController?.[1] || '').toLowerCase():
45
+ batchVotesProtocol = batchPendleVotes
46
+ break
47
+ case (contracts.ybGaugeController?.[1] || '').toLowerCase():
48
+ batchVotesProtocol = batchYbVotes
49
+ break
50
+ default:
51
+ batchVotesProtocol = batchVotes
52
+ }
43
53
 
44
54
  const inputData = encodeAbiParameters(parseAbiParameters(batchVotesProtocol.inputType[mainnet.id]!) as any, [
45
55
  gaugeController,
@@ -20,12 +20,18 @@ export const GaugeControllerConstants = {
20
20
  lastUserVote: 1000000010,
21
21
  voteUserSlope: 1000000008,
22
22
  },
23
+ yb: {
24
+ pointWeights: 1000000006,
25
+ lastUserVote: 1000000005,
26
+ voteUserSlope: 1000000003,
27
+ },
23
28
  },
24
29
  GAUGE_CONTROLLER: {
25
30
  curve: '0x2F50D538606Fa9EDD2B11E2446BEb18C9D5846bB',
26
31
  balancer: '0xC128468b7Ce63eA702C1f104D55A2566b13D3ABD',
27
32
  frax: '0x3669C421b77340B2979d1A00a792CC2ee0FcE737',
28
33
  fxn: '0xe60eB8098B34eD775ac44B1ddE864e098C6d7f37',
34
+ yb: '0x1Be14811A3a06F6aF4fA64310a636e1Df04c1c21',
29
35
  },
30
36
  }
31
37
 
@@ -20,6 +20,13 @@ function getGaugeTimeStorageSlot(gauge: `0x${string}`, time: bigint, baseSlot: n
20
20
  return BigInt(finalSlot)
21
21
  }
22
22
 
23
+ function getGaugeTimeStorageSlotYb(gauge: `0x${string}`, _: bigint, baseSlot: number): bigint {
24
+ const gaugeEncoded = keccak256(
25
+ encodeAbiParameters([{ type: 'uint256' }, { type: 'address' }], [BigInt(baseSlot), gauge]),
26
+ )
27
+ return BigInt(gaugeEncoded)
28
+ }
29
+
23
30
  // Function to get storage slot for Curve protocol (pre-Vyper 0.3)
24
31
  function getGaugeTimeStorageSlotPreVyper03(gauge: `0x${string}`, time: bigint, baseSlot: number): bigint {
25
32
  const intermediateHash = _encodeGaugeTime(gauge, time, baseSlot)
@@ -44,6 +51,7 @@ export async function generateGaugeProof(
44
51
 
45
52
  const positionFunctions: Record<string, any> = {
46
53
  curve: getGaugeTimeStorageSlotPreVyper03,
54
+ yb: getGaugeTimeStorageSlotYb,
47
55
  default: getGaugeTimeStorageSlot,
48
56
  }
49
57
 
@@ -53,10 +53,23 @@ export async function generateUserProof(
53
53
  const getPosition = positionFunctions[protocol] || positionFunctions.default
54
54
  const voteUserSlopeSlot = getPosition(user, gaugeAddress, voteUserSlopeBaseSlot)
55
55
 
56
+ let index_additionnal_slots = [2n]
57
+ switch (protocol.toLowerCase()) {
58
+ case 'yb':
59
+ index_additionnal_slots = [1n, 3n]
60
+ break
61
+ default:
62
+ index_additionnal_slots = [2n]
63
+ break
64
+ }
65
+
56
66
  const voteUserSlopeSlope = voteUserSlopeSlot
57
- const voteUserSlopeEnd = voteUserSlopeSlot + 2n
58
67
 
59
- const slots = [toHex(lastUserVoteSlot), toHex(voteUserSlopeSlope), toHex(voteUserSlopeEnd)]
68
+ const slots = [toHex(lastUserVoteSlot), toHex(voteUserSlopeSlope)]
69
+
70
+ for (const index_additionnal_slot of index_additionnal_slots) {
71
+ slots.push(toHex(voteUserSlopeSlot + index_additionnal_slot))
72
+ }
60
73
 
61
74
  const proof = await publicClient.getProof({
62
75
  address: GaugeControllerConstants.GAUGE_CONTROLLER[protocol] as `0x${string}`,
@@ -0,0 +1,61 @@
1
+ import { contracts } from '@stake-dao/constants'
2
+ import { encodeAbiParameters, formatUnits, parseAbiParameters, zeroAddress } from 'viem'
3
+ import { mainnet } from 'viem/chains'
4
+ import batchYbUserVotes from '../../bytecodes/votemarket/batchYbUserVotes.js'
5
+ import { concatBytecode } from '../../index.js'
6
+ import { batchJsonRpc, equalTlc } from '../../utils.js'
7
+
8
+ export type Vote = {
9
+ gauge: string
10
+ slope: string
11
+ relativeWeight: number
12
+ weight: number
13
+ start: number
14
+ end: number
15
+ }
16
+
17
+ export type GaugesUserData = { veBalance: string; unusedVeBalance: string; unusedRelativeWeight: number; votes: Vote[] }
18
+
19
+ export const fetchYbUserVotes = async (rpc: string, user: string): Promise<GaugesUserData> => {
20
+ const calls = [
21
+ concatBytecode(
22
+ batchYbUserVotes.bytecode[mainnet.id]!,
23
+ encodeAbiParameters(parseAbiParameters(batchYbUserVotes.inputType[mainnet.id]!) as any, [
24
+ user,
25
+ contracts.ybGaugeController![1]!,
26
+ contracts.veYB![1]!,
27
+ ]),
28
+ ),
29
+ ]
30
+
31
+ const rawVotes = await batchJsonRpc({
32
+ rpc,
33
+ calls,
34
+ outputTypeAbi: batchYbUserVotes.outputType![mainnet.id],
35
+ parse: false,
36
+ callsKey: `votemarket/yb/fetchYbUserVotes.ts: rawGauges - chainId ${mainnet.id} - rpc ${rpc}`,
37
+ })
38
+
39
+ const veBalance = rawVotes[0].veBalance
40
+
41
+ const votes = rawVotes[0].votes
42
+ .filter((rv) => !equalTlc(rv.gauge, zeroAddress))
43
+ .map((v) => ({
44
+ gauge: v.gauge,
45
+ slope: formatUnits(v.slope, 0),
46
+ relativeWeight: Number(v.power) / 100,
47
+ weight: formatUnits((veBalance * BigInt(v.power)) / BigInt(10000), 18),
48
+ start: Number(v.start),
49
+ end: Number(v.end),
50
+ }))
51
+
52
+ const unusedRelativeWeight = 10000 - votes.reduce((total, x) => total + x.relativeWeight * 100, 0)
53
+ const unusedVeBalance = (veBalance * BigInt(unusedRelativeWeight)) / BigInt(10000)
54
+
55
+ return {
56
+ veBalance: formatUnits(veBalance, 18),
57
+ unusedVeBalance: formatUnits(unusedVeBalance, 18),
58
+ unusedRelativeWeight: unusedRelativeWeight / 100,
59
+ votes,
60
+ }
61
+ }