@stake-dao/reader 0.4.32 → 0.4.33

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 (53) hide show
  1. package/dist/esm/bytecodes/index.js +1 -0
  2. package/dist/esm/bytecodes/index.js.map +1 -1
  3. package/dist/esm/bytecodes/votemarket/getNeededCampaignUpdate.js +17 -0
  4. package/dist/esm/bytecodes/votemarket/getNeededCampaignUpdate.js.map +1 -0
  5. package/dist/esm/endpoints.js +1 -0
  6. package/dist/esm/endpoints.js.map +1 -1
  7. package/dist/esm/index.js +1 -0
  8. package/dist/esm/index.js.map +1 -1
  9. package/dist/esm/strategies/pancakeswap/fetch/getPancakeV3Vaults.js +1 -1
  10. package/dist/esm/strategies/pancakeswap/fetch/getPancakeV3Vaults.js.map +1 -1
  11. package/dist/esm/strategies/pancakeswap/fetch/pancakePositions.js +2 -2
  12. package/dist/esm/strategies/pancakeswap/fetch/pancakePositions.js.map +1 -1
  13. package/dist/esm/strategies/pancakeswap/fetch/pancakeswapMath.js +1 -1
  14. package/dist/esm/strategies/pancakeswap/fetch/pancakeswapMath.js.map +1 -1
  15. package/dist/esm/tsconfig.build.tsbuildinfo +1 -1
  16. package/dist/esm/votemarket/curve/fetchCurveGauges.js +4 -1
  17. package/dist/esm/votemarket/curve/fetchCurveGauges.js.map +1 -1
  18. package/dist/esm/votemarket/curve/fetchSnapshotUserData.js +34 -1
  19. package/dist/esm/votemarket/curve/fetchSnapshotUserData.js.map +1 -1
  20. package/dist/esm/votemarket/curve/fetchUserVlCvxClaimable.js +37 -5
  21. package/dist/esm/votemarket/curve/fetchUserVlCvxClaimable.js.map +1 -1
  22. package/dist/esm/votemarket/fetchCampaigns.js +4 -4
  23. package/dist/esm/votemarket/fetchCampaigns.js.map +1 -1
  24. package/dist/esm/votemarket/fetchNeededCampaignUpdate.js +17 -0
  25. package/dist/esm/votemarket/fetchNeededCampaignUpdate.js.map +1 -0
  26. package/dist/types/bytecodes/index.d.ts +1 -0
  27. package/dist/types/bytecodes/index.d.ts.map +1 -1
  28. package/dist/types/bytecodes/votemarket/getNeededCampaignUpdate.d.ts +4 -0
  29. package/dist/types/bytecodes/votemarket/getNeededCampaignUpdate.d.ts.map +1 -0
  30. package/dist/types/endpoints.d.ts +1 -0
  31. package/dist/types/endpoints.d.ts.map +1 -1
  32. package/dist/types/index.d.ts +1 -0
  33. package/dist/types/index.d.ts.map +1 -1
  34. package/dist/types/strategies/pancakeswap/fetch/pancakeswapMath.d.ts.map +1 -1
  35. package/dist/types/votemarket/curve/fetchCurveGauges.d.ts.map +1 -1
  36. package/dist/types/votemarket/curve/fetchSnapshotUserData.d.ts +6 -0
  37. package/dist/types/votemarket/curve/fetchSnapshotUserData.d.ts.map +1 -1
  38. package/dist/types/votemarket/curve/fetchUserVlCvxClaimable.d.ts.map +1 -1
  39. package/dist/types/votemarket/fetchNeededCampaignUpdate.d.ts +2 -0
  40. package/dist/types/votemarket/fetchNeededCampaignUpdate.d.ts.map +1 -0
  41. package/package.json +2 -2
  42. package/src/bytecodes/index.ts +1 -0
  43. package/src/bytecodes/votemarket/getNeededCampaignUpdate.ts +19 -0
  44. package/src/endpoints.ts +2 -0
  45. package/src/index.ts +1 -0
  46. package/src/strategies/pancakeswap/fetch/getPancakeV3Vaults.ts +1 -1
  47. package/src/strategies/pancakeswap/fetch/pancakePositions.ts +2 -2
  48. package/src/strategies/pancakeswap/fetch/pancakeswapMath.ts +1 -1
  49. package/src/votemarket/curve/fetchCurveGauges.ts +5 -1
  50. package/src/votemarket/curve/fetchSnapshotUserData.ts +43 -3
  51. package/src/votemarket/curve/fetchUserVlCvxClaimable.ts +51 -6
  52. package/src/votemarket/fetchCampaigns.ts +4 -4
  53. package/src/votemarket/fetchNeededCampaignUpdate.ts +28 -0
