@stake-dao/reader 0.4.23 → 0.4.25

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.
@@ -0,0 +1,69 @@
1
+ import snapshot from '@snapshot-labs/snapshot.js';
2
+ import { gql } from 'graphql-request';
3
+ import { isAddress } from 'viem';
4
+ import { graphql } from '../../utils.js';
5
+ const TITLE = 'Gauge Weight for Week of';
6
+ const SNAPSHOT_PROPOSAL_QUERY = (space) => gql `
7
+ query Proposals {
8
+ proposals (
9
+ first: 20
10
+ where: {
11
+ space: "${space}"
12
+ title_contains: "${TITLE}"
13
+ type: "weighted"
14
+ }
15
+ orderBy: "created"
16
+ orderDirection: desc
17
+ ){
18
+ id
19
+ title
20
+ start
21
+ end
22
+ state
23
+ snapshot
24
+ choices
25
+ space {
26
+ strategies {
27
+ name
28
+ network
29
+ params
30
+ }
31
+ }
32
+ }
33
+ }
34
+ `;
35
+ export const fetchSnapshotUserData = async (userAddress, spaces) => {
36
+ if (spaces.length === 0) {
37
+ return undefined;
38
+ }
39
+ const responses = await Promise.all(spaces.map((space) => graphql('https://hub.snapshot.org/graphql', SNAPSHOT_PROPOSAL_QUERY(space))));
40
+ const results = [];
41
+ for (let i = 0; i < responses.length; i++) {
42
+ const response = responses[i];
43
+ if (!response.proposals) {
44
+ return undefined;
45
+ }
46
+ const proposals = response.proposals;
47
+ const proposal = proposals.find((proposal) => proposal.title.startsWith(TITLE));
48
+ if (!proposal) {
49
+ return undefined;
50
+ }
51
+ // Fetch user voting power
52
+ let vp = 0;
53
+ if (isAddress(userAddress)) {
54
+ const fetchedVp = await snapshot.utils.getScores(spaces[i], proposal.space.strategies, '1', [userAddress], Number.parseInt(proposal.snapshot));
55
+ for (const v of fetchedVp) {
56
+ if (v?.[userAddress]) {
57
+ vp += v?.[userAddress] || 0;
58
+ }
59
+ }
60
+ }
61
+ results.push({
62
+ proposal,
63
+ space: spaces[i],
64
+ vp,
65
+ });
66
+ }
67
+ return results;
68
+ };
69
+ //# sourceMappingURL=fetchSnapshotUserData.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fetchSnapshotUserData.js","sourceRoot":"","sources":["../../../../src/votemarket/curve/fetchSnapshotUserData.ts"],"names":[],"mappings":"AAAA,OAAO,QAAQ,MAAM,4BAA4B,CAAA;AACjD,OAAO,EAAE,GAAG,EAAE,MAAM,iBAAiB,CAAA;AACrC,OAAO,EAAE,SAAS,EAAE,MAAM,MAAM,CAAA;AAChC,OAAO,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAA;AA2BxC,MAAM,KAAK,GAAG,0BAA0B,CAAA;AAExC,MAAM,uBAAuB,GAAG,CAAC,KAAa,EAAE,EAAE,CAAC,GAAG,CAAA;;;;;sBAKhC,KAAK;+BACI,KAAK;;;;;;;;;;;;;;;;;;;;;;CAsBnC,CAAA;AAED,MAAM,CAAC,MAAM,qBAAqB,GAAG,KAAK,EACxC,WAAmB,EACnB,MAAgB,EAC0B,EAAE;IAC5C,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACxB,OAAO,SAAS,CAAA;IAClB,CAAC;IACD,MAAM,SAAS,GAAG,MAAM,OAAO,CAAC,GAAG,CACjC,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,OAAO,CAAC,kCAAkC,EAAE,uBAAuB,CAAC,KAAK,CAAC,CAAC,CAAC,CACnG,CAAA;IAED,MAAM,OAAO,GAAwB,EAAE,CAAA;IACvC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,SAAS,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QAC1C,MAAM,QAAQ,GAAG,SAAS,CAAC,CAAC,CAAC,CAAA;QAE7B,IAAI,CAAC,QAAQ,CAAC,SAAS,EAAE,CAAC;YACxB,OAAO,SAAS,CAAA;QAClB,CAAC;QACD,MAAM,SAAS,GAAG,QAAQ,CAAC,SAA+B,CAAA;QAE1D,MAAM,QAAQ,GAAG,SAAS,CAAC,IAAI,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,QAAQ,CAAC,KAAK,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,CAAA;QAC/E,IAAI,CAAC,QAAQ,EAAE,CAAC;YACd,OAAO,SAAS,CAAA;QAClB,CAAC;QAED,0BAA0B;QAC1B,IAAI,EAAE,GAAG,CAAC,CAAA;QACV,IAAI,SAAS,CAAC,WAAW,CAAC,EAAE,CAAC;YAC3B,MAAM,SAAS,GAAG,MAAO,QAAgB,CAAC,KAAK,CAAC,SAAS,CACvD,MAAM,CAAC,CAAC,CAAC,EACT,QAAQ,CAAC,KAAK,CAAC,UAAU,EACzB,GAAG,EACH,CAAC,WAAW,CAAC,EACb,MAAM,CAAC,QAAQ,CAAC,QAAQ,CAAC,QAAQ,CAAC,CACnC,CAAA;YAED,KAAK,MAAM,CAAC,IAAI,SAAS,EAAE,CAAC;gBAC1B,IAAI,CAAC,EAAE,CAAC,WAAW,CAAC,EAAE,CAAC;oBACrB,EAAE,IAAI,CAAC,EAAE,CAAC,WAAW,CAAC,IAAI,CAAC,CAAA;gBAC7B,CAAC;YACH,CAAC;QACH,CAAC;QAED,OAAO,CAAC,IAAI,CAAC;YACX,QAAQ;YACR,KAAK,EAAE,MAAM,CAAC,CAAC,CAAW;YAC1B,EAAE;SACH,CAAC,CAAA;IACJ,CAAC;IAED,OAAO,OAAO,CAAA;AAChB,CAAC,CAAA"}
@@ -24,4 +24,5 @@ export { buildPendleStrategies } from './strategies/pendle/build.js';
24
24
  export { default as getPendleApiData } from './strategies/pendle/getPendleApiData.js';
