@factordao/governance 1.1.3 → 1.1.4

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/README.md CHANGED
@@ -1,18 +1,362 @@
1
- # Factor Governance
2
-
3
- This repository contains the governance for Factor.
4
-
5
- ## Implementation plan
6
- - [x] Create the subgraph to track the `emit AddVault(_chainId, _vault);` event from `FactorScale` on Arbitrum
7
- - [x] Create the function to get all the vaults for all the available chains
8
- - [x] Create the subgraph to track the `emit Vote(user, vaults[i], weights[i], newVote);` event from `FactorScale`
9
- - [x] Create the function to get all the votes for a given user
10
- - [x] Create the function to get all the votes for all the users
11
- - [x] Create the function to get all the votes allocations
12
- - [x] Create the subgraph to track the `emit ReceiveVotingResults(wTime, vaults, fctrAmounts);` event from `FactorGaugeController` of both Arbitrum and Base which is emitted after the broadcast
13
- - [x] Create the subgraph to track the `emit UpdateVaultReward(vault, newSpeed, uint128(block.timestamp) + WEEK);` event from `FactorGaugeController`
14
- - [x] Create the function to get all the rewards for a given vault
15
- - [x] Create the function to get all the rewards for all vaults
16
- - [x] Create the function to get the incentives, if they're active or not and how much they're worth
17
- - [x] Calculate the APY for scale and the given vault (?)
18
- - [ ] Create the function to get the `function earned(address account, address _rewardsToken)` for a given account and rewards token to get the rewards for the user (?)
1
+ # @factordao/governance
2
+
3
+ A TypeScript SDK for Factor DAO's governance system. Provides data fetching for vaults, voting, rewards, and token balances across multiple blockchain networks.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install @factordao/governance
9
+ # or
10
+ yarn add @factordao/governance
11
+ ```
12
+
13
+ ## Supported Chains
14
+
15
+ - Arbitrum One
16
+ - Base
17
+ - Optimism
18
+ - Sonic
19
+
20
+ ## Quick Start
21
+
22
+ ```typescript
23
+ import {
24
+ getVaultsWithFullData,
25
+ getVaultsRewardsData,
26
+ FactorEnvironment,
27
+ } from "@factordao/governance";
28
+
29
+ // Get all vaults with aggregated data (votes, rewards, APY)
30
+ const vaults = await getVaultsWithFullData(FactorEnvironment.PRODUCTION);
31
+
32
+ // Get detailed reward data for specific vaults
33
+ const rewardsData = await getVaultsRewardsData(
34
+ [{ address: "0x...", chainId: 42161 }],
35
+ "0xUserAddress", // optional
36
+ "your-alchemy-key" // optional
37
+ );
38
+ ```
39
+
40
+ ## API Reference
41
+
42
+ ### Vault Functions
43
+
44
+ #### `getAvailableVaultsForVoting(chainId, environment)`
45
+
46
+ Fetches all available vaults for voting on a specific chain.
47
+
48
+ ```typescript
49
+ import { getAvailableVaultsForVoting, FactorEnvironment } from "@factordao/governance";
50
+ import { ChainId } from "@factordao/tokenlist";
51
+
52
+ const vaults = await getAvailableVaultsForVoting(
53
+ ChainId.ARBITRUM_ONE,
54
+ FactorEnvironment.PRODUCTION
55
+ );
56
+ // Returns: string[] - Array of vault addresses
57
+ ```
58
+
59
+ #### `getVaultsWithFullData(environment)`
60
+
61
+ Comprehensive function that aggregates vault data, votes, voting power, and rewards across all chains with calculated APY.
62
+
63
+ ```typescript
64
+ import { getVaultsWithFullData, FactorEnvironment } from "@factordao/governance";
65
+
66
+ const vaults = await getVaultsWithFullData(FactorEnvironment.PRODUCTION);
67
+ // Returns: AggregatedVault[]
68
+ ```
69
+
70
+ **Returns:**
71
+ ```typescript
72
+ interface AggregatedVault {
73
+ id: string; // Vault address
74
+ chainId: number; // Chain ID
75
+ votes: VaultVoteAllocation[]; // Vote allocations
76
+ totalAllocatedVeFCTR: bigint; // Total veFCTR allocated
77
+ voteSharePercentage: number; // Percentage of total votes
78
+ rewards: VaultRewardByChain[]; // Reward data by chain
79
+ }
80
+ ```
81
+
82
+ ### Voting Functions
83
+
84
+ #### `getVotesForUser(chainId, environment, user)`
85
+
86
+ Gets voting data for a specific user.
87
+
88
+ ```typescript
89
+ import { getVotesForUser, FactorEnvironment } from "@factordao/governance";
90
+ import { ChainId } from "@factordao/tokenlist";
91
+
92
+ const votes = await getVotesForUser(
93
+ ChainId.ARBITRUM_ONE,
94
+ FactorEnvironment.PRODUCTION,
95
+ "0xUserAddress"
96
+ );
97
+ // Returns: VaultVotes[]
98
+ ```
99
+
100
+ #### `getVotesForAllUsers(chainId, environment)`
101
+
102
+ Fetches all votes across all users.
103
+
104
+ ```typescript
105
+ import { getVotesForAllUsers, FactorEnvironment } from "@factordao/governance";
106
+ import { ChainId } from "@factordao/tokenlist";
107
+
108
+ const allVotes = await getVotesForAllUsers(
109
+ ChainId.ARBITRUM_ONE,
110
+ FactorEnvironment.PRODUCTION
111
+ );
112
+ // Returns: VaultVotes[]
113
+ ```
114
+
115
+ ### Reward Functions
116
+
117
+ #### `getRewardsForVault(chainId, environment, vault)`
118
+
119
+ Gets reward data for a specific vault.
120
+
121
+ ```typescript
122
+ import { getRewardsForVault, FactorEnvironment } from "@factordao/governance";
123
+ import { ChainId } from "@factordao/tokenlist";
124
+
125
+ const rewards = await getRewardsForVault(
126
+ ChainId.ARBITRUM_ONE,
127
+ FactorEnvironment.PRODUCTION,
128
+ "0xVaultAddress"
129
+ );
130
+ // Returns: VaultReward[]
131
+ ```
132
+
133
+ #### `getRewardsForAllVaults(chainId, environment)`
134
+
135
+ Fetches rewards for all vaults on a chain.
136
+
137
+ ```typescript
138
+ import { getRewardsForAllVaults, FactorEnvironment } from "@factordao/governance";
139
+ import { ChainId } from "@factordao/tokenlist";
140
+
141
+ const allRewards = await getRewardsForAllVaults(
142
+ ChainId.ARBITRUM_ONE,
143
+ FactorEnvironment.PRODUCTION
144
+ );
145
+ // Returns: VaultReward[]
146
+ ```
147
+
148
+ #### `getVaultsRewardsData(vaults, userAddress?, alchemyApiKey?)`
149
+
150
+ Fetches detailed Scale/Boost reward data using multicalls. This is the most comprehensive reward function.
151
+
152
+ ```typescript
153
+ import { getVaultsRewardsData } from "@factordao/governance";
154
+
155
+ const rewardsData = await getVaultsRewardsData(
156
+ [
157
+ { address: "0xVault1", chainId: 42161 },
158
+ { address: "0xVault2", chainId: 8453 },
159
+ ],
160
+ "0xUserAddress", // optional - include for user-specific pending rewards
161
+ "your-alchemy-key" // optional - improves RPC reliability
162
+ );
163
+ // Returns: VaultRewardsData[]
164
+ ```
165
+
166
+ **Returns:**
167
+ ```typescript
168
+ interface VaultRewardsData {
169
+ vaultAddress: string;
170
+ chainId: number;
171
+ scale: {
172
+ rewardTokens: RewardTokenInfo[];
173
+ totalActiveSupply: bigint;
174
+ rewardsData: Record<string, RewardData>;
175
+ };
176
+ boost: {
177
+ rewardTokens: RewardTokenInfo[];
178
+ rewardsData: Record<string, RewardData>;
179
+ };
180
+ user?: {
181
+ activeBalance: bigint;
182
+ scalePendingByToken: Record<string, bigint>;
183
+ earnedByToken: Record<string, bigint>;
184
+ };
185
+ }
186
+ ```
187
+
188
+ ### Token Balance Functions
189
+
190
+ #### `getTokenBalancesForUser(chainId, environment, user)`
191
+
192
+ Gets token balances for a specific user (veFCTR with voting power).
193
+
194
+ ```typescript
195
+ import { getTokenBalancesForUser, FactorEnvironment } from "@factordao/governance";
196
+ import { ChainId } from "@factordao/tokenlist";
197
+
198
+ const balances = await getTokenBalancesForUser(
199
+ ChainId.ARBITRUM_ONE,
200
+ FactorEnvironment.PRODUCTION,
201
+ "0xUserAddress"
202
+ );
203
+ // Returns: UserTokenBalances
204
+ ```
205
+
206
+ #### `getTokenBalancesForAllUsers(chainId, environment)`
207
+
208
+ Fetches all user token balances.
209
+
210
+ ```typescript
211
+ import { getTokenBalancesForAllUsers, FactorEnvironment } from "@factordao/governance";
212
+ import { ChainId } from "@factordao/tokenlist";
213
+
214
+ const allBalances = await getTokenBalancesForAllUsers(
215
+ ChainId.ARBITRUM_ONE,
216
+ FactorEnvironment.PRODUCTION
217
+ );
218
+ // Returns: AllUsersTokenBalances
219
+ ```
220
+
221
+ ## Types
222
+
223
+ ### Enums
224
+
225
+ ```typescript
226
+ enum FactorEnvironment {
227
+ TESTING = "testing",
228
+ STAGING = "staging",
229
+ PRODUCTION = "production",
230
+ }
231
+ ```
232
+
233
+ ### Core Types
234
+
235
+ ```typescript
236
+ interface VaultVotes {
237
+ id: string;
238
+ user: string;
239
+ vault: string;
240
+ weight: bigint;
241
+ newVote: boolean;
242
+ }
243
+
244
+ interface VoteData {
245
+ weight: bigint;
246
+ newVote: boolean;
247
+ }
248
+
249
+ interface VaultReward {
250
+ id: string;
251
+ vault: string;
252
+ speed: bigint;
253
+ activeFrom: bigint;
254
+ }
255
+
256
+ interface TokenBalance {
257
+ id: string;
258
+ amount: bigint;
259
+ expiry: bigint;
260
+ }
261
+
262
+ interface UserTokenBalances {
263
+ balances: TokenBalance[];
264
+ votingPower: bigint;
265
+ }
266
+
267
+ interface AllUsersTokenBalances {
268
+ [userAddress: string]: UserTokenBalances;
269
+ }
270
+
271
+ interface VaultVoteAllocation {
272
+ user: string;
273
+ weight: bigint;
274
+ votingPower: bigint;
275
+ }
276
+
277
+ interface VaultRewardByChain {
278
+ chainId: number;
279
+ speed: bigint;
280
+ activeFrom: bigint;
281
+ }
282
+
283
+ interface RewardTokenInfo {
284
+ token: string;
285
+ symbol: string;
286
+ decimals: number;
287
+ }
288
+
289
+ interface RewardData {
290
+ rewardPerSecond: bigint;
291
+ periodFinish: bigint;
292
+ apr: number;
293
+ }
294
+ ```
295
+
296
+ ## Configuration
297
+
298
+ ### Environment Variables
299
+
300
+ Create a `.env` file:
301
+
302
+ ```env
303
+ ALCHEMY_API_KEY=<your-alchemy-api-key> # Optional, improves RPC reliability
304
+ FACTOR_ENVIRONMENT=production # testing | staging | production
305
+ ```
306
+
307
+ ### Using with Environment Variable
308
+
309
+ ```typescript
310
+ import { getVaultsWithFullData, FactorEnvironment } from "@factordao/governance";
311
+
312
+ const environment =
313
+ (process.env.FACTOR_ENVIRONMENT as FactorEnvironment) ||
314
+ FactorEnvironment.PRODUCTION;
315
+
316
+ const vaults = await getVaultsWithFullData(environment);
317
+ ```
318
+
319
+ ## Data Sources
320
+
321
+ The SDK fetches data from:
322
+
323
+ - **Subgraphs (Goldsky)** - Vault, voting, and reward event data
324
+ - **Factor Price API** - FCTR token prices
325
+ - **Factor Studio Stats API** - Vault TVL data
326
+ - **DefiLlama** - Token prices for reward calculations
327
+ - **RPC Providers** - On-chain contract reads via multicall
328
+
329
+ ## Development
330
+
331
+ ### Setup
332
+
333
+ ```bash
334
+ git clone <repo>
335
+ cd factor-governance
336
+ yarn install
337
+ ```
338
+
339
+ ### Scripts
340
+
341
+ ```bash
342
+ yarn build # Build ESM and CJS outputs
343
+ yarn dev # Run with ts-node
344
+ yarn lint # Fix linting issues
345
+ yarn format # Format code with Prettier
346
+ ```
347
+
348
+ ### Running Tests
349
+
350
+ ```bash
351
+ # Create .env file first
352
+ cp .env.example .env
353
+
354
+ # Run test scripts
355
+ npx ts-node test/01-get-vaults-with-full-data.ts
356
+ npx ts-node test/02-get-vaults-rewards-data.ts
357
+ npx ts-node test/03-performance-test.ts
358
+ ```
359
+
360
+ ## License
361
+
362
+ MIT
@@ -33,7 +33,7 @@ async function fetchPaginatedData(subgraphUrl, queryBuilder, dataExtractor) {
33
33
  }
34
34
  exports.factorScaleSubgraphUrl = {
35
35
  [tokenlist_1.ChainId.ARBITRUM_ONE]: {
36
- testing: 'https://api.goldsky.com/api/public/project_cmgzitcts001c5np28moc9lyy/subgraphs/scale-arbitrum_testing/v0.0.4/gn',
36
+ testing: 'https://api.goldsky.com/api/public/project_cmgzitcts001c5np28moc9lyy/subgraphs/scale-arbitrum_testing/v0.0.5/gn',
37
37
  production: 'https://api.goldsky.com/api/public/project_cmgzitcts001c5np28moc9lyy/subgraphs/scale-arbitrum_production/v0.0.4/gn',
38
38
  },
39
39
  [tokenlist_1.ChainId.BASE]: {
@@ -51,11 +51,11 @@ exports.factorScaleSubgraphUrl = {
51
51
  };
52
52
  exports.factorGaugeControllerSubgraphUrl = {
53
53
  [tokenlist_1.ChainId.ARBITRUM_ONE]: {
54
- testing: 'https://api.goldsky.com/api/public/project_cmgzitcts001c5np28moc9lyy/subgraphs/gauge-arbitrum_testing/v0.0.2/gn',
54
+ testing: 'https://api.goldsky.com/api/public/project_cmgzitcts001c5np28moc9lyy/subgraphs/gauge-arbitrum_testing/v0.0.3/gn',
55
55
  production: 'https://api.goldsky.com/api/public/project_cmgzitcts001c5np28moc9lyy/subgraphs/gauge-arbitrum_production/v0.0.2/gn',
56
56
  },
57
57
  [tokenlist_1.ChainId.BASE]: {
58
- testing: 'https://api.goldsky.com/api/public/project_cmgzitcts001c5np28moc9lyy/subgraphs/gauge-base_testing/v0.0.2/gn',
58
+ testing: 'https://api.goldsky.com/api/public/project_cmgzitcts001c5np28moc9lyy/subgraphs/gauge-base_testing/v0.0.3/gn',
59
59
  production: '',
60
60
  },
61
61
  [tokenlist_1.ChainId.OPTIMISM]: {
@@ -69,7 +69,7 @@ exports.factorGaugeControllerSubgraphUrl = {
69
69
  };
70
70
  exports.factorFCTRSubgraphUrl = {
71
71
  [tokenlist_1.ChainId.ARBITRUM_ONE]: {
72
- testing: 'https://api.goldsky.com/api/public/project_cmgzitcts001c5np28moc9lyy/subgraphs/token-balance-arbitrum_testing/v0.0.4/gn',
72
+ testing: 'https://api.goldsky.com/api/public/project_cmgzitcts001c5np28moc9lyy/subgraphs/token-balance-arbitrum_testing/v0.0.5/gn',
73
73
  production: 'https://api.goldsky.com/api/public/project_cmgzitcts001c5np28moc9lyy/subgraphs/token-balance-arbitrum_production/v0.0.2/gn',
74
74
  },
75
75
  [tokenlist_1.ChainId.BASE]: {
@@ -29,7 +29,7 @@ export async function fetchPaginatedData(subgraphUrl, queryBuilder, dataExtracto
29
29
  }
30
30
  export const factorScaleSubgraphUrl = {
31
31
  [ChainId.ARBITRUM_ONE]: {
32
- testing: 'https://api.goldsky.com/api/public/project_cmgzitcts001c5np28moc9lyy/subgraphs/scale-arbitrum_testing/v0.0.4/gn',
32
+ testing: 'https://api.goldsky.com/api/public/project_cmgzitcts001c5np28moc9lyy/subgraphs/scale-arbitrum_testing/v0.0.5/gn',
33
33
  production: 'https://api.goldsky.com/api/public/project_cmgzitcts001c5np28moc9lyy/subgraphs/scale-arbitrum_production/v0.0.4/gn',
34
34
  },
35
35
  [ChainId.BASE]: {
@@ -47,11 +47,11 @@ export const factorScaleSubgraphUrl = {
47
47
  };
48
48
  export const factorGaugeControllerSubgraphUrl = {
49
49
  [ChainId.ARBITRUM_ONE]: {
50
- testing: 'https://api.goldsky.com/api/public/project_cmgzitcts001c5np28moc9lyy/subgraphs/gauge-arbitrum_testing/v0.0.2/gn',
50
+ testing: 'https://api.goldsky.com/api/public/project_cmgzitcts001c5np28moc9lyy/subgraphs/gauge-arbitrum_testing/v0.0.3/gn',
51
51
  production: 'https://api.goldsky.com/api/public/project_cmgzitcts001c5np28moc9lyy/subgraphs/gauge-arbitrum_production/v0.0.2/gn',
52
52
  },
53
53
  [ChainId.BASE]: {
54
- testing: 'https://api.goldsky.com/api/public/project_cmgzitcts001c5np28moc9lyy/subgraphs/gauge-base_testing/v0.0.2/gn',
54
+ testing: 'https://api.goldsky.com/api/public/project_cmgzitcts001c5np28moc9lyy/subgraphs/gauge-base_testing/v0.0.3/gn',
55
55
  production: '',
56
56
  },
57
57
  [ChainId.OPTIMISM]: {
@@ -65,7 +65,7 @@ export const factorGaugeControllerSubgraphUrl = {
65
65
  };
66
66
  export const factorFCTRSubgraphUrl = {
67
67
  [ChainId.ARBITRUM_ONE]: {
68
- testing: 'https://api.goldsky.com/api/public/project_cmgzitcts001c5np28moc9lyy/subgraphs/token-balance-arbitrum_testing/v0.0.4/gn',
68
+ testing: 'https://api.goldsky.com/api/public/project_cmgzitcts001c5np28moc9lyy/subgraphs/token-balance-arbitrum_testing/v0.0.5/gn',
69
69
  production: 'https://api.goldsky.com/api/public/project_cmgzitcts001c5np28moc9lyy/subgraphs/token-balance-arbitrum_production/v0.0.2/gn',
70
70
  },
71
71
  [ChainId.BASE]: {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@factordao/governance",
3
- "version": "1.1.3",
3
+ "version": "1.1.4",
4
4
  "license": "MIT",
5
5
  "files": [
6
6
  "dist",