UNPKG

@gooddollar/goodprotocol

Version:
360 lines (322 loc) 11.9 kB
import hre, { ethers, upgrades } from "hardhat"; import { loadFixture } from "@nomicfoundation/hardhat-network-helpers"; import { expect } from "chai"; import { InvitesV1, IGoodDollar, IIdentity } from "../../types"; import { SignerWithAddress } from "@nomiclabs/hardhat-ethers/dist/src/signer-with-address"; import { createDAO } from "../helpers"; const BN = ethers.BigNumber; describe("InvitesV1", () => { let invites: InvitesV1, founder: SignerWithAddress; let inviter1, inviter2, invitee1, invitee2, invitee3, invitee4, invitee5, invitee6, invitee7, invitee8; let avatar, gd: IGoodDollar, Controller, id: IIdentity; before(async () => { [ founder, inviter1, inviter2, invitee1, invitee2, invitee3, invitee4, invitee5, invitee6, invitee7, invitee8 ] = await ethers.getSigners(); const InvitesV1 = await ethers.getContractFactory("InvitesV1"); let { daoCreator, controller, avatar: av, gd: gooddollar, identity } = await loadFixture(createDAO); Controller = controller; avatar = av; invites = (await upgrades.deployProxy( InvitesV1, [avatar, identity, gooddollar, 500], { unsafeAllowCustomTypes: true, kind: "transparent" } )) as InvitesV1; gd = (await ethers.getContractAt( "IGoodDollar", gooddollar, founder )) as IGoodDollar; id = (await ethers.getContractAt( "IIdentity", identity, founder )) as IIdentity; await gd["mint(address,uint256)"](invites.address, BN.from(5000)); // await gd.transfer(invites.address, BN.from(5000)); }); it("should have balance", async () => { const balance = await gd.balanceOf(invites.address); expect(balance).to.equal(5000); }); it("should have version", async () => { expect(await invites.active()).to.be.true; const version = await invites.version(); expect(version).to.be.equal("1.5.0"); }); it("should let anyone join", async () => { await invites .connect(inviter1) .join(ethers.utils.hexZeroPad("0xfa", 32), ethers.constants.HashZero); let inviter = await invites.users(inviter1.address); expect(inviter.inviteCode).to.equal(ethers.utils.hexZeroPad("0xfa", 32)); }); it("should allow to join only once", async () => { await expect( invites .connect(inviter1) .join( ethers.utils.hexZeroPad("0xfa", 32), ethers.utils.hexZeroPad("0x01", 32) ) ).to.revertedWith(/user already joined/); }); it("should not allow code reuse", async () => { // const invites = await Invites.deployed(); await expect( invites .connect(inviter2) .join(ethers.utils.hexZeroPad("0xfa", 32), ethers.constants.HashZero) ).to.revertedWith(/invite code already in use/); }); it("should mark inviter", async () => { await invites .connect(invitee1) .join( ethers.utils.hexZeroPad("0xaa", 32), ethers.utils.hexZeroPad("0xfa", 32) ); let invitee = await invites.users(invitee1.address); let inviterInvitees = await invites.getInvitees(inviter1.address); expect(invitee.invitedBy).to.be.equal(inviter1.address); expect(inviterInvitees).to.include(invitee1.address); }); it("should not pay bounty for non whitelisted invitee", async () => { await expect( invites.connect(inviter1).bountyFor(invitee1.address) ).to.revertedWith(/user not elligble for bounty yet/); }); it("should not pay bounty for non whitelisted inviter", async () => { await id.addWhitelistedWithDID(invitee1.address, Math.random() + ""); expect(await id.isWhitelisted(invitee1.address)).to.be.true; expect(await invites.canCollectBountyFor(invitee1.address)).to.be.false; await expect( invites.connect(inviter1).bountyFor(invitee1.address) ).to.revertedWith(/user not elligble for bounty yet/); }); it("should pay bounty for whitelisted invitee and inviter", async () => { const bounty = (await invites.levels(0)).bounty.toNumber(); await id .addWhitelistedWithDID(inviter1.address, Math.random() + "") .catch(e => e); const startBalance = await gd .balanceOf(inviter1.address) .then(_ => _.toNumber()); expect(await id.isWhitelisted(inviter1.address)).to.be.true; let pending = await invites.getPendingInvitees(inviter1.address); expect(pending.length, "pending").to.be.equal(1); const inviteeBalance = await gd .balanceOf(invitee1.address) .then(_ => _.toNumber()); await invites.connect(inviter1).bountyFor(invitee1.address); let invitee = await invites.users(invitee1.address); let inviter = await invites.users(inviter1.address); const endBalance = await gd .balanceOf(inviter1.address) .then(_ => _.toNumber()); pending = await invites.getPendingInvitees(inviter1.address); const txFee = await gd["getFees(uint256)"](bounty).then(_ => _["0"].toNumber() ); //gd might have a tx fee const txFee2 = await gd["getFees(uint256)"](bounty / 2).then(_ => _["0"].toNumber() ); //gd might have a tx fee expect(pending.length, "pending").to.be.equal(0); expect(invitee.bountyPaid).to.be.true; expect(inviter.totalApprovedInvites.toNumber()).to.be.equal(1); expect(inviter.totalEarned.toNumber()).to.be.equal(bounty); expect( endBalance - startBalance + txFee, "inviter rewards not matching bounty" ).to.be.equal(bounty); expect( (await gd.balanceOf(invitee1.address).then(_ => _.toNumber())) - inviteeBalance, "invitee rewrad should be bounty/2" ).to.be.equal(bounty / 2 - txFee2); //test that invitee got half bonus }); it("should update global stats", async () => { const bounty = (await invites.levels(0)).bounty.toNumber(); const stats = await invites.stats(); expect(stats.totalApprovedInvites.toNumber()).to.be.equal( 1, "approved invites" ); expect(stats.totalInvited.toNumber()).to.be.equal(1, "total invited"); expect(stats.totalBountiesPaid.toNumber()).to.be.equal(bounty); }); it("should not pay bounty twice", async () => { await expect( invites.connect(inviter2).bountyFor(invitee1.address) ).to.revertedWith(/user not elligble for bounty yet/); }); it("should not fail in collectBounties for invalid invitees", async () => { await invites .connect(invitee7) .join( ethers.utils.hexZeroPad("0x01", 32), ethers.utils.hexZeroPad("0xfa", 32) ); await invites .connect(invitee8) .join( ethers.utils.hexZeroPad("0x02", 32), ethers.utils.hexZeroPad("0xfa", 32) ); let pending = await invites.getPendingInvitees(inviter1.address); expect(pending.length, "pending").to.be.equal(2); await expect(invites.connect(inviter1).collectBounties()).to.not.reverted; let user1 = await invites.users(invitee7.address); let user2 = await invites.users(invitee8.address); pending = await invites.getPendingInvitees(inviter1.address); expect( await invites.getPendingBounties(inviter1.address).then(_ => _.toNumber()) ).to.be.equal(0); expect(user1.bountyPaid).to.be.false; expect(user2.bountyPaid).to.be.false; expect(pending.length, "pending").to.be.equal(2); }); it("should collectBounties for inviter", async () => { await id .addWhitelistedWithDID(invitee7.address, Math.random() + "") .catch(e => e); await id .addWhitelistedWithDID(invitee8.address, Math.random() + "") .catch(e => e); expect( await invites.getPendingBounties(inviter1.address).then(_ => _.toNumber()) ).to.be.equal(2); const res = await invites .connect(inviter1) .collectBounties() .catch(e => e); let user1 = await invites.users(invitee7.address); let user2 = await invites.users(invitee8.address); let pending = await invites.getPendingInvitees(inviter1.address); expect( await invites.getPendingBounties(inviter1.address).then(_ => _.toNumber()) ).to.be.equal(0); expect(pending.length, "pending").to.be.equal(0); expect(user1.bountyPaid, "user1").to.be.true; expect(user2.bountyPaid, "user2").to.be.true; }); it("should not set level not by owner", async () => { await expect( invites.connect(inviter1).setLevel(0, 1, 5, 1) ).to.revertedWith(/Only owner or avatar can perform this action/); }); it("should set level by owner", async () => { await invites.setLevel(0, 1, 5, 1); let lvl = await invites.levels(0); expect(lvl.toNext.toNumber()).to.be.equal(1); expect(lvl.daysToComplete.toNumber()).to.be.equal(1); await invites.setLevel(1, 0, 10, 2); lvl = await invites.levels(1); expect(lvl.toNext.toNumber()).to.be.equal(0); expect(lvl.daysToComplete.toNumber()).to.be.equal(2); expect(lvl.bounty.toNumber()).to.be.equal(10); }); it("should update inviter level", async () => { await invites .connect(inviter1) .join(ethers.utils.hexZeroPad("0xfa", 32), ethers.constants.HashZero) .then(_ => _.wait()) .catch(e => e); await id .addWhitelistedWithDID(inviter1.address, Math.random() + "") .catch(e => e); await invites.setLevel(0, 1, 5, 1); //1 inviter to level up await invites.setLevel(1, 0, 10, 2); // 10 bounty for second level await invites .connect(invitee4) .join( ethers.utils.hexZeroPad("0x03", 32), ethers.utils.hexZeroPad("0xfa", 32) ); await invites .connect(invitee5) .join( ethers.utils.hexZeroPad("0x04", 32), ethers.utils.hexZeroPad("0xfa", 32) ); await id .addWhitelistedWithDID(invitee4.address, Math.random() + "") .catch(e => e); await id .addWhitelistedWithDID(invitee5.address, Math.random() + "") .catch(e => e); const res1 = await (await invites.bountyFor(invitee4.address)).wait(); const log1 = res1.events.find(_ => _.event === "InviterBounty"); expect(log1.event).to.be.equal("InviterBounty"); expect(log1.args.inviterLevel.toNumber()).to.be.equal(1); expect(log1.args.earnedLevel).to.be.equal(true); expect(log1.args.bountyPaid.toNumber()).to.be.equal(5); let inviter = await invites.users(inviter1.address); expect(inviter.level.toNumber()).to.be.equal(1); const res2 = await ( await invites.connect(inviter1).collectBounties() ).wait(); const log2 = res2.events.find(_ => _.event === "InviterBounty"); expect(log2.event).to.be.equal("InviterBounty"); expect(log2.args.inviterLevel.toNumber()).to.be.equal(1); expect(log2.args.earnedLevel).to.be.equal(false); expect(log2.args.bountyPaid.toNumber()).to.be.equal(10); }); it("should allow to set inviter later and pay bounty", async () => { await invites .connect(invitee6) .join(ethers.utils.hexZeroPad("0xfd", 32), ethers.constants.HashZero); await invites .connect(invitee6) .join( ethers.utils.hexZeroPad("0xfd", 32), ethers.utils.hexZeroPad("0xfa", 32) ); const invitee = await invites.users(invitee6.address); expect(invitee.invitedBy).to.equal(inviter1.address); await id .addWhitelistedWithDID(invitee6.address, Math.random() + "") .catch(e => e); await expect(invites.bountyFor(invitee6.address)).to.emit( invites, "InviterBounty" ); }); it("should end contract by owner", async () => { expect( await gd.balanceOf(invites.address).then(_ => _.toNumber()) ).to.be.gt(0); await invites.end(); expect( await gd.balanceOf(invites.address).then(_ => _.toNumber()) ).to.be.eq(0); }); });