25
25
  export { fetchCurveGauges } from './votemarket/curve/fetchCurveGauges.js';
26
26
  export { fetchCurveUserVotes } from './votemarket/curve/fetchCurveUserVotes.js';
27
+ export { fetchSnapshotUserData } from './votemarket/curve/fetchSnapshotUserData.js';
27
28
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,kBAAkB,EAAE,0BAA0B,EAAE,MAAM,aAAa,CAAA;AAC5E,cAAc,UAAU,CAAA;AAKxB,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAA;AAKzC,OAAO,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAA;AACvD,OAAO,EAAE,eAAe,EAAE,sBAAsB,EAAE,uBAAuB,EAAE,MAAM,gCAAgC,CAAA;AAKjH,cAAc,6BAA6B,CAAA;AAG3C,OAAO,EAAE,oBAAoB,EAAE,MAAM,6BAA6B,CAAA;AAClE,OAAO,EAAE,UAAU,EAAE,MAAM,mCAAmC,CAAA;AAC9D,OAAO,EAAE,eAAe,EAAE,MAAM,0DAA0D,CAAA;AAC1F,OAAO,EAAE,gBAAgB,EAAE,MAAM,2DAA2D,CAAA;AAC5F,OAAO,EAAE,qBAAqB,EAAE,MAAM,gEAAgE,CAAA;AAGtG,OAAO,EAAE,UAAU,EAAE,MAAM,6BAA6B,CAAA;AAGxD,OAAO,EAAE,uBAAuB,EAAE,MAAM,gCAAgC,CAAA;AACxE,OAAO,EAAE,aAAa,EAAE,MAAM,gCAAgC,CAAA;AAG9D,OAAO,EAAE,oBAAoB,EAAE,MAAM,6BAA6B,CAAA;AAClE,OAAO,EAAE,UAAU,EAAE,MAAM,mCAAmC,CAAA;AAG9D,OAAO,EAAE,gBAAgB,EAAE,MAAM,yCAAyC,CAAA;AAC1E,OAAO,EAAE,0BAA0B,EAAE,MAAM,mCAAmC,CAAA;AAC9E,OAAO,EAAE,+BAA+B,EAAE,MAAM,wCAAwC,CAAA;AACxF,OAAO,EAAE,mBAAmB,EAAE,MAAM,oDAAoD,CAAA;AACxF,OAAO,EAAE,qBAAqB,EAAE,MAAM,yDAAyD,CAAA;AAG/F,OAAO,EAAE,WAAW,EAAE,MAAM,8BAA8B,CAAA;AAC1D,OAAO,EAAE,qBAAqB,EAAE,MAAM,8BAA8B,CAAA;AACpE,OAAO,EAAE,OAAO,IAAI,gBAAgB,EAAE,MAAM,yCAAyC,CAAA;AASrF,OAAO,EAAE,gBAAgB,EAAE,MAAM,wCAAwC,CAAA;AACzE,OAAO,EAAE,mBAAmB,EAAE,MAAM,2CAA2C,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,kBAAkB,EAAE,0BAA0B,EAAE,MAAM,aAAa,CAAA;AAC5E,cAAc,UAAU,CAAA;AAKxB,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAA;AAKzC,OAAO,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAA;AACvD,OAAO,EAAE,eAAe,EAAE,sBAAsB,EAAE,uBAAuB,EAAE,MAAM,gCAAgC,CAAA;AAKjH,cAAc,6BAA6B,CAAA;AAG3C,OAAO,EAAE,oBAAoB,EAAE,MAAM,6BAA6B,CAAA;AAClE,OAAO,EAAE,UAAU,EAAE,MAAM,mCAAmC,CAAA;AAC9D,OAAO,EAAE,eAAe,EAAE,MAAM,0DAA0D,CAAA;AAC1F,OAAO,EAAE,gBAAgB,EAAE,MAAM,2DAA2D,CAAA;AAC5F,OAAO,EAAE,qBAAqB,EAAE,MAAM,gEAAgE,CAAA;AAGtG,OAAO,EAAE,UAAU,EAAE,MAAM,6BAA6B,CAAA;AAGxD,OAAO,EAAE,uBAAuB,EAAE,MAAM,gCAAgC,CAAA;AACxE,OAAO,EAAE,aAAa,EAAE,MAAM,gCAAgC,CAAA;AAG9D,OAAO,EAAE,oBAAoB,EAAE,MAAM,6BAA6B,CAAA;AAClE,OAAO,EAAE,UAAU,EAAE,MAAM,mCAAmC,CAAA;AAG9D,OAAO,EAAE,gBAAgB,EAAE,MAAM,yCAAyC,CAAA;AAC1E,OAAO,EAAE,0BAA0B,EAAE,MAAM,mCAAmC,CAAA;AAC9E,OAAO,EAAE,+BAA+B,EAAE,MAAM,wCAAwC,CAAA;AACxF,OAAO,EAAE,mBAAmB,EAAE,MAAM,oDAAoD,CAAA;AACxF,OAAO,EAAE,qBAAqB,EAAE,MAAM,yDAAyD,CAAA;AAG/F,OAAO,EAAE,WAAW,EAAE,MAAM,8BAA8B,CAAA;AAC1D,OAAO,EAAE,qBAAqB,EAAE,MAAM,8BAA8B,CAAA;AACpE,OAAO,EAAE,OAAO,IAAI,gBAAgB,EAAE,MAAM,yCAAyC,CAAA;AASrF,OAAO,EAAE,gBAAgB,EAAE,MAAM,wCAAwC,CAAA;AACzE,OAAO,EAAE,mBAAmB,EAAE,MAAM,2CAA2C,CAAA;AAC/E,OAAO,EAAE,qBAAqB,EAAE,MAAM,6CAA6C,CAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/lockers/fetch/index.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,iBAAiB,CAAA;AAK5C,OAA6B,EAAE,KAAK,cAAc,EAAE,MAAM,kCAAkC,CAAA;AAsB5F,UAAU,aAAa;IACrB,QAAQ,EAAE,GAAG,CAAA;IACb,OAAO,EAAE,MAAM,CAAA;IACf,MAAM,EAAE,KAAK,EAAE,CAAA;IACf,gBAAgB,CAAC,EAAE,OAAO,CAAA;CAC3B;AAED,eAAO,MAAM,YAAY,oDAA2D,aAAa;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAqRhG,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/lockers/fetch/index.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,iBAAiB,CAAA;AAK5C,OAA6B,EAAE,KAAK,cAAc,EAAE,MAAM,kCAAkC,CAAA;AAsB5F,UAAU,aAAa;IACrB,QAAQ,EAAE,GAAG,CAAA;IACb,OAAO,EAAE,MAAM,CAAA;IACf,MAAM,EAAE,KAAK,EAAE,CAAA;IACf,gBAAgB,CAAC,EAAE,OAAO,CAAA;CAC3B;AAED,eAAO,MAAM,YAAY,oDAA2D,aAAa;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA+RhG,CAAA"}
@@ -2,14 +2,17 @@ declare const getHttpCalls: (chainId: number) => Promise<{
2
2
  bribesData: any;
3
3
  fpisBribesData: any;
4
4
  cvgAprs: any;
5
+ sdfxsWorkingData?: undefined;
5
6
  } | {
6
7
  bribesData: any;
8
+ sdfxsWorkingData: any;
7
9
  fpisBribesData?: undefined;
8
10
  cvgAprs?: undefined;
9
11
  } | {
10
12
  bribesData?: undefined;
11
13
  fpisBribesData?: undefined;
12
14
  cvgAprs?: undefined;
15
+ sdfxsWorkingData?: undefined;
13
16
  }>;
