@gooddollar/goodprotocol 1.0.17 → 1.0.18-beta.0

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/hardhat.config.ts CHANGED
@@ -18,6 +18,7 @@ import {
18
18
  airdrop as gdxAirdrop,
19
19
  airdropRecover as gdxAirdropRecover
20
20
  } from "./scripts/gdx/gdxAirdropCalculation";
21
+ import { sumStakersGdRewards } from "./scripts/staking/stakersGdRewardsCalculation";
21
22
  import { verify } from "./scripts/verify";
22
23
  import { ethers } from "ethers";
23
24
  config();
@@ -223,8 +224,6 @@ task("gdxAirdrop", "Calculates airdrop data")
223
224
 
224
225
  task("gdxAirdropRecover", "Calculates new airdrop data for recovery")
225
226
  .addParam("action", "addition/tree")
226
- .addOptionalPositionalParam("address", "proof for address")
227
- .addOptionalParam("ethsnapshotblock", "eth block for calculate")
228
227
  .setAction(async (taskArgs, hre) => {
229
228
  const actions = gdxAirdropRecover(hre.ethers);
230
229
  switch (taskArgs.action) {
@@ -243,3 +242,10 @@ task("verifyjson", "verify contracts on etherscan").setAction(
243
242
  }
244
243
  );
245
244
  export default hhconfig;
245
+
246
+ task("sumStakersGdRewards", "Sums the GoodDollar reward for each staker")
247
+ .setAction(async (taskArgs, hre) => {
248
+ const actions = sumStakersGdRewards(hre.ethers);
249
+ return actions.getStakersGdRewards();
250
+ }
251
+ );
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gooddollar/goodprotocol",
3
- "version": "1.0.17",
3
+ "version": "1.0.18-beta.0",
4
4
  "description": "GoodDollar Protocol",
5
5
  "scripts": {
6
6
  "build": "scripts/build.sh deploy",
@@ -463,6 +463,7 @@
463
463
  "StakersDistribution": "0x5766cf4b2fdb09d986eb1783d276013c224e28c8",
464
464
  "GoodFundManager": "0x0c6c80d2061afa35e160f3799411d83bdeea0a5a",
465
465
  "GReputation": "0x603b8c0f110e037b51a381cbcacabb8d6c6e4543",
466
+ "CompoundVotingMachine": "0x57ee6ceff51cb30ecb1245934a882c500fbec1e9",
466
467
  "ProtocolUpgradeRecover": "0x6f1b4dFDd7156FC5752541Ef35EDF57B48E74475",
467
468
  "network": "production-mainnet",
468
469
  "networkId": 1,
@@ -502,8 +503,7 @@
502
503
  "0x3ff2d8eb2573819a9ef7167d2ba6fd6d31b17f4f",
503
504
  6944
504
505
  ]
505
- ],
506
- "CompoundVotingMachine": "0xc2Ff55b896e3c42f9e1c2f7467C51b93F1C23dFD"
506
+ ]
507
507
  },
