@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 +362 -18
- package/dist/cjs/utils/subgraphs.js +4 -4
- package/dist/mjs/utils/subgraphs.js +4 -4
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,18 +1,362 @@
|
|
|
1
|
-
#
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
##
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
-
|
|
16
|
-
-
|
|
17
|
-
-
|
|
18
|
-
-
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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]: {
|