@gooddollar/goodprotocol 1.0.24 → 1.0.26
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/artifacts/abis/FuseFaucet.min.json +1 -0
- package/artifacts/abis/FuseStakingV3.min.json +1 -0
- package/artifacts/abis/IConsensus.min.json +1 -0
- package/artifacts/abis/InvitesV1.min.json +1 -0
- package/artifacts/abis/PegSwap.min.json +1 -0
- package/artifacts/contracts/DAOStackInterfaces.sol/Avatar.dbg.json +1 -1
- package/artifacts/contracts/DAOStackInterfaces.sol/Controller.dbg.json +1 -1
- package/artifacts/contracts/DAOStackInterfaces.sol/GlobalConstraintInterface.dbg.json +1 -1
- package/artifacts/contracts/DAOStackInterfaces.sol/IntVoteInterface.dbg.json +1 -1
- package/artifacts/contracts/DAOStackInterfaces.sol/ReputationInterface.dbg.json +1 -1
- package/artifacts/contracts/DAOStackInterfaces.sol/SchemeRegistrar.dbg.json +1 -1
- package/artifacts/contracts/Interfaces.sol/AggregatorV3Interface.dbg.json +1 -1
- package/artifacts/contracts/Interfaces.sol/ERC20.dbg.json +1 -1
- package/artifacts/contracts/Interfaces.sol/IAaveIncentivesController.dbg.json +1 -1
- package/artifacts/contracts/Interfaces.sol/IAdminWallet.dbg.json +1 -1
- package/artifacts/contracts/Interfaces.sol/IDonationStaking.dbg.json +1 -1
- package/artifacts/contracts/Interfaces.sol/IERC2917.dbg.json +1 -1
- package/artifacts/contracts/Interfaces.sol/IFirstClaimPool.dbg.json +1 -1
- package/artifacts/contracts/Interfaces.sol/IGoodDollar.dbg.json +1 -1
- package/artifacts/contracts/Interfaces.sol/IGoodStaking.dbg.json +1 -1
- package/artifacts/contracts/Interfaces.sol/IHasRouter.dbg.json +1 -1
- package/artifacts/contracts/Interfaces.sol/IIdentity.dbg.json +1 -1
- package/artifacts/contracts/Interfaces.sol/ILendingPool.dbg.json +1 -1
- package/artifacts/contracts/Interfaces.sol/INameService.dbg.json +1 -1
- package/artifacts/contracts/Interfaces.sol/IUBIScheme.dbg.json +1 -1
- package/artifacts/contracts/Interfaces.sol/ProxyAdmin.dbg.json +1 -1
- package/artifacts/contracts/Interfaces.sol/Reserve.dbg.json +1 -1
- package/artifacts/contracts/Interfaces.sol/Staking.dbg.json +1 -1
- package/artifacts/contracts/Interfaces.sol/Uniswap.dbg.json +1 -1
- package/artifacts/contracts/Interfaces.sol/UniswapFactory.dbg.json +1 -1
- package/artifacts/contracts/Interfaces.sol/UniswapPair.dbg.json +1 -1
- package/artifacts/contracts/Interfaces.sol/cERC20.dbg.json +1 -1
- package/artifacts/contracts/fuseFaucet/FuseFaucet.sol/FuseFaucet.dbg.json +4 -0
- package/artifacts/contracts/fuseFaucet/FuseFaucet.sol/FuseFaucet.json +325 -0
- package/artifacts/contracts/governance/ClaimersDistribution.sol/ClaimersDistribution.dbg.json +1 -1
- package/artifacts/contracts/governance/CompoundVotingMachine.sol/CompoundVotingMachine.dbg.json +1 -1
- package/artifacts/contracts/governance/GReputation.sol/GReputation.dbg.json +1 -1
- package/artifacts/contracts/governance/GovernanceStaking.sol/GovernanceStaking.dbg.json +1 -1
- package/artifacts/contracts/governance/MultiBaseGovernanceShareField.sol/MultiBaseGovernanceShareField.dbg.json +1 -1
- package/artifacts/contracts/governance/Reputation.sol/Reputation.dbg.json +1 -1
- package/artifacts/contracts/governance/StakersDistribution.sol/StakersDistribution.dbg.json +1 -1
- package/artifacts/contracts/invite/InvitesV1.sol/InvitesV1.dbg.json +4 -0
- package/artifacts/contracts/invite/InvitesV1.sol/InvitesV1.json +492 -0
- package/artifacts/contracts/mocks/AaveMock.sol/AaveMock.dbg.json +1 -1
- package/artifacts/contracts/mocks/DAIMock.sol/DAIMock.dbg.json +1 -1
- package/artifacts/contracts/mocks/DecimalsMock.sol/DecimalsMock.dbg.json +1 -1
- package/artifacts/contracts/mocks/GoodCompoundStakingTest.sol/GoodCompoundStakingTest.dbg.json +1 -1
- package/artifacts/contracts/mocks/GoodFundManagerTest.sol/GoodFundManagerTest.dbg.json +1 -1
- package/artifacts/contracts/mocks/IncentiveControllerMock.sol/IncentiveControllerMock.dbg.json +1 -1
- package/artifacts/contracts/mocks/LendingPoolMock.sol/LendingPoolMock.dbg.json +1 -1
- package/artifacts/contracts/mocks/OverMintTester.sol/OverMintTester.dbg.json +1 -1
- package/artifacts/contracts/mocks/OverMintTesterRegularStake.sol/OverMintTesterRegularStake.dbg.json +1 -1
- package/artifacts/contracts/mocks/SixteenDecimalsTokenMock.sol/SixteenDecimalsTokenMock.dbg.json +1 -1
- package/artifacts/contracts/mocks/SwapHelperTest.sol/SwapHelperTest.dbg.json +1 -1
- package/artifacts/contracts/mocks/TwentyDecimalsTokenMock.sol/TwentyDecimalsTokenMock.dbg.json +1 -1
- package/artifacts/contracts/mocks/UpgradableMocks.sol/UpgradableMock.dbg.json +1 -1
- package/artifacts/contracts/mocks/UpgradableMocks.sol/UpgradableMock2.dbg.json +1 -1
- package/artifacts/contracts/mocks/UpgradableMocks.sol/UpgradableMock3.dbg.json +1 -1
- package/artifacts/contracts/mocks/UpgradableMocks.sol/UpgradableMock4.dbg.json +1 -1
- package/artifacts/contracts/mocks/UsdcMock.sol/USDCMock.dbg.json +1 -1
- package/artifacts/contracts/mocks/cBATMock.sol/cBATMock.dbg.json +1 -1
- package/artifacts/contracts/mocks/cDAILowWorthMock.sol/cDAILowWorthMock.dbg.json +1 -1
- package/artifacts/contracts/mocks/cDAIMock.sol/cDAIMock.dbg.json +1 -1
- package/artifacts/contracts/mocks/cDAINonMintableMock.sol/cDAINonMintableMock.dbg.json +1 -1
- package/artifacts/contracts/mocks/cDecimalsMock.sol/cDecimalsMock.dbg.json +1 -1
- package/artifacts/contracts/mocks/cSDTMock.sol/cSDTMock.dbg.json +1 -1
- package/artifacts/contracts/mocks/cUSDCMock.sol/cUSDCMock.dbg.json +1 -1
- package/artifacts/contracts/reserve/ExchangeHelper.sol/ExchangeHelper.dbg.json +1 -1
- package/artifacts/contracts/reserve/GoodMarketMaker.sol/GoodMarketMaker.dbg.json +1 -1
- package/artifacts/contracts/reserve/GoodReserveCDai.sol/ContributionCalc.dbg.json +1 -1
- package/artifacts/contracts/reserve/GoodReserveCDai.sol/GoodReserveCDai.dbg.json +1 -1
- package/artifacts/contracts/staking/BaseShareField.sol/BaseShareField.dbg.json +1 -1
- package/artifacts/contracts/staking/BaseShareFieldV2.sol/BaseShareFieldV2.dbg.json +1 -1
- package/artifacts/contracts/staking/DonationsStaking.sol/DonationsStaking.dbg.json +1 -1
- package/artifacts/contracts/staking/FuseStakingV3.sol/FuseStakingV3.dbg.json +4 -0
- package/artifacts/contracts/staking/FuseStakingV3.sol/FuseStakingV3.json +733 -0
- package/artifacts/contracts/staking/FuseStakingV3.sol/IConsensus.dbg.json +4 -0
- package/artifacts/contracts/staking/FuseStakingV3.sol/IConsensus.json +104 -0
- package/artifacts/contracts/staking/FuseStakingV3.sol/PegSwap.dbg.json +4 -0
- package/artifacts/contracts/staking/FuseStakingV3.sol/PegSwap.json +34 -0
- package/artifacts/contracts/staking/GoodFundManager.sol/GoodFundManager.dbg.json +1 -1
- package/artifacts/contracts/staking/SimpleStaking.sol/SimpleStaking.dbg.json +1 -1
- package/artifacts/contracts/staking/SimpleStakingV2.sol/SimpleStakingV2.dbg.json +1 -1
- package/artifacts/contracts/staking/UniswapV2SwapHelper.sol/UniswapV2SwapHelper.dbg.json +1 -1
- package/artifacts/contracts/staking/aave/AaveStakingFactory.sol/AaveStakingFactory.dbg.json +1 -1
- package/artifacts/contracts/staking/aave/GoodAaveStaking.sol/GoodAaveStaking.dbg.json +1 -1
- package/artifacts/contracts/staking/aave/GoodAaveStakingV2.sol/GoodAaveStakingV2.dbg.json +1 -1
- package/artifacts/contracts/staking/compound/CompoundStakingFactory.sol/CompoundStakingFactory.dbg.json +1 -1
- package/artifacts/contracts/staking/compound/GoodCompoundStaking.sol/GoodCompoundStaking.dbg.json +1 -1
- package/artifacts/contracts/staking/compound/GoodCompoundStakingV2.sol/GoodCompoundStakingV2.dbg.json +1 -1
- package/artifacts/contracts/ubi/UBIScheme.sol/UBIScheme.dbg.json +1 -1
- package/artifacts/contracts/utils/BancorFormula.sol/BancorFormula.dbg.json +1 -1
- package/artifacts/contracts/utils/BulkProof.sol/BulkProof.dbg.json +1 -1
- package/artifacts/contracts/utils/DAOContract.sol/DAOContract.dbg.json +1 -1
- package/artifacts/contracts/utils/DAOUpgradeableContract.sol/DAOUpgradeableContract.dbg.json +1 -1
- package/artifacts/contracts/utils/DSMath.sol/DSMath.dbg.json +1 -1
- package/artifacts/contracts/utils/DataTypes.sol/DataTypes.dbg.json +1 -1
- package/artifacts/contracts/utils/NameService.sol/NameService.dbg.json +1 -1
- package/artifacts/contracts/utils/ProtocolUpgrade.sol/OldMarketMaker.dbg.json +1 -1
- package/artifacts/contracts/utils/ProtocolUpgrade.sol/ProtocolUpgrade.dbg.json +1 -1
- package/artifacts/contracts/utils/ProtocolUpgradeFuse.sol/ProtocolUpgradeFuse.dbg.json +1 -1
- package/artifacts/contracts/utils/ProtocolUpgradeFuseRecover.sol/ProtocolUpgradeFuseRecover.dbg.json +1 -1
- package/artifacts/contracts/utils/ProtocolUpgradeRecover.sol/ProtocolUpgradeRecover.dbg.json +1 -1
- package/artifacts/contracts/utils/ReputationTestHelper.sol/ReputationTestHelper.dbg.json +1 -1
- package/contracts/fuseFaucet/FuseFaucet.sol +172 -0
- package/contracts/invite/InvitesV1.sol +316 -0
- package/contracts/staking/FuseStakingV3.sol +641 -0
- package/hardhat.config.ts +7 -0
- package/package.json +5 -5
- package/scripts/misc/faucetStats.ts +103 -0
- package/scripts/upgradeToV2/upgradeToV2.ts +22 -7
- package/test/FuseFaucet.test.ts +168 -0
- package/test/InvitesV1.test.ts +354 -0
- package/test/staking/FuseStaking.test.ts +152 -0
- package/types/FuseFaucet.ts +498 -0
- package/types/FuseStakingV3.ts +1234 -0
- package/types/IConsensus.ts +225 -0
- package/types/InvitesV1.ts +797 -0
- package/types/OwnableUpgradeable.ts +166 -0
- package/types/PegSwap.ts +112 -0
- package/types/factories/FuseFaucet__factory.ts +373 -0
- package/types/factories/FuseStakingV3__factory.ts +781 -0
- package/types/factories/IConsensus__factory.ts +116 -0
- package/types/factories/InvitesV1__factory.ts +540 -0
- package/types/factories/OwnableUpgradeable__factory.ts +78 -0
- package/types/factories/PegSwap__factory.ts +46 -0
- package/types/hardhat.d.ts +54 -0
- package/types/index.ts +12 -0
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import { range, sortBy, toPairs } from "lodash";
|
|
2
|
+
import fetch from "node-fetch";
|
|
3
|
+
import PromisePool from "async-promise-pool";
|
|
4
|
+
import fs from "fs";
|
|
5
|
+
import { ethers } from "hardhat";
|
|
6
|
+
import { start } from "repl";
|
|
7
|
+
import { JsonRpcProvider } from "@ethersproject/providers";
|
|
8
|
+
import { off } from "process";
|
|
9
|
+
|
|
10
|
+
function arrayToCsv(data) {
|
|
11
|
+
return data
|
|
12
|
+
.map(
|
|
13
|
+
row =>
|
|
14
|
+
row
|
|
15
|
+
.map(String) // convert every value to String
|
|
16
|
+
.map(v => v.replaceAll('"', '""')) // escape double colons
|
|
17
|
+
.map(v => `"${v}"`) // quote it
|
|
18
|
+
.join(",") // comma-separated
|
|
19
|
+
)
|
|
20
|
+
.join("\r\n"); // rows starting on new lines
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const main = async () => {
|
|
24
|
+
const archive = new JsonRpcProvider("https://explorer-node.fuse.io");
|
|
25
|
+
const blockStep = 10000;
|
|
26
|
+
const pool = new PromisePool({ concurrency: 10 });
|
|
27
|
+
|
|
28
|
+
let faucet = await ethers.getContractAt(
|
|
29
|
+
["event WalletTopped(address indexed user, uint256 amount)"],
|
|
30
|
+
"0x01ab5966C1d742Ae0CFF7f14cC0F4D85156e83d9"
|
|
31
|
+
);
|
|
32
|
+
const endBlock = Number(await ethers.provider.getBlockNumber());
|
|
33
|
+
const daysBack = 30;
|
|
34
|
+
const dayBlocks = 12 * 60 * 24;
|
|
35
|
+
const startBlock = endBlock - dayBlocks * daysBack;
|
|
36
|
+
const days = range(startBlock, endBlock, dayBlocks);
|
|
37
|
+
const dailyBalance = [];
|
|
38
|
+
for (let day of days) {
|
|
39
|
+
dailyBalance.push(
|
|
40
|
+
(
|
|
41
|
+
await archive.getBalance(
|
|
42
|
+
"0x01ab5966C1d742Ae0CFF7f14cC0F4D85156e83d9",
|
|
43
|
+
day
|
|
44
|
+
)
|
|
45
|
+
)
|
|
46
|
+
.div(1e10)
|
|
47
|
+
.toNumber() / 1e8
|
|
48
|
+
);
|
|
49
|
+
}
|
|
50
|
+
let curBlock = startBlock;
|
|
51
|
+
|
|
52
|
+
const toppingsByAddress = {};
|
|
53
|
+
const toppingsByAmount = {};
|
|
54
|
+
let totalToppings = 0;
|
|
55
|
+
let totalAmount = 0;
|
|
56
|
+
console.log({ dailyBalance });
|
|
57
|
+
console.log({ startBlock, endBlock });
|
|
58
|
+
while (curBlock <= endBlock) {
|
|
59
|
+
const fromBlock = curBlock;
|
|
60
|
+
const toBlock = Math.min(fromBlock + blockStep, endBlock);
|
|
61
|
+
pool.add(async () => {
|
|
62
|
+
const f = faucet.filters.WalletTopped();
|
|
63
|
+
const events = await faucet
|
|
64
|
+
.queryFilter(f, fromBlock, toBlock)
|
|
65
|
+
.catch(e => {
|
|
66
|
+
console.log("failed", { fromBlock, toBlock });
|
|
67
|
+
return [];
|
|
68
|
+
});
|
|
69
|
+
events.forEach(e => {
|
|
70
|
+
totalToppings += 1;
|
|
71
|
+
totalAmount += Number(e.args.amount);
|
|
72
|
+
toppingsByAddress[e.args.user] =
|
|
73
|
+
(toppingsByAddress[e.args.user] || 0) + 1;
|
|
74
|
+
toppingsByAmount[e.args.amount] =
|
|
75
|
+
(toppingsByAmount[e.args.amount] || 0) + 1;
|
|
76
|
+
});
|
|
77
|
+
console.log("fetched events", {
|
|
78
|
+
fromBlock,
|
|
79
|
+
toBlock,
|
|
80
|
+
events: events.length
|
|
81
|
+
});
|
|
82
|
+
});
|
|
83
|
+
curBlock += blockStep;
|
|
84
|
+
}
|
|
85
|
+
await pool.all();
|
|
86
|
+
|
|
87
|
+
const topToppers = sortBy(toPairs(toppingsByAddress), "1").reverse();
|
|
88
|
+
const topAmounts = sortBy(toPairs(toppingsByAmount), "1").reverse();
|
|
89
|
+
const totalWallets = topToppers.length;
|
|
90
|
+
|
|
91
|
+
const avgToppingsPerWallet = totalToppings / totalWallets;
|
|
92
|
+
const avgToppingAmount = totalAmount / totalToppings;
|
|
93
|
+
|
|
94
|
+
fs.writeFileSync("topToppers.csv", arrayToCsv(topToppers));
|
|
95
|
+
fs.writeFileSync("topAmounts.csv", arrayToCsv(topAmounts));
|
|
96
|
+
console.log({
|
|
97
|
+
totalAmount,
|
|
98
|
+
totalToppings,
|
|
99
|
+
avgToppingsPerWallet,
|
|
100
|
+
avgToppingAmount
|
|
101
|
+
});
|
|
102
|
+
};
|
|
103
|
+
main().catch(e => console.log(e));
|
|
@@ -88,8 +88,8 @@ export const main = async (
|
|
|
88
88
|
};
|
|
89
89
|
}
|
|
90
90
|
|
|
91
|
-
const
|
|
92
|
-
const isTest = network.name === "hardhat" ||
|
|
91
|
+
const isDappTest = networkName.startsWith("dapptest");
|
|
92
|
+
const isTest = network.name === "hardhat" || isDappTest;
|
|
93
93
|
const isCoverage = process.env.CODE_COVERAGE;
|
|
94
94
|
const isDevelop = !isProduction;
|
|
95
95
|
const isMainnet = networkName.includes("mainnet");
|
|
@@ -99,7 +99,7 @@ export const main = async (
|
|
|
99
99
|
};
|
|
100
100
|
console.log(`networkName ${networkName}`, {
|
|
101
101
|
isTest,
|
|
102
|
-
|
|
102
|
+
isDappTest,
|
|
103
103
|
isCoverage,
|
|
104
104
|
isMainnet,
|
|
105
105
|
isDevelop
|
|
@@ -843,14 +843,30 @@ export const main = async (
|
|
|
843
843
|
// Promise.resolve(["0x9999c40c8b88c740076b15d2e708db6a7a071b53", 13888])
|
|
844
844
|
// ];
|
|
845
845
|
let deployed;
|
|
846
|
-
if (!isRopsten || isTest) {
|
|
846
|
+
if (!isDappTest && (!isRopsten || isTest)) {
|
|
847
847
|
const aaveps = aaveTokens.map(async token => {
|
|
848
848
|
let rewardsPerBlock = (protocolSettings.staking.rewardsPerBlock / 2) //aave gets half of the rewards
|
|
849
849
|
.toFixed(0);
|
|
850
|
-
console.log("deployStakingContracts", {
|
|
850
|
+
console.log("deployStakingContracts aave", {
|
|
851
851
|
token,
|
|
852
852
|
settings: protocolSettings.staking,
|
|
853
|
-
rewardsPerBlock
|
|
853
|
+
rewardsPerBlock,
|
|
854
|
+
params: [
|
|
855
|
+
token.address,
|
|
856
|
+
get(protocolSettings, "aave.lendingPool", dao.AaveLendingPool),
|
|
857
|
+
release.NameService,
|
|
858
|
+
protocolSettings.staking.fullRewardsThreshold, //blocks before switching for 0.5x rewards to 1x multiplier
|
|
859
|
+
token.usdOracle,
|
|
860
|
+
|
|
861
|
+
get(
|
|
862
|
+
protocolSettings,
|
|
863
|
+
"aave.incentiveController",
|
|
864
|
+
dao.AaveIncentiveController
|
|
865
|
+
),
|
|
866
|
+
token.aaveUsdOracle,
|
|
867
|
+
token.swapPath,
|
|
868
|
+
GAS_SETTINGS
|
|
869
|
+
]
|
|
854
870
|
});
|
|
855
871
|
const tx = await (
|
|
856
872
|
await aavefactory[
|
|
@@ -861,7 +877,6 @@ export const main = async (
|
|
|
861
877
|
release.NameService,
|
|
862
878
|
protocolSettings.staking.fullRewardsThreshold, //blocks before switching for 0.5x rewards to 1x multiplier
|
|
863
879
|
token.usdOracle,
|
|
864
|
-
|
|
865
880
|
get(
|
|
866
881
|
protocolSettings,
|
|
867
882
|
"aave.incentiveController",
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
import hre, { ethers, upgrades } from "hardhat";
|
|
2
|
+
import { expect } from "chai";
|
|
3
|
+
import { FuseFaucet, IGoodDollar, IIdentity } from "../types";
|
|
4
|
+
import { SignerWithAddress } from "@nomiclabs/hardhat-ethers/dist/src/signer-with-address";
|
|
5
|
+
import { createDAO } from "./helpers";
|
|
6
|
+
|
|
7
|
+
const BN = ethers.BigNumber;
|
|
8
|
+
|
|
9
|
+
describe("FuseFaucet", () => {
|
|
10
|
+
let faucet: FuseFaucet, founder: SignerWithAddress;
|
|
11
|
+
let user1 = ethers.Wallet.createRandom().connect(ethers.provider);
|
|
12
|
+
let user2 = ethers.Wallet.createRandom().connect(ethers.provider);
|
|
13
|
+
let signers;
|
|
14
|
+
|
|
15
|
+
let avatar, gd: IGoodDollar, Controller, id: IIdentity;
|
|
16
|
+
|
|
17
|
+
before(async () => {
|
|
18
|
+
[founder, ...signers] = await ethers.getSigners();
|
|
19
|
+
|
|
20
|
+
const FuseFaucetF = await ethers.getContractFactory("FuseFaucet");
|
|
21
|
+
|
|
22
|
+
let {
|
|
23
|
+
daoCreator,
|
|
24
|
+
controller,
|
|
25
|
+
avatar: av,
|
|
26
|
+
gd: gooddollar,
|
|
27
|
+
identity
|
|
28
|
+
} = await createDAO();
|
|
29
|
+
|
|
30
|
+
Controller = controller;
|
|
31
|
+
avatar = av;
|
|
32
|
+
|
|
33
|
+
// await daoCreator.setSchemes(
|
|
34
|
+
// avatar,
|
|
35
|
+
// [identity],
|
|
36
|
+
// [ethers.constants.HashZero],
|
|
37
|
+
// ["0x0000001F"],
|
|
38
|
+
// ""
|
|
39
|
+
// );
|
|
40
|
+
|
|
41
|
+
faucet = (await upgrades.deployProxy(FuseFaucetF, [identity], {
|
|
42
|
+
kind: "transparent"
|
|
43
|
+
})) as FuseFaucet;
|
|
44
|
+
|
|
45
|
+
gd = (await ethers.getContractAt(
|
|
46
|
+
"IGoodDollar",
|
|
47
|
+
gooddollar,
|
|
48
|
+
founder
|
|
49
|
+
)) as IGoodDollar;
|
|
50
|
+
id = (await ethers.getContractAt(
|
|
51
|
+
"IIdentity",
|
|
52
|
+
identity,
|
|
53
|
+
founder
|
|
54
|
+
)) as IIdentity;
|
|
55
|
+
|
|
56
|
+
await founder.sendTransaction({
|
|
57
|
+
value: ethers.utils.parseEther("1"),
|
|
58
|
+
to: faucet.address
|
|
59
|
+
});
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
it("should have balance", async () => {
|
|
63
|
+
const balance = await ethers.provider.getBalance(faucet.address);
|
|
64
|
+
expect(balance).to.equal(ethers.utils.parseEther("1"));
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
it("should let new user top once", async () => {
|
|
68
|
+
expect(await faucet.canTop(user1.address)).to.true;
|
|
69
|
+
const tx = await (await faucet.topWallet(user1.address)).wait();
|
|
70
|
+
const balance = await ethers.provider.getBalance(user1.address);
|
|
71
|
+
expect(balance).to.equal(await faucet.toppingAmount());
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
it("should not let new user top more than once", async () => {
|
|
75
|
+
await user1.sendTransaction({
|
|
76
|
+
to: ethers.constants.AddressZero,
|
|
77
|
+
value: ethers.utils.parseUnits("400000", "gwei")
|
|
78
|
+
});
|
|
79
|
+
expect(await faucet.canTop(user1.address)).to.false;
|
|
80
|
+
await expect(faucet.topWallet(user1.address)).to.revertedWith(
|
|
81
|
+
"User not whitelisted or not first time"
|
|
82
|
+
);
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
it("should not refund gas when reverted", async () => {
|
|
86
|
+
const balance = await ethers.provider.getBalance(founder.address);
|
|
87
|
+
const faucetBalance = await ethers.provider.getBalance(faucet.address);
|
|
88
|
+
expect(await faucet.canTop(user1.address)).to.false;
|
|
89
|
+
await expect(faucet.topWallet(user1.address)).to.revertedWith(
|
|
90
|
+
"User not whitelisted or not first time"
|
|
91
|
+
);
|
|
92
|
+
const balanceAfter = await ethers.provider.getBalance(founder.address);
|
|
93
|
+
const faucetBalanceAfter = await ethers.provider.getBalance(faucet.address);
|
|
94
|
+
expect(faucetBalanceAfter).to.eq(faucetBalance);
|
|
95
|
+
expect(balanceAfter).to.lt(balance);
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
it("should let user top again once identified", async () => {
|
|
99
|
+
await id.addWhitelistedWithDID(user1.address, "did:1");
|
|
100
|
+
expect(await faucet.canTop(user1.address)).to.true;
|
|
101
|
+
const tx = await (await faucet.topWallet(user1.address)).wait();
|
|
102
|
+
console.log(tx.gasUsed.toString());
|
|
103
|
+
const balance = await ethers.provider.getBalance(user1.address);
|
|
104
|
+
expect(balance).to.equal(await faucet.toppingAmount());
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
it("should not let identified user top over daily limit", async () => {
|
|
108
|
+
await user1.sendTransaction({
|
|
109
|
+
to: ethers.constants.AddressZero,
|
|
110
|
+
value: ethers.utils.parseUnits("400000", "gwei")
|
|
111
|
+
});
|
|
112
|
+
const tx = await (await faucet.topWallet(user1.address)).wait();
|
|
113
|
+
await user1.sendTransaction({
|
|
114
|
+
to: ethers.constants.AddressZero,
|
|
115
|
+
value: ethers.utils.parseUnits("400000", "gwei")
|
|
116
|
+
});
|
|
117
|
+
expect(await faucet.canTop(user1.address)).to.false;
|
|
118
|
+
await expect(faucet.topWallet(user1.address)).to.revertedWith(
|
|
119
|
+
"max daily toppings"
|
|
120
|
+
);
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
// it("should not top if wallet not half empty", async () => {
|
|
124
|
+
// expect(await faucet.canTop(founder.address)).to.false;
|
|
125
|
+
// await expect(faucet.topWallet(founder.address)).to.revertedWith(
|
|
126
|
+
// "User balance above minimum"
|
|
127
|
+
// );
|
|
128
|
+
// });
|
|
129
|
+
|
|
130
|
+
it("should not let user top over weekly limit", async () => {
|
|
131
|
+
for (let i = 0; i < 3; i++) {
|
|
132
|
+
await ethers.provider.send("evm_increaseTime", [60 * 60 * 24]);
|
|
133
|
+
await (await faucet.topWallet(user1.address)).wait();
|
|
134
|
+
await user1.sendTransaction({
|
|
135
|
+
to: ethers.constants.AddressZero,
|
|
136
|
+
value: ethers.utils.parseUnits("500000", "gwei")
|
|
137
|
+
});
|
|
138
|
+
// await (await faucet.topWallet(user1.address)).wait();
|
|
139
|
+
// await user1.sendTransaction({
|
|
140
|
+
// to: ethers.constants.AddressZero,
|
|
141
|
+
// value: ethers.utils.parseUnits("500000", "gwei"),
|
|
142
|
+
// });
|
|
143
|
+
}
|
|
144
|
+
// await (await faucet.topWallet(user1.address)).wait();
|
|
145
|
+
// await user1.sendTransaction({
|
|
146
|
+
// to: ethers.constants.AddressZero,
|
|
147
|
+
// value: ethers.utils.parseUnits("500000", "gwei"),
|
|
148
|
+
// });
|
|
149
|
+
await ethers.provider.send("evm_increaseTime", [60 * 60 * 24]);
|
|
150
|
+
|
|
151
|
+
expect(await faucet.canTop(user1.address)).to.false;
|
|
152
|
+
await expect(faucet.topWallet(user1.address)).to.revertedWith(
|
|
153
|
+
"User wallet has been topped too many times this week"
|
|
154
|
+
);
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
it("should reimburse gas costs", async () => {
|
|
158
|
+
const balance = await ethers.provider.getBalance(founder.address);
|
|
159
|
+
const tx = await (
|
|
160
|
+
await faucet.topWallet(user2.address, { gasPrice: 1e9 })
|
|
161
|
+
).wait();
|
|
162
|
+
// const gasCosts = tx.gasUsed.mul(1e9);
|
|
163
|
+
// const afterRefund = gasCosts.sub(await faucet["gasRefund()"]());
|
|
164
|
+
const balanceAfter = await ethers.provider.getBalance(founder.address);
|
|
165
|
+
const diff = balance.sub(balanceAfter).toNumber();
|
|
166
|
+
expect(diff).to.lt(10000);
|
|
167
|
+
});
|
|
168
|
+
});
|
|
@@ -0,0 +1,354 @@
|
|
|
1
|
+
import hre, { ethers, upgrades } from "hardhat";
|
|
2
|
+
import { expect } from "chai";
|
|
3
|
+
import { InvitesV1, IGoodDollar, IIdentity } from "../types";
|
|
4
|
+
import { SignerWithAddress } from "@nomiclabs/hardhat-ethers/dist/src/signer-with-address";
|
|
5
|
+
import { createDAO } from "./helpers";
|
|
6
|
+
|
|
7
|
+
const BN = ethers.BigNumber;
|
|
8
|
+
|
|
9
|
+
describe("InvitesV1", () => {
|
|
10
|
+
let invites: InvitesV1, founder: SignerWithAddress;
|
|
11
|
+
let inviter1,
|
|
12
|
+
inviter2,
|
|
13
|
+
invitee1,
|
|
14
|
+
invitee2,
|
|
15
|
+
invitee3,
|
|
16
|
+
invitee4,
|
|
17
|
+
invitee5,
|
|
18
|
+
invitee6,
|
|
19
|
+
invitee7,
|
|
20
|
+
invitee8;
|
|
21
|
+
|
|
22
|
+
let avatar, gd: IGoodDollar, Controller, id: IIdentity;
|
|
23
|
+
|
|
24
|
+
before(async () => {
|
|
25
|
+
[
|
|
26
|
+
founder,
|
|
27
|
+
inviter1,
|
|
28
|
+
inviter2,
|
|
29
|
+
invitee1,
|
|
30
|
+
invitee2,
|
|
31
|
+
invitee3,
|
|
32
|
+
invitee4,
|
|
33
|
+
invitee5,
|
|
34
|
+
invitee6,
|
|
35
|
+
invitee7,
|
|
36
|
+
invitee8
|
|
37
|
+
] = await ethers.getSigners();
|
|
38
|
+
|
|
39
|
+
const InvitesV1 = await ethers.getContractFactory("InvitesV1");
|
|
40
|
+
|
|
41
|
+
let {
|
|
42
|
+
daoCreator,
|
|
43
|
+
controller,
|
|
44
|
+
avatar: av,
|
|
45
|
+
gd: gooddollar,
|
|
46
|
+
identity
|
|
47
|
+
} = await createDAO();
|
|
48
|
+
|
|
49
|
+
Controller = controller;
|
|
50
|
+
avatar = av;
|
|
51
|
+
|
|
52
|
+
invites = (await upgrades.deployProxy(
|
|
53
|
+
InvitesV1,
|
|
54
|
+
[avatar, identity, gooddollar, 500],
|
|
55
|
+
{
|
|
56
|
+
unsafeAllowCustomTypes: true,
|
|
57
|
+
kind: "transparent"
|
|
58
|
+
}
|
|
59
|
+
)) as InvitesV1;
|
|
60
|
+
|
|
61
|
+
gd = (await ethers.getContractAt(
|
|
62
|
+
"IGoodDollar",
|
|
63
|
+
gooddollar,
|
|
64
|
+
founder
|
|
65
|
+
)) as IGoodDollar;
|
|
66
|
+
id = (await ethers.getContractAt(
|
|
67
|
+
"IIdentity",
|
|
68
|
+
identity,
|
|
69
|
+
founder
|
|
70
|
+
)) as IIdentity;
|
|
71
|
+
|
|
72
|
+
await gd["mint(address,uint256)"](invites.address, BN.from(5000));
|
|
73
|
+
// await gd.transfer(invites.address, BN.from(5000));
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
it("should have balance", async () => {
|
|
77
|
+
const balance = await gd.balanceOf(invites.address);
|
|
78
|
+
expect(balance).to.equal(5000);
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
it("should have version", async () => {
|
|
82
|
+
expect(await invites.active()).to.be.true;
|
|
83
|
+
const version = await invites.version();
|
|
84
|
+
expect(version).to.be.equal("1.5.0");
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
it("should let anyone join", async () => {
|
|
88
|
+
await invites
|
|
89
|
+
.connect(inviter1)
|
|
90
|
+
.join(ethers.utils.hexZeroPad("0xfa", 32), ethers.constants.HashZero);
|
|
91
|
+
let inviter = await invites.users(inviter1.address);
|
|
92
|
+
expect(inviter.inviteCode).to.equal(ethers.utils.hexZeroPad("0xfa", 32));
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
it("should allow to join only once", async () => {
|
|
96
|
+
await expect(
|
|
97
|
+
invites
|
|
98
|
+
.connect(inviter1)
|
|
99
|
+
.join(
|
|
100
|
+
ethers.utils.hexZeroPad("0xfa", 32),
|
|
101
|
+
ethers.utils.hexZeroPad("0x01", 32)
|
|
102
|
+
)
|
|
103
|
+
).to.revertedWith("user already joined");
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
it("should not allow code reuse", async () => {
|
|
107
|
+
// const invites = await Invites.deployed();
|
|
108
|
+
await expect(
|
|
109
|
+
invites
|
|
110
|
+
.connect(inviter2)
|
|
111
|
+
.join(ethers.utils.hexZeroPad("0xfa", 32), ethers.constants.HashZero)
|
|
112
|
+
).to.revertedWith("invite code already in use");
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
it("should mark inviter", async () => {
|
|
116
|
+
await invites
|
|
117
|
+
.connect(invitee1)
|
|
118
|
+
.join(
|
|
119
|
+
ethers.utils.hexZeroPad("0xaa", 32),
|
|
120
|
+
ethers.utils.hexZeroPad("0xfa", 32)
|
|
121
|
+
);
|
|
122
|
+
let invitee = await invites.users(invitee1.address);
|
|
123
|
+
let inviterInvitees = await invites.getInvitees(inviter1.address);
|
|
124
|
+
expect(invitee.invitedBy).to.be.equal(inviter1.address);
|
|
125
|
+
expect(inviterInvitees).to.include(invitee1.address);
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
it("should not pay bounty for non whitelisted invitee", async () => {
|
|
129
|
+
await expect(
|
|
130
|
+
invites.connect(inviter1).bountyFor(invitee1.address)
|
|
131
|
+
).to.revertedWith("user not elligble for bounty yet");
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
it("should not pay bounty for non whitelisted inviter", async () => {
|
|
135
|
+
await id.addWhitelistedWithDID(invitee1.address, Math.random() + "");
|
|
136
|
+
expect(await id.isWhitelisted(invitee1.address)).to.be.true;
|
|
137
|
+
expect(await invites.canCollectBountyFor(invitee1.address)).to.be.false;
|
|
138
|
+
await expect(
|
|
139
|
+
invites.connect(inviter1).bountyFor(invitee1.address)
|
|
140
|
+
).to.revertedWith("user not elligble for bounty yet");
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
it("should pay bounty for whitelisted invitee and inviter", async () => {
|
|
144
|
+
const bounty = (await invites.levels(0)).bounty.toNumber();
|
|
145
|
+
await id
|
|
146
|
+
.addWhitelistedWithDID(inviter1.address, Math.random() + "")
|
|
147
|
+
.catch(e => e);
|
|
148
|
+
const startBalance = await gd
|
|
149
|
+
.balanceOf(inviter1.address)
|
|
150
|
+
.then(_ => _.toNumber());
|
|
151
|
+
expect(await id.isWhitelisted(inviter1.address)).to.be.true;
|
|
152
|
+
let pending = await invites.getPendingInvitees(inviter1.address);
|
|
153
|
+
expect(pending.length, "pending").to.be.equal(1);
|
|
154
|
+
const inviteeBalance = await gd
|
|
155
|
+
.balanceOf(invitee1.address)
|
|
156
|
+
.then(_ => _.toNumber());
|
|
157
|
+
await invites.connect(inviter1).bountyFor(invitee1.address);
|
|
158
|
+
|
|
159
|
+
let invitee = await invites.users(invitee1.address);
|
|
160
|
+
let inviter = await invites.users(inviter1.address);
|
|
161
|
+
const endBalance = await gd
|
|
162
|
+
.balanceOf(inviter1.address)
|
|
163
|
+
.then(_ => _.toNumber());
|
|
164
|
+
|
|
165
|
+
pending = await invites.getPendingInvitees(inviter1.address);
|
|
166
|
+
const txFee = await gd.getFees(bounty).then(_ => _["0"].toNumber()); //gd might have a tx fee
|
|
167
|
+
const txFee2 = await gd.getFees(bounty / 2).then(_ => _["0"].toNumber()); //gd might have a tx fee
|
|
168
|
+
|
|
169
|
+
expect(pending.length, "pending").to.be.equal(0);
|
|
170
|
+
expect(invitee.bountyPaid).to.be.true;
|
|
171
|
+
expect(inviter.totalApprovedInvites.toNumber()).to.be.equal(1);
|
|
172
|
+
expect(inviter.totalEarned.toNumber()).to.be.equal(bounty);
|
|
173
|
+
expect(
|
|
174
|
+
endBalance - startBalance + txFee,
|
|
175
|
+
"inviter rewards not matching bounty"
|
|
176
|
+
).to.be.equal(bounty);
|
|
177
|
+
expect(
|
|
178
|
+
(await gd.balanceOf(invitee1.address).then(_ => _.toNumber())) -
|
|
179
|
+
inviteeBalance,
|
|
180
|
+
"invitee rewrad should be bounty/2"
|
|
181
|
+
).to.be.equal(bounty / 2 - txFee2); //test that invitee got half bonus
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
it("should update global stats", async () => {
|
|
185
|
+
const bounty = (await invites.levels(0)).bounty.toNumber();
|
|
186
|
+
const stats = await invites.stats();
|
|
187
|
+
expect(stats.totalApprovedInvites.toNumber()).to.be.equal(
|
|
188
|
+
1,
|
|
189
|
+
"approved invites"
|
|
190
|
+
);
|
|
191
|
+
expect(stats.totalInvited.toNumber()).to.be.equal(1, "total invited");
|
|
192
|
+
expect(stats.totalBountiesPaid.toNumber()).to.be.equal(bounty);
|
|
193
|
+
});
|
|
194
|
+
|
|
195
|
+
it("should not pay bounty twice", async () => {
|
|
196
|
+
await expect(
|
|
197
|
+
invites.connect(inviter2).bountyFor(invitee1.address)
|
|
198
|
+
).to.revertedWith("user not elligble for bounty yet");
|
|
199
|
+
});
|
|
200
|
+
|
|
201
|
+
it("should not fail in collectBounties for invalid invitees", async () => {
|
|
202
|
+
await invites
|
|
203
|
+
.connect(invitee7)
|
|
204
|
+
.join(
|
|
205
|
+
ethers.utils.hexZeroPad("0x01", 32),
|
|
206
|
+
ethers.utils.hexZeroPad("0xfa", 32)
|
|
207
|
+
);
|
|
208
|
+
await invites
|
|
209
|
+
.connect(invitee8)
|
|
210
|
+
.join(
|
|
211
|
+
ethers.utils.hexZeroPad("0x02", 32),
|
|
212
|
+
ethers.utils.hexZeroPad("0xfa", 32)
|
|
213
|
+
);
|
|
214
|
+
|
|
215
|
+
let pending = await invites.getPendingInvitees(inviter1.address);
|
|
216
|
+
expect(pending.length, "pending").to.be.equal(2);
|
|
217
|
+
await expect(invites.connect(inviter1).collectBounties()).to.not.reverted;
|
|
218
|
+
let user1 = await invites.users(invitee7.address);
|
|
219
|
+
let user2 = await invites.users(invitee8.address);
|
|
220
|
+
pending = await invites.getPendingInvitees(inviter1.address);
|
|
221
|
+
expect(
|
|
222
|
+
await invites.getPendingBounties(inviter1.address).then(_ => _.toNumber())
|
|
223
|
+
).to.be.equal(0);
|
|
224
|
+
expect(user1.bountyPaid).to.be.false;
|
|
225
|
+
expect(user2.bountyPaid).to.be.false;
|
|
226
|
+
expect(pending.length, "pending").to.be.equal(2);
|
|
227
|
+
});
|
|
228
|
+
|
|
229
|
+
it("should collectBounties for inviter", async () => {
|
|
230
|
+
await id
|
|
231
|
+
.addWhitelistedWithDID(invitee7.address, Math.random() + "")
|
|
232
|
+
.catch(e => e);
|
|
233
|
+
await id
|
|
234
|
+
.addWhitelistedWithDID(invitee8.address, Math.random() + "")
|
|
235
|
+
.catch(e => e);
|
|
236
|
+
expect(
|
|
237
|
+
await invites.getPendingBounties(inviter1.address).then(_ => _.toNumber())
|
|
238
|
+
).to.be.equal(2);
|
|
239
|
+
const res = await invites
|
|
240
|
+
.connect(inviter1)
|
|
241
|
+
.collectBounties()
|
|
242
|
+
.catch(e => e);
|
|
243
|
+
|
|
244
|
+
let user1 = await invites.users(invitee7.address);
|
|
245
|
+
let user2 = await invites.users(invitee8.address);
|
|
246
|
+
let pending = await invites.getPendingInvitees(inviter1.address);
|
|
247
|
+
expect(
|
|
248
|
+
await invites.getPendingBounties(inviter1.address).then(_ => _.toNumber())
|
|
249
|
+
).to.be.equal(0);
|
|
250
|
+
expect(pending.length, "pending").to.be.equal(0);
|
|
251
|
+
expect(user1.bountyPaid, "user1").to.be.true;
|
|
252
|
+
expect(user2.bountyPaid, "user2").to.be.true;
|
|
253
|
+
});
|
|
254
|
+
|
|
255
|
+
it("should not set level not by owner", async () => {
|
|
256
|
+
await expect(
|
|
257
|
+
invites.connect(inviter1).setLevel(0, 1, 5, 1)
|
|
258
|
+
).to.revertedWith("Only owner or avatar can perform this action");
|
|
259
|
+
});
|
|
260
|
+
|
|
261
|
+
it("should set level by owner", async () => {
|
|
262
|
+
await invites.setLevel(0, 1, 5, 1);
|
|
263
|
+
let lvl = await invites.levels(0);
|
|
264
|
+
expect(lvl.toNext.toNumber()).to.be.equal(1);
|
|
265
|
+
expect(lvl.daysToComplete.toNumber()).to.be.equal(1);
|
|
266
|
+
await invites.setLevel(1, 0, 10, 2);
|
|
267
|
+
lvl = await invites.levels(1);
|
|
268
|
+
expect(lvl.toNext.toNumber()).to.be.equal(0);
|
|
269
|
+
expect(lvl.daysToComplete.toNumber()).to.be.equal(2);
|
|
270
|
+
expect(lvl.bounty.toNumber()).to.be.equal(10);
|
|
271
|
+
});
|
|
272
|
+
|
|
273
|
+
it("should update inviter level", async () => {
|
|
274
|
+
await invites
|
|
275
|
+
.connect(inviter1)
|
|
276
|
+
.join(ethers.utils.hexZeroPad("0xfa", 32), ethers.constants.HashZero)
|
|
277
|
+
.then(_ => _.wait())
|
|
278
|
+
.catch(e => e);
|
|
279
|
+
|
|
280
|
+
await id
|
|
281
|
+
.addWhitelistedWithDID(inviter1.address, Math.random() + "")
|
|
282
|
+
.catch(e => e);
|
|
283
|
+
await invites.setLevel(0, 1, 5, 1); //1 inviter to level up
|
|
284
|
+
await invites.setLevel(1, 0, 10, 2); // 10 bounty for second level
|
|
285
|
+
|
|
286
|
+
await invites
|
|
287
|
+
.connect(invitee4)
|
|
288
|
+
.join(
|
|
289
|
+
ethers.utils.hexZeroPad("0x03", 32),
|
|
290
|
+
ethers.utils.hexZeroPad("0xfa", 32)
|
|
291
|
+
);
|
|
292
|
+
await invites
|
|
293
|
+
.connect(invitee5)
|
|
294
|
+
.join(
|
|
295
|
+
ethers.utils.hexZeroPad("0x04", 32),
|
|
296
|
+
ethers.utils.hexZeroPad("0xfa", 32)
|
|
297
|
+
);
|
|
298
|
+
await id
|
|
299
|
+
.addWhitelistedWithDID(invitee4.address, Math.random() + "")
|
|
300
|
+
.catch(e => e);
|
|
301
|
+
await id
|
|
302
|
+
.addWhitelistedWithDID(invitee5.address, Math.random() + "")
|
|
303
|
+
.catch(e => e);
|
|
304
|
+
const res1 = await (await invites.bountyFor(invitee4.address)).wait();
|
|
305
|
+
|
|
306
|
+
const log1 = res1.events.find(_ => _.event === "InviterBounty");
|
|
307
|
+
expect(log1.event).to.be.equal("InviterBounty");
|
|
308
|
+
expect(log1.args.inviterLevel.toNumber()).to.be.equal(1);
|
|
309
|
+
expect(log1.args.earnedLevel).to.be.equal(true);
|
|
310
|
+
expect(log1.args.bountyPaid.toNumber()).to.be.equal(5);
|
|
311
|
+
|
|
312
|
+
let inviter = await invites.users(inviter1.address);
|
|
313
|
+
expect(inviter.level.toNumber()).to.be.equal(1);
|
|
314
|
+
const res2 = await (
|
|
315
|
+
await invites.connect(inviter1).collectBounties()
|
|
316
|
+
).wait();
|
|
317
|
+
const log2 = res2.events.find(_ => _.event === "InviterBounty");
|
|
318
|
+
expect(log2.event).to.be.equal("InviterBounty");
|
|
319
|
+
expect(log2.args.inviterLevel.toNumber()).to.be.equal(1);
|
|
320
|
+
expect(log2.args.earnedLevel).to.be.equal(false);
|
|
321
|
+
expect(log2.args.bountyPaid.toNumber()).to.be.equal(10);
|
|
322
|
+
});
|
|
323
|
+
|
|
324
|
+
it("should allow to set inviter later and pay bounty", async () => {
|
|
325
|
+
await invites
|
|
326
|
+
.connect(invitee6)
|
|
327
|
+
.join(ethers.utils.hexZeroPad("0xfd", 32), ethers.constants.HashZero);
|
|
328
|
+
await invites
|
|
329
|
+
.connect(invitee6)
|
|
330
|
+
.join(
|
|
331
|
+
ethers.utils.hexZeroPad("0xfd", 32),
|
|
332
|
+
ethers.utils.hexZeroPad("0xfa", 32)
|
|
333
|
+
);
|
|
334
|
+
const invitee = await invites.users(invitee6.address);
|
|
335
|
+
expect(invitee.invitedBy).to.equal(inviter1.address);
|
|
336
|
+
await id
|
|
337
|
+
.addWhitelistedWithDID(invitee6.address, Math.random() + "")
|
|
338
|
+
.catch(e => e);
|
|
339
|
+
await expect(invites.bountyFor(invitee6.address)).to.emit(
|
|
340
|
+
invites,
|
|
341
|
+
"InviterBounty"
|
|
342
|
+
);
|
|
343
|
+
});
|
|
344
|
+
|
|
345
|
+
it("should end contract by owner", async () => {
|
|
346
|
+
expect(
|
|
347
|
+
await gd.balanceOf(invites.address).then(_ => _.toNumber())
|
|
348
|
+
).to.be.gt(0);
|
|
349
|
+
await invites.end();
|
|
350
|
+
expect(
|
|
351
|
+
await gd.balanceOf(invites.address).then(_ => _.toNumber())
|
|
352
|
+
).to.be.eq(0);
|
|
353
|
+
});
|
|
354
|
+
});
|