@@ -1,6 +1,7 @@
1
1
  import snapshot from '@snapshot-labs/snapshot.js'
2
2
  import { gql } from 'graphql-request'
3
3
  import { isAddress } from 'viem'
4
+ import { SNAPSHOT_HUB } from '../../endpoints.js'
4
5
  import { graphql } from '../../utils.js'
5
6
 
6
7
  interface SnapshotProposal {
@@ -21,6 +22,7 @@ interface ISnapshotUserData {
21
22
  proposal: SnapshotProposal
22
23
  vp: number
23
24
  space: string
25
+ userVotes: { [gaugeId: string]: { weight: number; relativeWeight: number } }
24
26
  }
25
27
 
26
28
  interface SnapshotStrategy {
@@ -66,6 +68,24 @@ query Proposals {
66
68
  }
67
69
  `
68
70
 
71
+ const SNAPSHOT_USER_VOTE_QUERY = (space: string, proposal: string, user: string) => gql`
72
+ query UserVote {
73
+ votes (
74
+ first: 1
75
+ where: {
76
+ space: "${space}"
77
+ proposal: "${proposal}"
78
+ voter: "${user}"
79
+ }
80
+ ) {
81
+ id
82
+ created
83
+ choice
84
+ vp
85
+ }
86
+ }
87
+ `
88
+
69
89
  export const fetchSnapshotUserData = async (
70
90
  userAddress: string,
71
91
  spaces: string[],
@@ -74,9 +94,7 @@ export const fetchSnapshotUserData = async (
74
94
  return undefined
75
95
  }
76
96
 
77
- const responses = await Promise.all(
78
- spaces.map((space) => graphql('https://hub.snapshot.org/graphql', SNAPSHOT_PROPOSAL_QUERY(space))),
79
- )
97
+ const responses = await Promise.all(spaces.map((space) => graphql(SNAPSHOT_HUB, SNAPSHOT_PROPOSAL_QUERY(space))))
80
98
 
81
99
  const results: ISnapshotUserData[] = []
82
100
  for (let i = 0; i < responses.length; i++) {
@@ -94,6 +112,7 @@ export const fetchSnapshotUserData = async (
94
112
 
95
113
  // Fetch user voting power
96
114
  let vp = 0
115
+ const userVotes = {}
97
116
  if (isAddress(userAddress)) {
98
117
  const fetchedVp = await (snapshot as any).utils.getScores(
99
118
  spaces[i],
@@ -108,12 +127,33 @@ export const fetchSnapshotUserData = async (
108
127
  vp += v?.[userAddress] || 0
109
128
  }
110
129
  }
130
+
131
+ const rawUserVotes = await graphql(SNAPSHOT_HUB, SNAPSHOT_USER_VOTE_QUERY(spaces[i]!, proposal.id, userAddress))
132
+
133
+ if (rawUserVotes?.votes && rawUserVotes.votes.length > 0) {
134
+ const rawUserVote = rawUserVotes.votes[0]
135
+ const totalSnapshotVote = Object.keys(rawUserVote.choice).reduce(
136
+ (total, i) => (total += rawUserVote.choice[i]),
137
+ 0,
138
+ )
139
+
140
+ for (const i of Object.keys(rawUserVote.choice)) {
141
+ const relativeWeight = rawUserVote.choice[i] / totalSnapshotVote
142
+ const proposalChoiceIndex = Number(i) - 1
143
+
144
+ userVotes[proposal.choices[proposalChoiceIndex]!] = {
145
+ weight: rawUserVote.vp * relativeWeight,
146
+ relativeWeight: relativeWeight * 100,
147
+ }
148
+ }
149
+ }
111
150
  }
112
151
 
113
152
  results.push({
114
153
  proposal,
115
154
  space: spaces[i] as string,
116
155
  vp,
156
+ userVotes,
117
157
  })
118
158
  }
119
159
 
@@ -19,9 +19,39 @@ type UnknownToken = {
19
19
  }
20
20
 
21
21
  const getMerkleData = async (epoch: number) => {
22
- return await fetch(
22
+ const response = await fetch(
23
23
  `${GH_STAKE_DAO_BOUNTIES_REPORT}/refs/heads/main/bounties-reports/${epoch}/vlCVX/merkle_data.json`,
24
- ).then((res) => res.json())
24
+ )
25
+ if (!response.ok) throw new Error('Failed to fetch merkle data')
26
+ return response.json()
27
+ }
28
+
29
+ const isRootMatch = (contractRoot: string, fileRoot: string) =>
30
+ (contractRoot === ZERO_ROOT && fileRoot === ZERO_ROOT) || contractRoot.toLowerCase() === fileRoot.toLowerCase()
31
+
32
+ const validateMerkleRoots = (delegatorRoot: string, nonDelegatorRoot: string, merkleData: any) => {
33
+ const delegatorMatches = isRootMatch(delegatorRoot, merkleData.delegators.merkleRoot)
34
+ const nonDelegatorMatches = isRootMatch(nonDelegatorRoot, merkleData.nonDelegators.merkleRoot)
35
+ return delegatorMatches || nonDelegatorMatches
36
+ }
37
+
38
+ const getMerkleRoots = async (provider: any) => {
39
+ const contracts = [contract('vlCvxDelegatorMerkle', mainnet.id), contract('vlCvxNotDelegatorMerkle', mainnet.id)]
40
+
41
+ const result = await multicall(
42
+ provider,
43
+ contracts.map((address) => ({
44
+ address,
45
+ name: 'root',
46
+ params: [],
47
+ })),
48
+ parseAbi(['function root() external view returns (bytes32)']),
49
+ )
50
+
51
+ return {
52
+ delegatorRoot: result[0].result,
53
+ nonDelegatorRoot: result[1].result,
54
+ }
25
55
  }
26
56
 
27
57
  const getClaimedData = async (provider: any, tokens: string[], user: string, contract: string) => {
@@ -74,14 +104,29 @@ const getParsedData = (
74
104
  : undefined
75
105
  }
76
106
 
107
+ const ZERO_ROOT = '0x0000000000000000000000000000000000000000000000000000000000000000'
108
+
77
109
  export const fetchUserVlCvxClaimable = async (provider: any, rpc: Rpcs, user: string) => {
78
110
  const nowEpoch = Math.floor(Date.now() / (1000 * ONE_WEEK)) * ONE_WEEK
111
+ const prevEpoch = nowEpoch - ONE_WEEK
112
+
113
+ const { delegatorRoot, nonDelegatorRoot } = await getMerkleRoots(provider)
79
114
 
80
115
  let vlCvxClaimable: any
81
- try {
82
- vlCvxClaimable = await getMerkleData(nowEpoch)
83
- } catch {
84
- vlCvxClaimable = await getMerkleData(nowEpoch - ONE_WEEK)
116
+
117
+ // Try current week, then previous week if needed
118
+ for (const epoch of [nowEpoch, prevEpoch]) {
119
+ try {
120
+ const merkleData = await getMerkleData(epoch)
121
+ if (validateMerkleRoots(delegatorRoot, nonDelegatorRoot, merkleData)) {
122
+ vlCvxClaimable = merkleData
123
+ break
124
+ }
125
+ } catch {}
126
+ }
127
+
128
+ if (!vlCvxClaimable) {
129
+ throw new Error('Could not find valid merkle data')
85
130
  }
86
131
 
87
132
  const vlCvxUserDelegated = vlCvxClaimable?.delegators.claims[user]
@@ -161,10 +161,10 @@ export const fetchCampaigns = async ({ platform, chainId, rpcs }: FetchCampaigns
161
161
  const prices = [
162
162
  ...(fetchedTokens.length > 0 ? await getPrices(fetchedTokens as any, chainId) : []),
163
163
  ...(nativeFetchedTokens.length > 0 ? await getPrices(nativeFetchedTokens as any, mainnet.id) : []),
164
- { address: '0x9E49A0314AE61e9C9E34e4Af62a73FBFfB6DE95A', symbol: 'ARR', usdPrice: 10 }, // For test purpose
165
- { address: '0x0Cc20784f790805537D4eE33B41f1aC4eC55446B', symbol: 'USDC', usdPrice: 1 }, // For test purpose
166
- { address: '0x59c9a01163e685719FAbE5De34779F563f49D4a3', symbol: 'CRV', usdPrice: 30 }, // For test purpose
167
- { address: '0x3c7b193aa39a85FDE911465d35CE3A74499F0A7B', symbol: 'ARR', usdPrice: 10 }, // For test purpose
164
+ // { address: '0x9E49A0314AE61e9C9E34e4Af62a73FBFfB6DE95A', symbol: 'ARR', usdPrice: 10 }, // For test purpose
165
+ // { address: '0x0Cc20784f790805537D4eE33B41f1aC4eC55446B', symbol: 'USDC', usdPrice: 1 }, // For test purpose
166
+ // { address: '0x59c9a01163e685719FAbE5De34779F563f49D4a3', symbol: 'CRV', usdPrice: 30 }, // For test purpose
167
+ // { address: '0x3c7b193aa39a85FDE911465d35CE3A74499F0A7B', symbol: 'ARR', usdPrice: 10 }, // For test purpose
168
168
  ]
169
169
 
170
170
  const allFetchedTokens = [...fetchedTokens, ...nativeFetchedTokens]
@@ -0,0 +1,28 @@
1
+ import { encodeAbiParameters, parseAbiParameters } from 'viem'
2
+ import { mainnet } from 'viem/chains'
3
+ import { getNeededCampaignUpdate } from '../bytecodes/index.js'
4
+ import { concatBytecode } from '../index.js'
5
+ import { batchJsonRpc } from '../utils.js'
6
+
7
+ export const fetchNeededCampaignUpdate = async (rpc: string, platform: string, campaign: any) => {
8
+ const inputData = encodeAbiParameters(
9
+ parseAbiParameters(
10
+ getNeededCampaignUpdate.inputType[campaign.chainId] || getNeededCampaignUpdate.inputType[mainnet.id]!,
11
+ ) as any,
12
+ [platform, campaign.id],
13
+ )
14
+ const call = concatBytecode(
15
+ getNeededCampaignUpdate.bytecode[campaign.chainId] || getNeededCampaignUpdate.bytecode[mainnet.id]!,
16
+ inputData,
17
+ )
18
+
19
+ const neededForUpdate = await batchJsonRpc({
20
+ rpc,
21
+ calls: [call],
22
+ outputTypeAbi:
23
+ getNeededCampaignUpdate.outputTypeHr[campaign.chainId] || getNeededCampaignUpdate.outputTypeHr[mainnet.id]!,
24
+ callsKey: `Get needed update - chainId ${campaign.chainId} - rpc ${rpc}`,
25
+ })
26
+
27
+ return neededForUpdate
28
+ }