508
508
  "production": {
509
509
  "NameService": "0xec6dcE387B1616a0c44fF2E4fA9E90E53Cf14eb0",
@@ -25,9 +25,9 @@ const quantile = (sorted, q) => {
25
25
  const quantileBN = (sorted, q) => {
26
26
  const pos = (sorted.length - 1) * q;
27
27
  const base = Math.floor(pos);
28
-
28
+
29
29
  let sum = BigNumber.from("0");
30
- for (let i = 0; i < base; i++)
30
+ for (let i = 0; i < base; i++)
31
31
  sum = BigNumber.from(sum).add(BigNumber.from(sorted[i]));
32
32
 
33
33
  return sum.toString();
@@ -212,35 +212,54 @@ export const airdrop = (ethers: typeof Ethers, ethSnapshotBlock) => {
212
212
  };
213
213
 
214
214
  export const airdropRecover = (ethers: typeof Ethers) => {
215
-
216
215
  const ZERO = ethers.BigNumber.from("0");
217
216
 
218
- const getHoldersInformation = async (newAddresses = {}, newIsContracts = {}) => {
217
+ const getHoldersInformation = async (
218
+ newAddresses = {},
219
+ newIsContracts = {}
220
+ ) => {
219
221
  const provider = new ethers.providers.InfuraProvider();
220
222
 
221
- const eventsABI = [
222
- "event TokenPurchased(address indexed caller,address indexed inputToken,uint256 inputAmount,uint256 actualReturn,address indexed receiverAddress)",
223
- "event TokenSold(address indexed caller,address indexed outputToken,uint256 gdAmount,uint256 contributionAmount,uint256 actualReturn,address indexed receiverAddress)"
224
- ];
223
+ let newReserve = await ethers.getContractAt(
224
+ "GoodReserveCDai",
225
+ "0x6C35677206ae7FF1bf753877649cF57cC30D1c42"
226
+ );
227
+
228
+ let recoveredReserve = await ethers.getContractAt(
229
+ "GoodReserveCDai",
230
+ "0xa150a825d425B36329D8294eeF8bD0fE68f8F6E0"
231
+ );
225
232
 
226
- let newReserve = await ethers.getContractAt(eventsABI, "0x6C35677206ae7FF1bf753877649cF57cC30D1c42");
227
- let exchangeHelper = await ethers.getContractAt(eventsABI, "0x0a8c6bB832801454F6CC21761D0A293Caa003296");
233
+ // let exchangeHelper = await ethers.getContractAt(
234
+ // eventsABI,
235
+ // "0x0a8c6bB832801454F6CC21761D0A293Caa003296"
236
+ // );
228
237
 
229
- exchangeHelper = exchangeHelper.connect(provider);
238
+ // exchangeHelper = exchangeHelper.connect(provider);
230
239
  newReserve = newReserve.connect(provider);
231
240
 
232
241
  const step = 100000;
233
242
  const START_BLOCK = 13683748; // Reserve was created
234
- const END_BLOCK = 14296271; // Following reserve created
243
+ // const END_BLOCK = 14296271; // Following reserve created
244
+ const END_BLOCK = await ethers.provider.getBlockNumber();
235
245
  const blocks = range(START_BLOCK, END_BLOCK, step);
236
246
 
237
- const reserveTokenPurchasedFilter = newReserve.filters.TokenPurchased();
238
- const reserveTokenSoldFilter = newReserve.filters.TokenSold();
247
+ const reserveTokenPurchasedFilter = newReserve.filters.Transfer(
248
+ ethers.constants.AddressZero
249
+ );
250
+ const reserveTokenSoldFilter = newReserve.filters.Transfer(
251
+ undefined,
252
+ ethers.constants.AddressZero
253
+ );
239
254
 
240
- const exchangeHelperTokenPurchasedFilter = exchangeHelper.filters.TokenPurchased();
241
- const exchangeHelperTokenSoldFilter = exchangeHelper.filters.TokenSold();
255
+ // const exchangeHelperTokenPurchasedFilter = exchangeHelper.filters.TokenPurchased();
256
+ // const exchangeHelperTokenSoldFilter = exchangeHelper.filters.TokenSold();
242
257
 
243
- const populateListOfAddressesAndBalances = async (contractInstance, purchaseFilter, soldFilter) => {
258
+ const populateListOfAddressesAndBalances = async (
259
+ contractInstance,
260
+ purchaseFilter,
261
+ soldFilter
262
+ ) => {
244
263
  for (let blockChunk of chunk(blocks, 10)) {
245
264
  // Get the filter (the second null could be omitted)
246
265
  const processedChunks = blockChunk.map(async bc => {
@@ -256,7 +275,7 @@ export const airdropRecover = (ethers: typeof Ethers) => {
256
275
  );
257
276
  });
258
277
 
259
- // console.log({purchaseEvents});
278
+ // console.log({ purchaseEvents });
260
279
 
261
280
  const soldEvents = await contractInstance
262
281
  .queryFilter(soldFilter, bc, Math.min(bc + step - 1, END_BLOCK))
@@ -276,28 +295,27 @@ export const airdropRecover = (ethers: typeof Ethers) => {
276
295
  // );
277
296
 
278
297
  const isContract = async (log, role) => {
279
- const possibleCodeStateOfAddress = await contractInstance.provider.getCode(log.args[role])
298
+ const possibleCodeStateOfAddress = await contractInstance.provider
299
+ .getCode(log.args[role])
280
300
  .catch(e => "0x");
281
301
  return possibleCodeStateOfAddress !== "0x";
282
302
  };
283
303
 
284
304
  // Print out all the values:
285
305
  const purchasedEventsMapped = purchaseEvents.map(async log => {
286
- let balance = newAddresses[log.args.receiverAddress] || ZERO;
287
- // console.log({balance});
306
+ let balance = newAddresses[log.args.to] || ZERO;
307
+ // console.log(log.blockNumber);
288
308
  // console.log(`actualReturn: ${log.args.actualReturn.toString()}`);
289
- newAddresses[log.args.receiverAddress] =
290
- balance.add(log.args.actualReturn);
291
- newIsContracts[log.args.receiverAddress] = await isContract(
292
- log, "receiverAddress"
293
- );
309
+ newAddresses[log.args.to] =
310
+ log.blockNumber === 14358516 //airdrop reimburse
311
+ ? balance.sub(log.args.value)
312
+ : balance.add(log.args.value);
313
+ newIsContracts[log.args.to] = await isContract(log, "to");
294
314
  });
295
315
  const soldEventsMapped = soldEvents.map(async log => {
296
- let balance = newAddresses[log.args.caller] || ZERO;
297
- newAddresses[log.args.caller] = balance.sub(log.args.gdAmount);
298
- newIsContracts[log.args.caller] = await isContract(
299
- log, "caller"
300
- );
316
+ let balance = newAddresses[log.args.from] || ZERO;
317
+ newAddresses[log.args.from] = balance.sub(log.args.value);
318
+ newIsContracts[log.args.from] = await isContract(log, "from");
301
319
  });
302
320
 
303
321
  await Promise.all([...purchasedEventsMapped, ...soldEventsMapped]);
@@ -306,8 +324,17 @@ export const airdropRecover = (ethers: typeof Ethers) => {
306
324
  }
307
325
  };
308
326
 
309
- await populateListOfAddressesAndBalances(newReserve, reserveTokenPurchasedFilter, reserveTokenSoldFilter);
310
- await populateListOfAddressesAndBalances(exchangeHelper, exchangeHelperTokenPurchasedFilter, exchangeHelperTokenSoldFilter);
327
+ await populateListOfAddressesAndBalances(
328
+ newReserve,
329
+ reserveTokenPurchasedFilter,
330
+ reserveTokenSoldFilter
331
+ );
332
+ await populateListOfAddressesAndBalances(
333
+ recoveredReserve,
334
+ reserveTokenPurchasedFilter,
335
+ reserveTokenSoldFilter
336
+ );
337
+ // await populateListOfAddressesAndBalances(exchangeHelper, exchangeHelperTokenPurchasedFilter, exchangeHelperTokenSoldFilter);
311
338
 
312
339
  // console.log({ newAddresses, newIsContracts });
313
340
  return { newAddresses, newIsContracts };
@@ -317,25 +344,30 @@ export const airdropRecover = (ethers: typeof Ethers) => {
317
344
  const { addressesCombined } = JSON.parse(
318
345
  fs.readFileSync("airdrop/buyBalancesCombined.json").toString()
319
346
  );
320
-
321
- let toTree: Array<[string, BigNumber]> = Object.entries(addressesCombined).map(
322
- ([addr, gdx]) => {
323
- return [addr, gdx as BigNumber];
324
- }
325
- );
326
-
347
+
348
+ let toTree: Array<[string, BigNumber]> = Object.entries(
349
+ addressesCombined
350
+ ).map(([addr, gdx]) => {
351
+ return [addr, gdx as BigNumber];
352
+ });
353
+
327
354
  // console.log(`Before sorting`);
328
- // toTree.forEach((a,_) => { console.log(`${a[0].toString()}:${ethers.BigNumber.from(a[1]).toString()}\n`)});
329
-
330
- toTree.sort((a, b) => BigNumber.from(b[1]).gt(a[1]) ? 0 : -1 );
355
+ // toTree.forEach((a,_) => { console.log(`${a[0].toString()}:${ethers.BigNumber.from(a[1]).toString()}\n`)});
356
+
357
+ toTree.sort((a, b) => (BigNumber.from(b[1]).gt(a[1]) ? 0 : -1));
331
358
 
332
359
  // console.log(`After sorting`);
333
- // toTree.forEach((a,_) => { console.log(`${a[0].toString()}:${ethers.BigNumber.from(a[1]).toString()}\n`)});
334
-
360
+ // toTree.forEach((a,_) => { console.log(`${a[0].toString()}:${ethers.BigNumber.from(a[1]).toString()}\n`)});
361
+
335
362
  let totalGDX = ZERO;
336
- toTree.forEach((a,_) => totalGDX = totalGDX.add(a[1]))
363
+ toTree.forEach((a, _) => (totalGDX = totalGDX.add(a[1])));
337
364
  console.log({
338
- toTree: toTree.forEach((a,_) => console.log({address: a[0].toString(), balance: BigNumber.from(a[1]).toString()})),
365
+ toTree: toTree.forEach((a, _) =>
366
+ console.log({
367
+ address: a[0].toString(),
368
+ balance: BigNumber.from(a[1]).toString()
369
+ })
370
+ ),
339
371
  numberOfAccounts: toTree.length,
340
372
  TotalGDX: totalGDX.toString()
341
373
  });
@@ -385,38 +417,63 @@ export const airdropRecover = (ethers: typeof Ethers) => {
385
417
  const gdxAirdropData = JSON.parse(
386
418
  fs.readFileSync("airdrop/gdxairdrop.json").toString()
387
419
  );
388
- const addressesCombined = {}
420
+ const addressesCombined = {};
389
421
  for (const [address, balance] of Object.entries(gdxAirdropData.treeData)) {
390
- addressesCombined[address] = BigNumber.from(balance['gdx']);
422
+ addressesCombined[address] = BigNumber.from(balance["gdx"]).toString();
391
423
  }
392
424
 
393
425
  // get new holders info and turn into array
394
- const { newAddresses, } = await getHoldersInformation();
395
-
396
- let newAddressesArray: Array<[string, BigNumber]> = Object.entries(newAddresses).map(
397
- ([addr, gdx]) => {
398
- return [addr, gdx as BigNumber];
399
- }
400
- );
426
+ const { newAddresses } = await getHoldersInformation();
401
427
 
428
+ let newAddressesArray: Array<[string, BigNumber]> = Object.entries(
429
+ newAddresses
430
+ ).map(([addr, gdx]) => {
431
+ return [addr, gdx as BigNumber];
432
+ });
402
433
 
403
- // Unite previous airdrop with current information
434
+ // Unite previous airdrop with current information
404
435
  for (const newAddressEntry of newAddressesArray) {
405
436
  const address = newAddressEntry[0];
406
437
  const addition = newAddressEntry[1];
407
-
408
- if (addition<=ZERO)
409
- continue;
438
+
439
+ if (addition <= ZERO) continue;
410
440
 
411
441
  // console.log({address})
412
442
  // console.log({before: BigNumber.from(addressesCombined[address] || "0").toString() })
413
443
  // console.log({addition: addition.toString()})
414
- addressesCombined[address] = ethers.BigNumber.from(addressesCombined[address] || 0).add(addition.toString()).toString();
444
+ addressesCombined[address] = ethers.BigNumber.from(
445
+ addressesCombined[address] || 0
446
+ )
447
+ .add(addition.toString())
448
+ .toString();
415
449
  // console.log({total: addressesCombined[address].toString()})
416
450
  // console.log(`\n`);
417
451
  }
418
-
419
- fs.writeFileSync("airdrop/buyBalancesCombined.json", JSON.stringify({ addressesCombined }));
452
+
453
+ let newReserve = await ethers.getContractAt(
454
+ "GoodReserveCDai",
455
+ "0xa150a825d425B36329D8294eeF8bD0fE68f8F6E0"
456
+ );
457
+
458
+ const ps = Object.entries(addressesCombined).map(async ([addr, amount]) => {
459
+ console.log(addr, amount);
460
+ const balance = await newReserve.balanceOf(addr);
461
+ const diff = balance.sub(amount);
462
+ if (diff.lt(0)) {
463
+ console.log({
464
+ addr,
465
+ balance: balance.toString(),
466
+ amount,
467
+ diff: diff.toString()
468
+ });
469
+ }
470
+ });
471
+
472
+ await Promise.all(ps);
473
+ fs.writeFileSync(
474
+ "airdrop/buyBalancesCombined.json",
475
+ JSON.stringify({ addressesCombined })
476
+ );
420
477
  };
421
478
 
422
479
  return { buildMerkleTree, addCalculationsToPreviousData };
@@ -0,0 +1,53 @@
1
+ import { range, chunk } from "lodash";
2
+ import fs from "fs";
3
+ import stakingContracts from "../../releases/deployment.json";
4
+ import { ethers as Ethers } from "hardhat";
5
+ import { BigNumber } from "ethereum-waffle/node_modules/ethers";
6
+
7
+ const ZERO = BigNumber.from("0");
8
+
9
+ export const sumStakersGdRewards = (ethers: typeof Ethers) => {
10
+
11
+ const getStakersGdRewards = async (stakersToGdRewards = {}) => {
12
+ const provider = new ethers.providers.InfuraProvider();
13
+
14
+ let goodFundManager = await ethers.getContractAt("GoodFundManager",stakingContracts["production-mainnet-bug"].GoodFundManager);
15
+ goodFundManager = goodFundManager.connect(provider);
16
+ const filter = goodFundManager.filters.StakingRewardMinted();
17
+
18
+ const step = 100000;
19
+ const ETH_START_BLOCK = 14291923;
20
+ const ETH_END_BLOCK = await provider.getBlockNumber();
21
+ const blocks = range(ETH_START_BLOCK, ETH_END_BLOCK, step);
22
+
23
+ for (let blockChunk of chunk(blocks, 10)) {
24
+ const processedChunks = blockChunk.map(async bc => {
25
+ const stakingRewardsEvents = await goodFundManager
26
+ .queryFilter(filter, bc, Math.min(bc + step - 1, ETH_END_BLOCK))
27
+ .catch(e => {
28
+ console.log("block transfer logs failed retrying...", bc);
29
+ return goodFundManager.queryFilter(
30
+ filter, bc, Math.min(bc + step - 1, ETH_END_BLOCK));
31
+ });
32
+
33
+ const stakingRewardsEventsMapped = stakingRewardsEvents.map(async log => {
34
+ const initBalance = stakersToGdRewards[log.args.staker] || ZERO;
35
+ stakersToGdRewards[log.args.staker] = initBalance.add(log.args.gdReward);
36
+ // console.log(`TransactionHash:\t${log.transactionHash}`);
37
+ // console.log(`Staking contract:\t${log.args.stakingContract}`);
38
+ // console.log(`Previous Balance:\t${initBalance.toString()} for address ${log.args.staker}`);
39
+ // console.log(`Addition:\t\t${log.args.gdReward.toString()} for address ${log.args.staker}`);
40
+ // console.log(`New Balance:\t\t${stakersToGdRewards[log.args.staker].toString()} for address ${log.args.staker}\n`);
41
+ });
42
+ await Promise.all([...stakingRewardsEventsMapped]);
43
+ });
44
+ await Promise.all(processedChunks);
45
+ }
46
+
47
+ console.log(`All stakers minted rewards:\n`);
48
+ Object.entries(stakersToGdRewards).forEach(a => { console.log(`${a[0].toString()}:${BigNumber.from(a[1]).toString()}\n`)});
49
+ // fs.writeFileSync("scripts/staking/stakersToGdRewards.json", JSON.stringify(stakersToGdRewards))
50
+ };
51
+
52
+ return { getStakersGdRewards};
53
+ }