14
17
  export default getHttpCalls;
15
18
  //# sourceMappingURL=getHttpCalls.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"getHttpCalls.d.ts","sourceRoot":"","sources":["../../../../src/lockers/utils/getHttpCalls.ts"],"names":[],"mappings":"AAEA,QAAA,MAAM,YAAY,YAAmB,MAAM;;;;;;;;;;;;EAkD1C,CAAA;AAED,eAAe,YAAY,CAAA"}
1
+ {"version":3,"file":"getHttpCalls.d.ts","sourceRoot":"","sources":["../../../../src/lockers/utils/getHttpCalls.ts"],"names":[],"mappings":"AAEA,QAAA,MAAM,YAAY,YAAmB,MAAM;;;;;;;;;;;;;;;EAoD1C,CAAA;AAED,eAAe,YAAY,CAAA"}
@@ -0,0 +1,25 @@
1
+ interface SnapshotProposal {
2
+ id: string;
3
+ title: string;
4
+ start: number;
5
+ end: number;
6
+ state: string;
7
+ choices: string[];
8
+ snapshot: string;
9
+ space: {
10
+ strategies: SnapshotStrategy[];
11
+ };
12
+ }
13
+ interface ISnapshotUserData {
14
+ proposal: SnapshotProposal;
15
+ vp: number;
16
+ space: string;
17
+ }
18
+ interface SnapshotStrategy {
19
+ name: string;
20
+ network: string;
21
+ params: any;
22
+ }
23
+ export declare const fetchSnapshotUserData: (userAddress: string, spaces: string[]) => Promise<ISnapshotUserData[] | undefined>;
24
+ export {};
25
+ //# sourceMappingURL=fetchSnapshotUserData.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fetchSnapshotUserData.d.ts","sourceRoot":"","sources":["../../../../src/votemarket/curve/fetchSnapshotUserData.ts"],"names":[],"mappings":"AAKA,UAAU,gBAAgB;IACxB,EAAE,EAAE,MAAM,CAAA;IACV,KAAK,EAAE,MAAM,CAAA;IACb,KAAK,EAAE,MAAM,CAAA;IACb,GAAG,EAAE,MAAM,CAAA;IACX,KAAK,EAAE,MAAM,CAAA;IACb,OAAO,EAAE,MAAM,EAAE,CAAA;IACjB,QAAQ,EAAE,MAAM,CAAA;IAChB,KAAK,EAAE;QACL,UAAU,EAAE,gBAAgB,EAAE,CAAA;KAC/B,CAAA;CACF;AAED,UAAU,iBAAiB;IACzB,QAAQ,EAAE,gBAAgB,CAAA;IAC1B,EAAE,EAAE,MAAM,CAAA;IACV,KAAK,EAAE,MAAM,CAAA;CACd;AAED,UAAU,gBAAgB;IACxB,IAAI,EAAE,MAAM,CAAA;IACZ,OAAO,EAAE,MAAM,CAAA;IACf,MAAM,EAAE,GAAG,CAAA;CACZ;AAkCD,eAAO,MAAM,qBAAqB,gBACnB,MAAM,UACX,MAAM,EAAE,KACf,OAAO,CAAC,iBAAiB,EAAE,GAAG,SAAS,CAgDzC,CAAA"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@stake-dao/reader",
3
3
  "description": "",
