@glowlabs-org/utils 0.0.9 → 0.1.2
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/.github/workflows/publish.yml +14 -4
- package/dist/cjs/constants/regex.d.ts +1 -0
- package/dist/cjs/constants/urls.d.ts +2 -0
- package/dist/cjs/constants/weights.d.ts +12 -0
- package/dist/cjs/index.d.ts +1 -1
- package/dist/cjs/index.js +18988 -89
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/lib/create-weekly-report/index.d.ts +73 -0
- package/dist/cjs/lib/create-weekly-report/types/Audit.d.ts +40 -0
- package/dist/cjs/lib/create-weekly-report/types/index.d.ts +7 -0
- package/dist/cjs/lib/create-weekly-report/types/merkle.d.ts +10 -0
- package/dist/cjs/lib/create-weekly-report/utils/accumulate-leaf-weights.d.ts +2 -0
- package/dist/cjs/lib/create-weekly-report/utils/custom-to-fixed.d.ts +1 -0
- package/dist/cjs/lib/create-weekly-report/utils/fetch-farms-for-week.d.ts +12 -0
- package/dist/cjs/lib/create-weekly-report/utils/from-bigint.d.ts +7 -0
- package/dist/cjs/lib/create-weekly-report/utils/greater-than-max-deviation.d.ts +1 -0
- package/dist/cjs/lib/create-weekly-report/utils/hashLeaf.d.ts +7 -0
- package/dist/cjs/lib/create-weekly-report/utils/multiply-bigInt-by-decimal-percentage.d.ts +1 -0
- package/dist/cjs/lib/create-weekly-report/utils/to-bigint.d.ts +7 -0
- package/dist/cjs/utils/custom-to-fixed.d.ts +1 -0
- package/dist/cjs/utils/greater-than-max-deviation.d.ts +1 -0
- package/dist/cjs/utils/hash-leaf.d.ts +7 -0
- package/dist/esm/constants/regex.d.ts +1 -0
- package/dist/esm/constants/urls.d.ts +2 -0
- package/dist/esm/constants/weights.d.ts +12 -0
- package/dist/esm/index.d.ts +1 -1
- package/dist/esm/index.js +18988 -89
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/lib/create-weekly-report/index.d.ts +73 -0
- package/dist/esm/lib/create-weekly-report/types/Audit.d.ts +40 -0
- package/dist/esm/lib/create-weekly-report/types/RewardSplit copy.d.ts +5 -0
- package/dist/esm/lib/create-weekly-report/types/RewardSplit.d.ts +5 -0
- package/dist/esm/lib/create-weekly-report/types/RewardSplits copy.d.ts +2 -0
- package/dist/esm/lib/create-weekly-report/types/RewardSplits.d.ts +2 -0
- package/dist/esm/lib/create-weekly-report/types/index.d.ts +7 -0
- package/dist/esm/lib/create-weekly-report/types/merkle.d.ts +10 -0
- package/dist/esm/lib/create-weekly-report/utils/accumulate-leaf-weights.d.ts +2 -0
- package/dist/esm/lib/create-weekly-report/utils/custom-to-fixed.d.ts +1 -0
- package/dist/esm/lib/create-weekly-report/utils/fetch-farms-for-week.d.ts +12 -0
- package/dist/esm/lib/create-weekly-report/utils/from-bigint.d.ts +7 -0
- package/dist/esm/lib/create-weekly-report/utils/greater-than-max-deviation.d.ts +1 -0
- package/dist/esm/lib/create-weekly-report/utils/hashLeaf.d.ts +7 -0
- package/dist/esm/lib/create-weekly-report/utils/multiply-bigInt-by-decimal-percentage.d.ts +1 -0
- package/dist/esm/lib/create-weekly-report/utils/to-bigint.d.ts +7 -0
- package/dist/esm/utils/custom-to-fixed.d.ts +1 -0
- package/dist/esm/utils/greater-than-max-deviation.d.ts +1 -0
- package/dist/esm/utils/hash-leaf.d.ts +7 -0
- package/package.json +13 -9
- package/rollup.config.js +2 -0
- package/src/constants/regex.ts +2 -0
- package/src/constants/urls.ts +3 -0
- package/src/constants/weights.ts +15 -0
- package/src/index.ts +1 -1
- package/src/lib/create-weekly-report/index.ts +693 -0
- package/src/lib/create-weekly-report/types/Audit.ts +41 -0
- package/src/{types → lib/create-weekly-report/types}/AuditCompleted.ts +3 -1
- package/src/lib/create-weekly-report/types/AuditInherited.ts +8 -0
- package/src/lib/create-weekly-report/types/Device.ts +7 -0
- package/src/lib/create-weekly-report/types/DuplicatedButPastAuditCompleted.ts +10 -0
- package/src/lib/create-weekly-report/types/Farm.ts +22 -0
- package/src/{types → lib/create-weekly-report/types}/FarmStatus.ts +6 -6
- package/src/{types → lib/create-weekly-report/types}/GCAServerResponse.ts +5 -1
- package/src/lib/create-weekly-report/types/GetEquipmentDataHandlerParams.ts +7 -0
- package/src/lib/create-weekly-report/types/PayoutWalletAndSplit.ts +25 -0
- package/src/lib/create-weekly-report/types/PayoutWalletAndSplitWithRewardSplits.ts +23 -0
- package/src/lib/create-weekly-report/types/RewardSplit copy.ts +7 -0
- package/src/lib/create-weekly-report/types/RewardSplit.ts +7 -0
- package/src/{types/RewardSplit.ts → lib/create-weekly-report/types/RewardSplits copy.ts } +2 -1
- package/src/{types → lib/create-weekly-report/types}/RewardSplits.ts +1 -1
- package/src/{types → lib/create-weekly-report/types}/SlotRange.ts +4 -1
- package/src/{types → lib/create-weekly-report/types}/WeekAndSlotRange.ts +4 -1
- package/src/lib/create-weekly-report/types/index.ts +7 -0
- package/src/lib/create-weekly-report/types/merkle.ts +11 -0
- package/src/lib/create-weekly-report/types/stashed-Farm.ts +22 -0
- package/src/lib/create-weekly-report/utils/accumulate-leaf-weights.ts +17 -0
- package/src/lib/create-weekly-report/utils/custom-to-fixed.ts +9 -0
- package/src/lib/create-weekly-report/utils/fetch-farms-for-week.ts +30 -0
- package/src/lib/create-weekly-report/utils/from-bigint.ts +12 -0
- package/src/lib/create-weekly-report/utils/greater-than-max-deviation.ts +9 -0
- package/src/lib/create-weekly-report/utils/hashLeaf.ts +20 -0
- package/src/lib/create-weekly-report/utils/multiply-bigInt-by-decimal-percentage.ts +15 -0
- package/src/lib/create-weekly-report/utils/to-bigint.ts +16 -0
- package/src/utils/custom-to-fixed.ts +9 -0
- package/src/utils/greater-than-max-deviation.ts +9 -0
- package/src/utils/hash-leaf.ts +22 -0
- package/tsconfig.json +2 -2
- package/dist/cjs/types/GCAAndServerUrl.d.ts +0 -5
- package/dist/cjs/types/index.d.ts +0 -14
- package/dist/esm/types/GCAAndServerUrl.d.ts +0 -5
- package/dist/esm/types/index.d.ts +0 -14
- package/src/types/AuditInherited.ts +0 -3
- package/src/types/Device.ts +0 -3
- package/src/types/DuplicatedButPastAuditCompleted.ts +0 -4
- package/src/types/Farm.ts +0 -22
- package/src/types/GCAAndServerUrl.ts +0 -5
- package/src/types/GetEquipmentDataHandlerParams.ts +0 -3
- package/src/types/PayoutWalletAndSplit.ts +0 -5
- package/src/types/PayoutWalletAndSplitWithRewardSplits.ts +0 -6
- package/src/types/index.ts +0 -14
- package/src/types/stashed-Farm.ts +0 -22
- /package/dist/cjs/{types → lib/create-weekly-report/types}/AuditCompleted.d.ts +0 -0
- /package/dist/cjs/{types → lib/create-weekly-report/types}/AuditInherited.d.ts +0 -0
- /package/dist/cjs/{types → lib/create-weekly-report/types}/Device.d.ts +0 -0
- /package/dist/cjs/{types → lib/create-weekly-report/types}/DuplicatedButPastAuditCompleted.d.ts +0 -0
- /package/dist/cjs/{types → lib/create-weekly-report/types}/Farm.d.ts +0 -0
- /package/dist/cjs/{types → lib/create-weekly-report/types}/FarmStatus.d.ts +0 -0
- /package/dist/cjs/{types → lib/create-weekly-report/types}/GCAServerResponse.d.ts +0 -0
- /package/dist/cjs/{types → lib/create-weekly-report/types}/GetEquipmentDataHandlerParams.d.ts +0 -0
- /package/dist/cjs/{types → lib/create-weekly-report/types}/PayoutWalletAndSplit.d.ts +0 -0
- /package/dist/cjs/{types → lib/create-weekly-report/types}/PayoutWalletAndSplitWithRewardSplits.d.ts +0 -0
- /package/dist/cjs/{types/RewardSplit.d.ts → lib/create-weekly-report/types/RewardSplit copy.d.ts} +0 -0
- /package/dist/{esm → cjs/lib/create-weekly-report}/types/RewardSplit.d.ts +0 -0
- /package/dist/cjs/{types/RewardSplits.d.ts → lib/create-weekly-report/types/RewardSplits copy.d.ts} +0 -0
- /package/dist/{esm → cjs/lib/create-weekly-report}/types/RewardSplits.d.ts +0 -0
- /package/dist/cjs/{types → lib/create-weekly-report/types}/SlotRange.d.ts +0 -0
- /package/dist/cjs/{types → lib/create-weekly-report/types}/WeekAndSlotRange.d.ts +0 -0
- /package/dist/cjs/{types → lib/create-weekly-report/types}/stashed-Farm.d.ts +0 -0
- /package/dist/esm/{types → lib/create-weekly-report/types}/AuditCompleted.d.ts +0 -0
- /package/dist/esm/{types → lib/create-weekly-report/types}/AuditInherited.d.ts +0 -0
- /package/dist/esm/{types → lib/create-weekly-report/types}/Device.d.ts +0 -0
- /package/dist/esm/{types → lib/create-weekly-report/types}/DuplicatedButPastAuditCompleted.d.ts +0 -0
- /package/dist/esm/{types → lib/create-weekly-report/types}/Farm.d.ts +0 -0
- /package/dist/esm/{types → lib/create-weekly-report/types}/FarmStatus.d.ts +0 -0
- /package/dist/esm/{types → lib/create-weekly-report/types}/GCAServerResponse.d.ts +0 -0
- /package/dist/esm/{types → lib/create-weekly-report/types}/GetEquipmentDataHandlerParams.d.ts +0 -0
- /package/dist/esm/{types → lib/create-weekly-report/types}/PayoutWalletAndSplit.d.ts +0 -0
- /package/dist/esm/{types → lib/create-weekly-report/types}/PayoutWalletAndSplitWithRewardSplits.d.ts +0 -0
- /package/dist/esm/{types → lib/create-weekly-report/types}/SlotRange.d.ts +0 -0
- /package/dist/esm/{types → lib/create-weekly-report/types}/WeekAndSlotRange.d.ts +0 -0
- /package/dist/esm/{types → lib/create-weekly-report/types}/stashed-Farm.d.ts +0 -0
@@ -0,0 +1,693 @@
|
|
1
|
+
import axios from "axios";
|
2
|
+
import { formatUnits, parseUnits } from "viem";
|
3
|
+
import { MerkleTree } from "merkletreejs";
|
4
|
+
import { BigNumber, ethers } from "ethers";
|
5
|
+
import { greaterThanMaxDeviation } from "./utils/greater-than-max-deviation";
|
6
|
+
import { customToFixed } from "./utils/custom-to-fixed";
|
7
|
+
import { HUB_URL } from "../../constants/urls";
|
8
|
+
import Decimal from "decimal.js";
|
9
|
+
import { multiplyBigIntByDecimalPercentage } from "./utils/multiply-bigInt-by-decimal-percentage";
|
10
|
+
import { toBigInt } from "./utils/to-bigint";
|
11
|
+
import { fromBigInt } from "./utils/from-bigint";
|
12
|
+
import { fetchFarmsForWeek } from "./utils/fetch-farms-for-week";
|
13
|
+
import { accumulateLeafWeights } from "./utils/accumulate-leaf-weights";
|
14
|
+
import { FinalizedLeaf, MerkleLeaf } from "./types/merkle";
|
15
|
+
import { Audit } from "./types/Audit";
|
16
|
+
import { NUMERIC_REGEX } from "../../constants/regex";
|
17
|
+
import {
|
18
|
+
GLOW_WEIGHT_DECIMAL_PRECISION,
|
19
|
+
MAX_WEIGHT,
|
20
|
+
USDG_WEIGHT_DECIMAL_PRECISION,
|
21
|
+
} from "../../constants/weights";
|
22
|
+
import { hashLeaf } from "./utils/hashLeaf";
|
23
|
+
|
24
|
+
export type MerkleLeafIntermediary = {
|
25
|
+
wallet: string;
|
26
|
+
glowWeight: bigint;
|
27
|
+
usdgWeight: bigint;
|
28
|
+
};
|
29
|
+
|
30
|
+
export type FinalLeaf = {
|
31
|
+
wallet: string;
|
32
|
+
glowWeight: string;
|
33
|
+
usdgWeight: string;
|
34
|
+
};
|
35
|
+
|
36
|
+
export type CreateWeeklyReportArgs = {
|
37
|
+
week: number;
|
38
|
+
gcaUrls: string[];
|
39
|
+
apiUrl: string;
|
40
|
+
};
|
41
|
+
|
42
|
+
async function createWeeklyReportLegacy(args: CreateWeeklyReportArgs) {
|
43
|
+
const mapLegacy = new Map<string, MerkleLeafIntermediary>();
|
44
|
+
|
45
|
+
function addValueToMapLegacy(
|
46
|
+
key: string,
|
47
|
+
value: MerkleLeafIntermediary,
|
48
|
+
map: Map<string, MerkleLeafIntermediary>
|
49
|
+
) {
|
50
|
+
if (map.has(key)) {
|
51
|
+
const existingValue = map.get(key)!;
|
52
|
+
existingValue.glowWeight += value.glowWeight;
|
53
|
+
existingValue.usdgWeight += value.usdgWeight;
|
54
|
+
if (
|
55
|
+
existingValue.glowWeight > MAX_WEIGHT ||
|
56
|
+
existingValue.usdgWeight > MAX_WEIGHT
|
57
|
+
) {
|
58
|
+
throw new Error(`Accumulated weight overflow on wallet ${key}`);
|
59
|
+
}
|
60
|
+
map.set(key, existingValue);
|
61
|
+
} else {
|
62
|
+
if (value.glowWeight > MAX_WEIGHT || value.usdgWeight > MAX_WEIGHT) {
|
63
|
+
throw new Error(`Initial weight overflow on wallet ${key}`);
|
64
|
+
}
|
65
|
+
map.set(key, value);
|
66
|
+
}
|
67
|
+
}
|
68
|
+
|
69
|
+
const apiResposne = await fetchFarmsForWeek(
|
70
|
+
args.week,
|
71
|
+
args.gcaUrls,
|
72
|
+
args.apiUrl
|
73
|
+
);
|
74
|
+
const farms = apiResposne.filteredFarms;
|
75
|
+
const rawData = apiResposne.rawData;
|
76
|
+
let totalCreditsProduced: bigint = BigInt(0);
|
77
|
+
|
78
|
+
for (const farm of farms) {
|
79
|
+
if (farm.status === "Unassigned") {
|
80
|
+
throw new Error(`Farm ${farm.shortId} is unassigned`);
|
81
|
+
}
|
82
|
+
|
83
|
+
if (farm.carbonCreditsProduced < 0) {
|
84
|
+
console.log(
|
85
|
+
`Farm: ${farm.shortId} has ${farm.carbonCreditsProduced} carbon credits produced`
|
86
|
+
);
|
87
|
+
throw new Error("Carbon credits produced is less than 0");
|
88
|
+
}
|
89
|
+
totalCreditsProduced += parseUnits(
|
90
|
+
customToFixed(farm.carbonCreditsProduced, 18),
|
91
|
+
18
|
92
|
+
);
|
93
|
+
|
94
|
+
if (!farm.rewardSplits)
|
95
|
+
throw new Error(`No reward splits for farm ${farm.shortId}`);
|
96
|
+
|
97
|
+
const sumOfRewardSplitsGlowWeight = farm.rewardSplits.reduce(
|
98
|
+
(acc, rewardSplit) => acc + rewardSplit.glowSplitPercent,
|
99
|
+
0
|
100
|
+
);
|
101
|
+
const sumOfRewardSplitsUSDGWeight = farm.rewardSplits.reduce(
|
102
|
+
(acc, rewardSplit) => acc + rewardSplit.usdgSplitPercent,
|
103
|
+
0
|
104
|
+
);
|
105
|
+
const percentTolerance = 1e-12;
|
106
|
+
if (Math.abs(sumOfRewardSplitsGlowWeight - 1) > percentTolerance)
|
107
|
+
throw new Error(
|
108
|
+
`Glow weight splits do not add up to 1 for farm ${farm.shortId}`
|
109
|
+
);
|
110
|
+
if (Math.abs(sumOfRewardSplitsUSDGWeight - 1) > percentTolerance)
|
111
|
+
throw new Error(
|
112
|
+
`USDG weight splits do not add up to 1 for farm ${farm.shortId}`
|
113
|
+
);
|
114
|
+
|
115
|
+
for (const rewardSplit of farm.rewardSplits) {
|
116
|
+
const glowBigInt: bigint = BigInt(
|
117
|
+
parseUnits(
|
118
|
+
customToFixed(farm.weeklyPayment, GLOW_WEIGHT_DECIMAL_PRECISION),
|
119
|
+
GLOW_WEIGHT_DECIMAL_PRECISION
|
120
|
+
)
|
121
|
+
);
|
122
|
+
const usdgBigInt: bigint = BigInt(
|
123
|
+
parseUnits(
|
124
|
+
customToFixed(
|
125
|
+
farm.carbonCreditsProduced,
|
126
|
+
USDG_WEIGHT_DECIMAL_PRECISION
|
127
|
+
),
|
128
|
+
USDG_WEIGHT_DECIMAL_PRECISION
|
129
|
+
)
|
130
|
+
);
|
131
|
+
const glowWeight = multiplyBigIntByDecimalPercentage(
|
132
|
+
glowBigInt,
|
133
|
+
GLOW_WEIGHT_DECIMAL_PRECISION,
|
134
|
+
rewardSplit.glowSplitPercent
|
135
|
+
);
|
136
|
+
const usdgWeight = multiplyBigIntByDecimalPercentage(
|
137
|
+
usdgBigInt,
|
138
|
+
USDG_WEIGHT_DECIMAL_PRECISION,
|
139
|
+
rewardSplit.usdgSplitPercent
|
140
|
+
);
|
141
|
+
const value: MerkleLeafIntermediary = {
|
142
|
+
wallet: rewardSplit.walletAddress,
|
143
|
+
glowWeight,
|
144
|
+
usdgWeight,
|
145
|
+
};
|
146
|
+
//Make sure the usdgWeight and the glowWeight are > 0 if the number is > 0
|
147
|
+
if (
|
148
|
+
farm.carbonCreditsProduced > 0 &&
|
149
|
+
usdgWeight <= 0 &&
|
150
|
+
rewardSplit.usdgSplitPercent > 0
|
151
|
+
) {
|
152
|
+
console.log(
|
153
|
+
farm.carbonCreditsProduced,
|
154
|
+
usdgWeight,
|
155
|
+
rewardSplit.usdgSplitPercent
|
156
|
+
);
|
157
|
+
throw new Error(
|
158
|
+
"USDG weight is less than 0 and carbon credits produced is greater than 0"
|
159
|
+
);
|
160
|
+
}
|
161
|
+
if (
|
162
|
+
farm.weeklyPayment > 0 &&
|
163
|
+
glowWeight <= 0 &&
|
164
|
+
rewardSplit.glowSplitPercent > 0
|
165
|
+
) {
|
166
|
+
console.log(
|
167
|
+
farm.weeklyPayment,
|
168
|
+
glowWeight,
|
169
|
+
rewardSplit.glowSplitPercent
|
170
|
+
);
|
171
|
+
throw new Error(
|
172
|
+
"Glow weight is less than 0 and weekly payment is greater than 0"
|
173
|
+
);
|
174
|
+
}
|
175
|
+
|
176
|
+
if (
|
177
|
+
farm.carbonCreditsProduced > 0 &&
|
178
|
+
usdgWeight <= 0 &&
|
179
|
+
rewardSplit.usdgSplitPercent > 0
|
180
|
+
) {
|
181
|
+
console.log(
|
182
|
+
farm.carbonCreditsProduced,
|
183
|
+
usdgWeight.toString(),
|
184
|
+
rewardSplit.usdgSplitPercent
|
185
|
+
);
|
186
|
+
throw new Error(
|
187
|
+
`USDG weight is less than or equal to 0 and carbon credits produced is greater than 0 for farm ${farm.shortId}`
|
188
|
+
);
|
189
|
+
}
|
190
|
+
if (
|
191
|
+
farm.weeklyPayment > 0 &&
|
192
|
+
glowWeight <= 0 &&
|
193
|
+
rewardSplit.glowSplitPercent > 0
|
194
|
+
) {
|
195
|
+
console.log(
|
196
|
+
farm.weeklyPayment,
|
197
|
+
glowWeight.toString(),
|
198
|
+
rewardSplit.glowSplitPercent
|
199
|
+
);
|
200
|
+
throw new Error(
|
201
|
+
`Glow weight is less than or equal to 0 and weekly payment is greater than 0 for farm ${farm.shortId}`
|
202
|
+
);
|
203
|
+
}
|
204
|
+
|
205
|
+
addValueToMapLegacy(rewardSplit.walletAddress, value, mapLegacy);
|
206
|
+
}
|
207
|
+
}
|
208
|
+
|
209
|
+
const merkleLeaves = Array.from(mapLegacy.values());
|
210
|
+
const finalLeaves: FinalLeaf[] = merkleLeaves.map(
|
211
|
+
({ wallet, glowWeight, usdgWeight }) => ({
|
212
|
+
wallet,
|
213
|
+
glowWeight: glowWeight.toString(),
|
214
|
+
usdgWeight: usdgWeight.toString(),
|
215
|
+
})
|
216
|
+
);
|
217
|
+
const leaves = finalLeaves.map((leaf) =>
|
218
|
+
hashLeaf({
|
219
|
+
address: leaf.wallet,
|
220
|
+
glowWeight: leaf.glowWeight,
|
221
|
+
usdcWeight: leaf.usdgWeight,
|
222
|
+
})
|
223
|
+
);
|
224
|
+
|
225
|
+
const tree = new MerkleTree(leaves, ethers.utils.keccak256, { sort: true });
|
226
|
+
const root = tree.getHexRoot();
|
227
|
+
|
228
|
+
const totalGlowWeightFinalizedLeavesSum = finalLeaves.reduce(
|
229
|
+
(acc, { glowWeight }) => acc.add(glowWeight),
|
230
|
+
ethers.BigNumber.from(0)
|
231
|
+
);
|
232
|
+
const totalGCCWeightFinalizedLeavesSum = finalLeaves.reduce(
|
233
|
+
(acc, { usdgWeight }) => acc.add(usdgWeight),
|
234
|
+
ethers.BigNumber.from(0)
|
235
|
+
);
|
236
|
+
|
237
|
+
if (totalGlowWeightFinalizedLeavesSum.toBigInt() > MAX_WEIGHT) {
|
238
|
+
throw new Error("Total glow weight is greater than max weight");
|
239
|
+
}
|
240
|
+
if (totalGCCWeightFinalizedLeavesSum.toBigInt() > MAX_WEIGHT) {
|
241
|
+
throw new Error("Total gcc weight is greater than max weight");
|
242
|
+
}
|
243
|
+
|
244
|
+
const headlineStats = {
|
245
|
+
weekNumber: args.week,
|
246
|
+
totalCreditsProduced: formatUnits(totalCreditsProduced, 18),
|
247
|
+
totalCreditsProducedBN: totalCreditsProduced.toString(),
|
248
|
+
totalGlowWeightInFinalized: totalGlowWeightFinalizedLeavesSum.toString(),
|
249
|
+
totalGlowWeightHuman: formatUnits(
|
250
|
+
BigInt(totalGlowWeightFinalizedLeavesSum.toString()),
|
251
|
+
GLOW_WEIGHT_DECIMAL_PRECISION
|
252
|
+
).toString(),
|
253
|
+
totalUSDGWeightInFinalized: totalGCCWeightFinalizedLeavesSum.toString(),
|
254
|
+
totalUSDGWeightHuman: formatUnits(
|
255
|
+
BigInt(totalGCCWeightFinalizedLeavesSum.toString()),
|
256
|
+
USDG_WEIGHT_DECIMAL_PRECISION
|
257
|
+
).toString(),
|
258
|
+
root: root,
|
259
|
+
glowWeightDecimals: GLOW_WEIGHT_DECIMAL_PRECISION,
|
260
|
+
usdgWeightDecimals: USDG_WEIGHT_DECIMAL_PRECISION,
|
261
|
+
};
|
262
|
+
|
263
|
+
const farmsWithMerkleProofs = finalLeaves.map((leaf) => {
|
264
|
+
const hashedLeaf = hashLeaf({
|
265
|
+
address: leaf.wallet,
|
266
|
+
glowWeight: leaf.glowWeight,
|
267
|
+
usdcWeight: leaf.usdgWeight,
|
268
|
+
});
|
269
|
+
const proof = tree.getHexProof(hashedLeaf);
|
270
|
+
const isValid = tree.verify(proof, hashedLeaf, root);
|
271
|
+
if (!isValid) {
|
272
|
+
throw new Error(`Invalid proof for wallet ${leaf.wallet}`);
|
273
|
+
}
|
274
|
+
return {
|
275
|
+
...leaf,
|
276
|
+
proof,
|
277
|
+
};
|
278
|
+
});
|
279
|
+
|
280
|
+
let forLoopedGlowWeightSum: ethers.BigNumber = ethers.BigNumber.from(0);
|
281
|
+
for (const leafProof of farmsWithMerkleProofs) {
|
282
|
+
forLoopedGlowWeightSum = forLoopedGlowWeightSum.add(
|
283
|
+
BigNumber.from(leafProof.glowWeight)
|
284
|
+
);
|
285
|
+
}
|
286
|
+
|
287
|
+
if (!forLoopedGlowWeightSum.eq(totalGlowWeightFinalizedLeavesSum)) {
|
288
|
+
console.error("Glow Weight Sum Mismatch:");
|
289
|
+
console.error("Sum from loop:", forLoopedGlowWeightSum.toString());
|
290
|
+
console.error(
|
291
|
+
"Sum from reduce:",
|
292
|
+
totalGlowWeightFinalizedLeavesSum.toString()
|
293
|
+
);
|
294
|
+
throw new Error("Glow weight sum is not equal");
|
295
|
+
}
|
296
|
+
|
297
|
+
let forLoopedGCCWeightSum: ethers.BigNumber = ethers.BigNumber.from(0);
|
298
|
+
for (const leafProof of farmsWithMerkleProofs) {
|
299
|
+
forLoopedGCCWeightSum = forLoopedGCCWeightSum.add(
|
300
|
+
BigNumber.from(leafProof.usdgWeight)
|
301
|
+
);
|
302
|
+
}
|
303
|
+
|
304
|
+
if (!forLoopedGCCWeightSum.eq(totalGCCWeightFinalizedLeavesSum)) {
|
305
|
+
console.error("USDG Weight Sum Mismatch:");
|
306
|
+
console.error("Sum from loop:", forLoopedGCCWeightSum.toString());
|
307
|
+
console.error(
|
308
|
+
"Sum from reduce:",
|
309
|
+
totalGCCWeightFinalizedLeavesSum.toString()
|
310
|
+
);
|
311
|
+
throw new Error("GCC weight sum is not equal");
|
312
|
+
}
|
313
|
+
|
314
|
+
{
|
315
|
+
const totalCreditsProducedNumber = Number(
|
316
|
+
headlineStats.totalCreditsProduced
|
317
|
+
);
|
318
|
+
const totalUSDGWeightNumber = Number(headlineStats.totalUSDGWeightHuman);
|
319
|
+
const maxDeviation = 0.001;
|
320
|
+
if (
|
321
|
+
greaterThanMaxDeviation(
|
322
|
+
totalCreditsProducedNumber,
|
323
|
+
totalUSDGWeightNumber,
|
324
|
+
maxDeviation
|
325
|
+
)
|
326
|
+
) {
|
327
|
+
console.error("Deviation Check Failed: Credits Produced vs USDG Weight");
|
328
|
+
console.error("Total Credits Produced:", totalCreditsProducedNumber);
|
329
|
+
console.error("Total USDG Weight:", totalUSDGWeightNumber);
|
330
|
+
console.error("Allowed Deviation:", maxDeviation);
|
331
|
+
throw new Error(
|
332
|
+
"Total credits produced and total usdg weight deviation > 0.1%"
|
333
|
+
);
|
334
|
+
}
|
335
|
+
}
|
336
|
+
|
337
|
+
{
|
338
|
+
const totalGlowWeightNumber = Number(headlineStats.totalGlowWeightHuman);
|
339
|
+
const totalProtocolFeePayments = farms.reduce(
|
340
|
+
(acc, farm) => acc + farm.weeklyPayment,
|
341
|
+
0
|
342
|
+
);
|
343
|
+
const maxDeviation = 0.001;
|
344
|
+
if (
|
345
|
+
greaterThanMaxDeviation(
|
346
|
+
totalGlowWeightNumber,
|
347
|
+
totalProtocolFeePayments,
|
348
|
+
maxDeviation
|
349
|
+
)
|
350
|
+
) {
|
351
|
+
console.error("Deviation Check Failed: Glow Weight vs Protocol Fees");
|
352
|
+
console.error("Total Glow Weight:", totalGlowWeightNumber);
|
353
|
+
console.error("Total Protocol Fees:", totalProtocolFeePayments);
|
354
|
+
console.error("Allowed Deviation:", maxDeviation);
|
355
|
+
throw new Error(
|
356
|
+
"Total glow weight and total protocol fee payments deviation > 0.1%"
|
357
|
+
);
|
358
|
+
}
|
359
|
+
}
|
360
|
+
|
361
|
+
return {
|
362
|
+
headlineStats,
|
363
|
+
finalLeaves,
|
364
|
+
farmsWithMerkleProofs,
|
365
|
+
farms,
|
366
|
+
rawData,
|
367
|
+
};
|
368
|
+
}
|
369
|
+
|
370
|
+
export async function createWeeklyReport({
|
371
|
+
week,
|
372
|
+
gcaUrls,
|
373
|
+
apiUrl,
|
374
|
+
}: CreateWeeklyReportArgs) {
|
375
|
+
if (week < 72) {
|
376
|
+
return createWeeklyReportLegacy({ week, gcaUrls, apiUrl });
|
377
|
+
}
|
378
|
+
|
379
|
+
const map = new Map<string, MerkleLeaf>();
|
380
|
+
|
381
|
+
const [apiResponse, auditsRes] = await Promise.all([
|
382
|
+
fetchFarmsForWeek(week, gcaUrls, apiUrl),
|
383
|
+
axios.get<Audit[]>(
|
384
|
+
`${HUB_URL}/api/audits?omitDocuments=true&weekNumber=${week}`
|
385
|
+
),
|
386
|
+
]);
|
387
|
+
|
388
|
+
const farms = apiResponse.filteredFarms;
|
389
|
+
const audits = auditsRes.data;
|
390
|
+
const rawData = apiResponse.rawData;
|
391
|
+
|
392
|
+
const shortIdToAdjustedCredit = new Map<string, bigint>();
|
393
|
+
|
394
|
+
for (const audit of audits) {
|
395
|
+
const activeShortIds = audit.activeShortIds ?? [];
|
396
|
+
const adjustedCredit =
|
397
|
+
audit.summary?.carbonFootprintAndProduction?.adjustedWeeklyCarbonCredit?.trim();
|
398
|
+
|
399
|
+
if (!adjustedCredit || !NUMERIC_REGEX.test(adjustedCredit))
|
400
|
+
throw new Error(
|
401
|
+
`Invalid adjustedWeeklyCarbonCredit for audit ${audit.id}`
|
402
|
+
);
|
403
|
+
if (activeShortIds.length === 0)
|
404
|
+
throw new Error(`audit ${audit.id} has empty activeShortIds`);
|
405
|
+
|
406
|
+
const splitValue = new Decimal(adjustedCredit).div(activeShortIds.length);
|
407
|
+
if (splitValue.isZero())
|
408
|
+
throw new Error(
|
409
|
+
`Zero adjustedWeeklyCarbonCredit split in audit ${audit.id}`
|
410
|
+
);
|
411
|
+
|
412
|
+
const splitBigInt = toBigInt(splitValue, USDG_WEIGHT_DECIMAL_PRECISION);
|
413
|
+
for (const sid of activeShortIds)
|
414
|
+
shortIdToAdjustedCredit.set(String(sid), splitBigInt);
|
415
|
+
}
|
416
|
+
|
417
|
+
const farmShortIds = new Set(farms.map((f: any) => String(f.shortId)));
|
418
|
+
audits.forEach((audit: any) =>
|
419
|
+
audit.activeShortIds?.forEach((sid: string | number) => {
|
420
|
+
if (!farmShortIds.has(String(sid)))
|
421
|
+
throw new Error(
|
422
|
+
`activeShortId ${sid} from audit ${audit.id} missing in filteredFarms`
|
423
|
+
);
|
424
|
+
})
|
425
|
+
);
|
426
|
+
|
427
|
+
let totalCreditsProduced18dp = BigInt(0);
|
428
|
+
|
429
|
+
for (const farm of farms) {
|
430
|
+
if (farm.status === "Unassigned") {
|
431
|
+
throw new Error(`farm ${farm.shortId} is unassigned`);
|
432
|
+
}
|
433
|
+
|
434
|
+
if (!farm.rewardSplits)
|
435
|
+
throw new Error(`farm ${farm.shortId} has no rewardSplits`);
|
436
|
+
|
437
|
+
if (farm.carbonCreditsProduced < 0) {
|
438
|
+
console.log(
|
439
|
+
`Farm: ${farm.shortId} has ${farm.carbonCreditsProduced} carbon credits produced`
|
440
|
+
);
|
441
|
+
throw new Error(
|
442
|
+
"Carbon credits produced is less than 0 for farm " + farm.shortId
|
443
|
+
);
|
444
|
+
}
|
445
|
+
|
446
|
+
totalCreditsProduced18dp += parseUnits(
|
447
|
+
customToFixed(farm.carbonCreditsProduced, 18),
|
448
|
+
18
|
449
|
+
);
|
450
|
+
|
451
|
+
const sumGlow = farm.rewardSplits.reduce(
|
452
|
+
(acc: number, r: any) => acc + r.glowSplitPercent,
|
453
|
+
0
|
454
|
+
);
|
455
|
+
const sumUSDG = farm.rewardSplits.reduce(
|
456
|
+
(acc: number, r: any) => acc + r.usdgSplitPercent,
|
457
|
+
0
|
458
|
+
);
|
459
|
+
const percentTolerance = 1e-12;
|
460
|
+
if (Math.abs(sumGlow - 1) > percentTolerance)
|
461
|
+
throw new Error(`Glow splits ≠1 for farm ${farm.shortId}`);
|
462
|
+
if (Math.abs(sumUSDG - 1) > percentTolerance)
|
463
|
+
throw new Error(`USDG splits ≠1 for farm ${farm.shortId}`);
|
464
|
+
|
465
|
+
const glowBase = parseUnits(
|
466
|
+
customToFixed(farm.weeklyPayment, GLOW_WEIGHT_DECIMAL_PRECISION),
|
467
|
+
GLOW_WEIGHT_DECIMAL_PRECISION
|
468
|
+
);
|
469
|
+
|
470
|
+
const adjustedCreditBigInt =
|
471
|
+
shortIdToAdjustedCredit.get(String(farm.shortId)) ?? BigInt(0);
|
472
|
+
|
473
|
+
for (const split of farm.rewardSplits) {
|
474
|
+
const glowWeight = multiplyBigIntByDecimalPercentage(
|
475
|
+
glowBase,
|
476
|
+
GLOW_WEIGHT_DECIMAL_PRECISION,
|
477
|
+
split.glowSplitPercent
|
478
|
+
);
|
479
|
+
const usdgWeight = multiplyBigIntByDecimalPercentage(
|
480
|
+
adjustedCreditBigInt,
|
481
|
+
USDG_WEIGHT_DECIMAL_PRECISION,
|
482
|
+
split.usdgSplitPercent
|
483
|
+
);
|
484
|
+
|
485
|
+
if (
|
486
|
+
split.usdgSplitPercent > 0 &&
|
487
|
+
adjustedCreditBigInt > BigInt(0) &&
|
488
|
+
usdgWeight === BigInt(0)
|
489
|
+
)
|
490
|
+
throw new Error(`USDG dust lost for farm ${farm.shortId}`);
|
491
|
+
if (
|
492
|
+
split.glowSplitPercent > 0 &&
|
493
|
+
glowBase > BigInt(0) &&
|
494
|
+
glowWeight === BigInt(0)
|
495
|
+
)
|
496
|
+
throw new Error(`Glow dust lost for farm ${farm.shortId}`);
|
497
|
+
|
498
|
+
if (glowWeight > MAX_WEIGHT || usdgWeight > MAX_WEIGHT)
|
499
|
+
throw new Error(
|
500
|
+
`Leaf weight overflow on wallet ${split.walletAddress}`
|
501
|
+
);
|
502
|
+
|
503
|
+
accumulateLeafWeights(
|
504
|
+
split.walletAddress,
|
505
|
+
{ wallet: split.walletAddress, glowWeight, usdgWeight },
|
506
|
+
map
|
507
|
+
);
|
508
|
+
}
|
509
|
+
}
|
510
|
+
|
511
|
+
const finalizedLeaves: FinalizedLeaf[] = Array.from(map.values()).map(
|
512
|
+
({ wallet, glowWeight, usdgWeight }) => ({
|
513
|
+
wallet,
|
514
|
+
glowWeight: glowWeight.toString(),
|
515
|
+
usdgWeight: usdgWeight.toString(),
|
516
|
+
})
|
517
|
+
);
|
518
|
+
|
519
|
+
const hashedLeaves = finalizedLeaves.map((leaf) =>
|
520
|
+
hashLeaf({
|
521
|
+
address: leaf.wallet,
|
522
|
+
glowWeight: leaf.glowWeight,
|
523
|
+
usdcWeight: leaf.usdgWeight,
|
524
|
+
})
|
525
|
+
);
|
526
|
+
|
527
|
+
const merkleTree = new MerkleTree(hashedLeaves, ethers.utils.keccak256, {
|
528
|
+
sort: true,
|
529
|
+
});
|
530
|
+
const merkleRoot = merkleTree.getHexRoot();
|
531
|
+
|
532
|
+
const totalGlowWeight = finalizedLeaves.reduce(
|
533
|
+
(acc, { glowWeight }) => acc.add(glowWeight),
|
534
|
+
ethers.BigNumber.from(0)
|
535
|
+
);
|
536
|
+
const totalUSDGWeight = finalizedLeaves.reduce(
|
537
|
+
(acc, { usdgWeight }) => acc.add(usdgWeight),
|
538
|
+
ethers.BigNumber.from(0)
|
539
|
+
);
|
540
|
+
|
541
|
+
if (totalGlowWeight.toBigInt() > MAX_WEIGHT)
|
542
|
+
throw new Error("Total glow weight overflow");
|
543
|
+
if (totalUSDGWeight.toBigInt() > MAX_WEIGHT)
|
544
|
+
throw new Error("Total USDG weight overflow");
|
545
|
+
|
546
|
+
const leavesWithProofs = finalizedLeaves.map((leaf) => {
|
547
|
+
const hashed = hashLeaf({
|
548
|
+
address: leaf.wallet,
|
549
|
+
glowWeight: leaf.glowWeight,
|
550
|
+
usdcWeight: leaf.usdgWeight,
|
551
|
+
});
|
552
|
+
const proof = merkleTree.getHexProof(hashed);
|
553
|
+
if (!merkleTree.verify(proof, hashed, merkleRoot))
|
554
|
+
throw new Error("Invalid proof for " + leaf.wallet);
|
555
|
+
return { ...leaf, proof };
|
556
|
+
});
|
557
|
+
|
558
|
+
const glowSumProofLoop = leavesWithProofs.reduce(
|
559
|
+
(acc, l) => acc.add(l.glowWeight),
|
560
|
+
ethers.BigNumber.from(0)
|
561
|
+
);
|
562
|
+
if (!glowSumProofLoop.eq(totalGlowWeight)) {
|
563
|
+
console.error("Glow Weight Sum Mismatch (Post-73):");
|
564
|
+
console.error("Sum from loop:", glowSumProofLoop.toString());
|
565
|
+
console.error("Sum from reduce:", totalGlowWeight.toString());
|
566
|
+
throw new Error("Glow sum mismatch");
|
567
|
+
}
|
568
|
+
|
569
|
+
const usdgSumProofLoop = leavesWithProofs.reduce(
|
570
|
+
(acc, l) => acc.add(l.usdgWeight),
|
571
|
+
ethers.BigNumber.from(0)
|
572
|
+
);
|
573
|
+
if (!usdgSumProofLoop.eq(totalUSDGWeight)) {
|
574
|
+
console.error("USDG Weight Sum Mismatch (Post-73):");
|
575
|
+
console.error("Sum from loop:", usdgSumProofLoop.toString());
|
576
|
+
console.error("Sum from reduce:", totalUSDGWeight.toString());
|
577
|
+
throw new Error("USDG sum mismatch");
|
578
|
+
}
|
579
|
+
|
580
|
+
const totalExpectedCredits = farms.reduce((acc: Decimal, f: any) => {
|
581
|
+
const adj = shortIdToAdjustedCredit.get(String(f.shortId)) ?? BigInt(0);
|
582
|
+
return acc.plus(fromBigInt(adj, USDG_WEIGHT_DECIMAL_PRECISION));
|
583
|
+
}, new Decimal(0));
|
584
|
+
|
585
|
+
const totalUSDGWeightHuman = new Decimal(
|
586
|
+
formatUnits(
|
587
|
+
BigInt(totalUSDGWeight.toString()),
|
588
|
+
USDG_WEIGHT_DECIMAL_PRECISION
|
589
|
+
)
|
590
|
+
);
|
591
|
+
if (
|
592
|
+
greaterThanMaxDeviation(
|
593
|
+
totalExpectedCredits.toNumber(),
|
594
|
+
totalUSDGWeightHuman.toNumber(),
|
595
|
+
0.001
|
596
|
+
)
|
597
|
+
) {
|
598
|
+
console.error(
|
599
|
+
"Deviation Check Failed (Post-73): Expected Credits vs USDG Weight"
|
600
|
+
);
|
601
|
+
console.error("Total Expected Credits:", totalExpectedCredits.toNumber());
|
602
|
+
console.error("Total USDG Weight:", totalUSDGWeightHuman.toNumber());
|
603
|
+
console.error("Allowed Deviation:", 0.001);
|
604
|
+
throw new Error("totalExpectedCredits vs USDG weight deviation >0.1% ");
|
605
|
+
}
|
606
|
+
|
607
|
+
const totalGlowWeightHuman = new Decimal(
|
608
|
+
formatUnits(
|
609
|
+
BigInt(totalGlowWeight.toString()),
|
610
|
+
GLOW_WEIGHT_DECIMAL_PRECISION
|
611
|
+
)
|
612
|
+
);
|
613
|
+
const totalProtocolFeePayments = farms.reduce(
|
614
|
+
(acc: number, f: any) => acc + f.weeklyPayment,
|
615
|
+
0
|
616
|
+
);
|
617
|
+
if (
|
618
|
+
greaterThanMaxDeviation(
|
619
|
+
totalGlowWeightHuman.toNumber(),
|
620
|
+
totalProtocolFeePayments,
|
621
|
+
0.001
|
622
|
+
)
|
623
|
+
) {
|
624
|
+
console.error(
|
625
|
+
"Deviation Check Failed (Post-73): Glow Weight vs Protocol Fees"
|
626
|
+
);
|
627
|
+
console.error("Total Glow Weight:", totalGlowWeightHuman.toNumber());
|
628
|
+
console.error("Total Protocol Fees:", totalProtocolFeePayments);
|
629
|
+
console.error("Allowed Deviation:", 0.001);
|
630
|
+
throw new Error("totalGlowWeight vs protocol fees deviation >0.1% ");
|
631
|
+
}
|
632
|
+
|
633
|
+
const headlineStats = {
|
634
|
+
weekNumber: week,
|
635
|
+
totalCreditsProduced: formatUnits(totalCreditsProduced18dp, 18),
|
636
|
+
totalCreditsProducedBN: totalCreditsProduced18dp.toString(),
|
637
|
+
totalGlowWeightInFinalized: totalGlowWeight.toString(),
|
638
|
+
totalGlowWeightHuman: totalGlowWeightHuman.toString(),
|
639
|
+
totalUSDGWeightInFinalized: totalUSDGWeight.toString(),
|
640
|
+
totalUSDGWeightHuman: totalUSDGWeightHuman.toString(),
|
641
|
+
root: merkleRoot,
|
642
|
+
glowWeightDecimals: GLOW_WEIGHT_DECIMAL_PRECISION,
|
643
|
+
usdgWeightDecimals: USDG_WEIGHT_DECIMAL_PRECISION,
|
644
|
+
};
|
645
|
+
|
646
|
+
const shortIdAdjustedList = Array.from(shortIdToAdjustedCredit.entries()).map(
|
647
|
+
([shortId, creditBigInt]) => ({
|
648
|
+
shortId,
|
649
|
+
adjustedCredit: fromBigInt(
|
650
|
+
creditBigInt,
|
651
|
+
USDG_WEIGHT_DECIMAL_PRECISION
|
652
|
+
).toString(),
|
653
|
+
})
|
654
|
+
);
|
655
|
+
|
656
|
+
const creditsDeviationList = farms.map((farm: any) => {
|
657
|
+
const adj = shortIdToAdjustedCredit.get(String(farm.shortId)) ?? BigInt(0);
|
658
|
+
const adjusted = fromBigInt(adj, USDG_WEIGHT_DECIMAL_PRECISION);
|
659
|
+
const produced = new Decimal(farm.carbonCreditsProduced);
|
660
|
+
let deviation: Decimal;
|
661
|
+
let absDeviation: Decimal;
|
662
|
+
let deviationPercent: Decimal;
|
663
|
+
if (produced.isZero() && adjusted.isZero()) {
|
664
|
+
deviation = new Decimal(0);
|
665
|
+
absDeviation = new Decimal(0);
|
666
|
+
deviationPercent = new Decimal(0);
|
667
|
+
} else {
|
668
|
+
deviation = produced.minus(adjusted);
|
669
|
+
absDeviation = deviation.abs();
|
670
|
+
deviationPercent = deviation
|
671
|
+
.div(produced.isZero() ? 1 : produced)
|
672
|
+
.mul(100);
|
673
|
+
}
|
674
|
+
return {
|
675
|
+
shortId: String(farm.shortId),
|
676
|
+
carbonCreditsProduced: produced.toNumber(),
|
677
|
+
adjustedWeeklyCarbonCredit: adjusted.toNumber(),
|
678
|
+
deviation: deviation.toNumber(),
|
679
|
+
absDeviation: absDeviation.toNumber(),
|
680
|
+
deviationPercent: deviationPercent.toNumber(),
|
681
|
+
};
|
682
|
+
});
|
683
|
+
|
684
|
+
return {
|
685
|
+
headlineStats,
|
686
|
+
finalizedLeaves,
|
687
|
+
leavesWithProofs,
|
688
|
+
farms,
|
689
|
+
rawData,
|
690
|
+
shortIdAdjustedList,
|
691
|
+
creditsDeviationList,
|
692
|
+
};
|
693
|
+
}
|