@gooddollar/goodprotocol 1.0.23 → 1.0.26-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/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 +7 -6
- package/patches/@nomiclabs+hardhat-etherscan+3.0.3.patch +41 -0
- package/patches/@openzeppelin+hardhat-upgrades+1.7.0.patch +67 -0
- package/patches/@openzeppelin+upgrades-core+1.4.2.patch +21 -0
- 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,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
|
+
});
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
import { ethers, network as networkConfig } from "hardhat";
|
|
2
|
+
import { FuseStakingV3 } from "../../types";
|
|
3
|
+
import { expect } from "chai";
|
|
4
|
+
import { deployMockContract, MockContract } from "ethereum-waffle";
|
|
5
|
+
import hre from "hardhat";
|
|
6
|
+
import { abi as ubiabi } from "../../artifacts/contracts/ubi/UBIScheme.sol/UBIScheme.json";
|
|
7
|
+
import { BigNumber } from "ethers";
|
|
8
|
+
export const NULL_ADDRESS = "0x0000000000000000000000000000000000000000";
|
|
9
|
+
|
|
10
|
+
describe("FuseStakingV3", () => {
|
|
11
|
+
let staking: FuseStakingV3;
|
|
12
|
+
let founder, staker1, staker2;
|
|
13
|
+
let signers;
|
|
14
|
+
|
|
15
|
+
let uniswap: MockContract,
|
|
16
|
+
uniswapFactory,
|
|
17
|
+
uniswapPair,
|
|
18
|
+
gdusdcPair,
|
|
19
|
+
fusefusdPair,
|
|
20
|
+
ubiMock;
|
|
21
|
+
|
|
22
|
+
const deployMocks = async () => {
|
|
23
|
+
let u = await hre.artifacts.readArtifact("Uniswap");
|
|
24
|
+
let uf = await hre.artifacts.readArtifact("UniswapFactory");
|
|
25
|
+
let up = await hre.artifacts.readArtifact("UniswapPair");
|
|
26
|
+
uniswap = await deployMockContract(signers[0], u.abi);
|
|
27
|
+
uniswapFactory = await deployMockContract(signers[0], uf.abi);
|
|
28
|
+
uniswapPair = await deployMockContract(signers[0], up.abi);
|
|
29
|
+
|
|
30
|
+
gdusdcPair = await deployMockContract(signers[0], up.abi);
|
|
31
|
+
fusefusdPair = await deployMockContract(signers[0], up.abi);
|
|
32
|
+
|
|
33
|
+
ubiMock = await deployMockContract(signers[0], ubiabi);
|
|
34
|
+
await uniswap.mock.factory.returns(uniswapFactory.address);
|
|
35
|
+
await uniswap.mock.WETH.returns(signers[3].address);
|
|
36
|
+
await uniswapFactory.mock.getPair.returns(uniswapPair.address);
|
|
37
|
+
await uniswapFactory.mock.getPair
|
|
38
|
+
.withArgs(
|
|
39
|
+
ethers.constants.AddressZero,
|
|
40
|
+
"0x620fd5fa44BE6af63715Ef4E65DDFA0387aD13F5"
|
|
41
|
+
)
|
|
42
|
+
.returns(gdusdcPair.address);
|
|
43
|
+
|
|
44
|
+
await uniswapFactory.mock.getPair
|
|
45
|
+
.withArgs(
|
|
46
|
+
signers[3].address,
|
|
47
|
+
"0x249BE57637D8B013Ad64785404b24aeBaE9B098B"
|
|
48
|
+
)
|
|
49
|
+
.returns(fusefusdPair.address);
|
|
50
|
+
|
|
51
|
+
await uniswapPair.mock.getReserves.returns(
|
|
52
|
+
ethers.utils.parseEther("1000"),
|
|
53
|
+
"100000",
|
|
54
|
+
"0"
|
|
55
|
+
);
|
|
56
|
+
await gdusdcPair.mock.getReserves.returns("4984886100", "10789000000", "0");
|
|
57
|
+
await fusefusdPair.mock.getReserves.returns(
|
|
58
|
+
ethers.utils.parseEther("10000"),
|
|
59
|
+
ethers.utils.parseEther("2000"), //200$ fusd 18 decimals
|
|
60
|
+
"0"
|
|
61
|
+
);
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
before(async () => {
|
|
65
|
+
signers = await ethers.getSigners();
|
|
66
|
+
[founder, staker1, staker2] = signers.map(_ => _.address);
|
|
67
|
+
await deployMocks();
|
|
68
|
+
|
|
69
|
+
let network = networkConfig.name;
|
|
70
|
+
staking = (await (
|
|
71
|
+
await ethers.getContractFactory("FuseStakingV3")
|
|
72
|
+
).deploy()) as FuseStakingV3;
|
|
73
|
+
|
|
74
|
+
await staking.initialize();
|
|
75
|
+
await staking.upgrade0();
|
|
76
|
+
await staking.upgrade1(NULL_ADDRESS, ubiMock.address, uniswap.address);
|
|
77
|
+
await staking.upgrade2();
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
it("should have owner", async () => {
|
|
81
|
+
expect(await staking.owner()).to.be.equal(founder);
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
it("should calc quantity with slippage", async () => {
|
|
85
|
+
const res = await staking[
|
|
86
|
+
"calcMaxTokenWithPriceImpact(uint256,uint256,uint256)"
|
|
87
|
+
]("6917100025787759640000", "265724494", ethers.utils.parseEther("500"));
|
|
88
|
+
|
|
89
|
+
// const fuseQuantity = ethers.utils.formatEther(res);
|
|
90
|
+
expect(res.maxToken).to.gt(0);
|
|
91
|
+
expect(res.maxToken).to.equal(
|
|
92
|
+
BigNumber.from("6917100025787759640000").mul(3).div(100)
|
|
93
|
+
);
|
|
94
|
+
expect(res.tokenOut).to.equal(7717004);
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
it("should calc quantity with uniswap mock", async () => {
|
|
98
|
+
const res = await staking["calcMaxFuseWithPriceImpact(uint256)"](
|
|
99
|
+
ethers.utils.parseEther("500")
|
|
100
|
+
);
|
|
101
|
+
|
|
102
|
+
// const fuseQuantity = ethers.utils.formatEther(res);
|
|
103
|
+
expect(res.fuseAmount).to.gt(0);
|
|
104
|
+
expect(res.fuseAmount).to.equal(ethers.utils.parseEther("30"));
|
|
105
|
+
|
|
106
|
+
await uniswapPair.mock.getReserves.returns(
|
|
107
|
+
ethers.utils.parseEther("100"),
|
|
108
|
+
"500000",
|
|
109
|
+
"0"
|
|
110
|
+
);
|
|
111
|
+
const res2 = await staking["calcMaxFuseWithPriceImpact(uint256)"](
|
|
112
|
+
ethers.utils.parseEther("500")
|
|
113
|
+
);
|
|
114
|
+
|
|
115
|
+
expect(res2.fuseAmount).to.equal(ethers.utils.parseEther("3"));
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
it("should calculate gd/usdc quantity with 0 price impact ", async () => {
|
|
119
|
+
const res = await staking["calcMaxFuseUSDCWithPriceImpact(uint256)"](
|
|
120
|
+
ethers.utils.parseEther("10")
|
|
121
|
+
);
|
|
122
|
+
//exchanging 10 fuse which are equal 2$ USDC should have no significant price impact on usdc/gd swap so we should be able to swap the whole 10
|
|
123
|
+
expect(res.maxFuse).to.gt(0);
|
|
124
|
+
expect(res.maxFuse).to.equal(ethers.utils.parseEther("10"));
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
it("should detect gd/usdc price impact", async () => {
|
|
128
|
+
const res = await staking["calcMaxFuseUSDCWithPriceImpact(uint256)"](
|
|
129
|
+
ethers.utils.parseEther("10000")
|
|
130
|
+
);
|
|
131
|
+
expect(res.maxFuse).to.lt(ethers.utils.parseEther("10000"));
|
|
132
|
+
expect(res.maxFuse).to.equal(ethers.utils.parseEther("1618.35")); //on fuse swap it was around 335$ on above gd/usdc reserves that reaches 3% impact, that means 335*5=1675fuse
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
it("should match fuseswap and allow to exchange +-4600 fuse to G$", async () => {
|
|
136
|
+
//G$/usdc reserves 52,841,23400/10410000000
|
|
137
|
+
//fuse/fusd reserves 619085*1e18/42905*1e18
|
|
138
|
+
|
|
139
|
+
await gdusdcPair.mock.getReserves.returns("5284123400", "10410000000", "0");
|
|
140
|
+
await fusefusdPair.mock.getReserves.returns(
|
|
141
|
+
ethers.utils.parseEther("619085"),
|
|
142
|
+
ethers.utils.parseEther("42905"),
|
|
143
|
+
"0"
|
|
144
|
+
);
|
|
145
|
+
|
|
146
|
+
const res = await staking["calcMaxFuseUSDCWithPriceImpact(uint256)"](
|
|
147
|
+
ethers.utils.parseEther("10000")
|
|
148
|
+
);
|
|
149
|
+
expect(res.maxFuse).to.lt(ethers.utils.parseEther("5000"));
|
|
150
|
+
expect(res.maxFuse).to.gt(ethers.utils.parseEther("4500"));
|
|
151
|
+
});
|
|
152
|
+
});
|