4
- "version": "0.4.23",
4
+ "version": "0.4.25",
5
5
  "license": "AGPL-3.0-only",
6
6
  "repository": {
7
7
  "type": "git",
@@ -31,11 +31,12 @@
31
31
  "*": {}
32
32
  },
33
33
  "dependencies": {
34
+ "@snapshot-labs/snapshot.js": "^0.9.7",
34
35
  "dayjs": "^1.11.11",
35
36
  "graphql-request": "^6.0.0",
36
37
  "lodash-es": "^4.17.21",
37
38
  "viem": "^2.9.31",
38
- "@stake-dao/constants": "0.4.13"
39
+ "@stake-dao/constants": "0.4.14"
39
40
  },
40
41
  "devDependencies": {
41
42
  "@types/lodash-es": "^4.17.12"
package/src/index.ts CHANGED
@@ -59,6 +59,7 @@ export { default as getPendleApiData } from './strategies/pendle/getPendleApiDat
59
59
  // Curve
60
60
  export { fetchCurveGauges } from './votemarket/curve/fetchCurveGauges.js'
61
61
  export { fetchCurveUserVotes } from './votemarket/curve/fetchCurveUserVotes.js'
62
+ export { fetchSnapshotUserData } from './votemarket/curve/fetchSnapshotUserData.js'
62
63
 
63
64
  /// --- END VOTEMARKET
64
65
  ///////////////////////////////////////////////////////////////
@@ -1,6 +1,6 @@
1
1
  import { type Locker, ONE_YEAR, delegationWithId, lockers } from '@stake-dao/constants'
2
2
  import { formatUnits, parseAbi, zeroAddress } from 'viem'
3
- import { mainnet } from 'viem/chains'
3
+ import { fraxtal, mainnet } from 'viem/chains'
4
4
  import lockersMulticallAbi from '../../abis/lockersMulticall.js'
5
5
  import { Zero, getSdtInflationData } from '../../index.js'
6
6
  import type { Price } from '../../prices.js'
@@ -208,20 +208,30 @@ export const fetchLockers = async ({ provider, chainId, prices, withAirdropGraph
208
208
  let bribeMaxApr = 0
209
209
  let bribeRewards: TBribesRewards | undefined = undefined
210
210
 
211
- if (chainId === mainnet.id) {
211
+ if (chainId === mainnet.id || chainId === fraxtal.id) {
212
+ let _workingSupply = gaugeWorkingSupply
213
+ let _veSdtTotalSupply = veSdtTotalSupply
214
+ let _veBalanceOfLocker = veBalanceOfLocker
215
+
216
+ if (locker.id === 'fxs') {
217
+ _workingSupply = httpCalls.sdfxsWorkingData.working_supply.toString()
218
+ _veSdtTotalSupply = BigInt(httpCalls.sdfxsWorkingData.veSDT_total_supply)
219
+ _veBalanceOfLocker = (httpCalls.sdfxsWorkingData.veBalance * 4).toString()
220
+ }
221
+
212
222
  const data = getBribesRewardsData(
213
223
  locker,
214
224
  httpCalls.bribesData,
215
- veSdtTotalSupply,
225
+ _veSdtTotalSupply,
216
226
  totalSupplyStaked,
217
- veBalanceOfLocker,
218
- gaugeWorkingSupply,
227
+ _veBalanceOfLocker,
228
+ _workingSupply,
219
229
  )
220
230
 
221
231
  bribeMinApr = data.bribeMinApr
222
232
  bribeMaxApr = data.bribeMaxApr
223
233
  bribeRewards = data.bribeRewards
224
- } else if (locker.id === 'cake' || locker.id === 'fxs') {
234
+ } else if (locker.id === 'cake') {
225
235
  let _veBalanceOfLocker = Number(veBalanceOfLocker)
226
236
 
227
237
  // Add sidechain veBalance
@@ -37,6 +37,7 @@ const getHttpCalls = async (chainId: number) => {
37
37
  case bsc.id: {
38
38
  const httpCalls = [
39
39
  (await fetch('https://raw.githubusercontent.com/stake-dao/bounties-report/main/delegationsAPRs.json')).json(),
40
+ (await fetch('https://api.stakedao.org/api/lockers/sdfxs-working-supply.json')).json(),
40
41
  ]
41
42
 
42
43
  const httpResponses = (await Promise.allSettled(httpCalls)).map((result) =>
@@ -44,8 +45,9 @@ const getHttpCalls = async (chainId: number) => {
44
45
  )
45
46
 
46
47
  const bribesData = httpResponses[0]
48
+ const sdfxsWorkingData = httpResponses[1]
47
49
 
48
- return { bribesData }
50
+ return { bribesData, sdfxsWorkingData }
49
51
  }
50
52
  }
51
53
 
@@ -0,0 +1,114 @@
1
+ import snapshot from '@snapshot-labs/snapshot.js'
2
+ import { gql } from 'graphql-request'
3
+ import { isAddress } from 'viem'
4
+ import { graphql } from '../../utils.js'
5
+
6
+ interface SnapshotProposal {
7
+ id: string
8
+ title: string
9
+ start: number
10
+ end: number
11
+ state: string
12
+ choices: string[]
13
+ snapshot: string
14
+ space: {
15
+ strategies: SnapshotStrategy[]
16
+ }
17
+ }
18
+
19
+ interface ISnapshotUserData {
20
+ proposal: SnapshotProposal
21
+ vp: number
22
+ space: string
23
+ }
24
+
25
+ interface SnapshotStrategy {
26
+ name: string
27
+ network: string
28
+ params: any
29
+ }
30
+
31
+ const TITLE = 'Gauge Weight for Week of'
32
+
33
+ const SNAPSHOT_PROPOSAL_QUERY = (space: string) => gql`
34
+ query Proposals {
35
+ proposals (
36
+ first: 20
37
+ where: {
38
+ space: "${space}"
39
+ title_contains: "${TITLE}"
40
+ type: "weighted"
41
+ }
42
+ orderBy: "created"
43
+ orderDirection: desc
44
+ ){
45
+ id
46
+ title
47
+ start
48
+ end
49
+ state
50
+ snapshot
51
+ choices
52
+ space {
53
+ strategies {
54
+ name
55
+ network
56
+ params
57
+ }
58
+ }
59
+ }
60
+ }
61
+ `
62
+
63
+ export const fetchSnapshotUserData = async (
64
+ userAddress: string,
65
+ spaces: string[],
66
+ ): Promise<ISnapshotUserData[] | undefined> => {
67
+ if (spaces.length === 0) {
68
+ return undefined
69
+ }
70
+ const responses = await Promise.all(
71
+ spaces.map((space) => graphql('https://hub.snapshot.org/graphql', SNAPSHOT_PROPOSAL_QUERY(space))),
72
+ )
73
+
74
+ const results: ISnapshotUserData[] = []
75
+ for (let i = 0; i < responses.length; i++) {
76
+ const response = responses[i]
77
+
78
+ if (!response.proposals) {
79
+ return undefined
80
+ }
81
+ const proposals = response.proposals as SnapshotProposal[]
82
+
83
+ const proposal = proposals.find((proposal) => proposal.title.startsWith(TITLE))
84
+ if (!proposal) {
85
+ return undefined
86
+ }
87
+
88
+ // Fetch user voting power
89
+ let vp = 0
90
+ if (isAddress(userAddress)) {
91
+ const fetchedVp = await (snapshot as any).utils.getScores(
92
+ spaces[i],
93
+ proposal.space.strategies,
94
+ '1',
95
+ [userAddress],
96
+ Number.parseInt(proposal.snapshot),
97
+ )
98
+
99
+ for (const v of fetchedVp) {
100
+ if (v?.[userAddress]) {
101
+ vp += v?.[userAddress] || 0
102
+ }
103
+ }
104
+ }
105
+
106
+ results.push({
107
+ proposal,
108
+ space: spaces[i] as string,
109
+ vp,
110
+ })
111
+ }
112
+
113
+ return results
114
+ }