@gooddollar/goodprotocol
Version:
GoodDollar Protocol
465 lines (369 loc) • 19.4 kB
text/typescript
import hre, { ethers, upgrades } from "hardhat";
import { loadFixture, time } from "@nomicfoundation/hardhat-network-helpers";
import { expect } from "chai";
import { IGoodDollar, IIdentity, IdentityV3, IdentityV4 } from "../../types";
import { createDAO, increaseTime, advanceBlocks } from "../helpers";
import { SignerWithAddress } from "@nomiclabs/hardhat-ethers/signers";
const BN = ethers.BigNumber;
describe("IdentityV4", () => {
let identity: IdentityV4, founder: SignerWithAddress;
let user1 = ethers.Wallet.createRandom().connect(ethers.provider);
let user2 = ethers.Wallet.createRandom().connect(ethers.provider);
let signers: Array<SignerWithAddress>;
let genericCall;
let avatar, gd: IGoodDollar, Controller, id: IIdentity;
before(async () => {
[founder, ...signers] = await ethers.getSigners();
let { controller, avatar: av, gd: gooddollar, identity: idv2, genericCall: gc } = await loadFixture(createDAO);
genericCall = gc;
identity = (await ethers.getContractAt("IdentityV4", idv2)) as IdentityV4;
Controller = controller;
avatar = av;
// await daoCreator.setSchemes(
// avatar,
// [identity],
// [ethers.constants.HashZero],
// ["0x0000001F"],
// ""
// );
gd = (await ethers.getContractAt("IGoodDollar", gooddollar, founder)) as IGoodDollar;
});
it("should set DAO by creator", async () => {
let f = await ethers.getContractFactory("IdentityV4");
let newid = (await upgrades.deployProxy(f, [signers[0].address, ethers.constants.AddressZero], {
kind: "uups"
})) as IdentityV4;
expect(await newid.dao()).eq(ethers.constants.AddressZero);
await expect(newid.connect(signers[0]).initDAO(await identity.nameService())).not.reverted;
expect(await newid.dao()).not.eq(ethers.constants.AddressZero);
});
it("should not be able to set DAO by non-creator", async () => {
let f = await ethers.getContractFactory("IdentityV4");
let newid = (await upgrades.deployProxy(f, [signers[0].address, ethers.constants.AddressZero], {
kind: "uups"
})) as IdentityV4;
expect(await newid.dao()).eq(ethers.constants.AddressZero);
await expect(newid.initDAO(await identity.nameService())).reverted;
});
it("should blacklist address", async () => {
let blacklisted = signers[1];
await identity.addBlacklisted(blacklisted.address);
expect(await identity.isBlacklisted(blacklisted.address)).true;
await identity.removeBlacklisted(blacklisted.address);
expect(await identity.isBlacklisted(blacklisted.address)).false;
});
it("should add, check and remove whitelisted", async () => {
let whitelisted = signers[1];
await identity.addWhitelisted(whitelisted.address);
expect(await identity.isWhitelisted(whitelisted.address)).true;
const id = await identity.identities(whitelisted.address);
expect(id.whitelistedOnChainId).gt(0);
await identity.removeWhitelisted(whitelisted.address);
expect(await identity.isWhitelisted(whitelisted.address)).false;
});
it("should increment and decrement whitelisteds when adding whitelisted", async () => {
let whitelisted = signers[1];
const oldWhitelistedCount = (await identity.whitelistedCount()) as any;
await identity.addWhitelisted(whitelisted.address);
const diffWhitelistedCount = ((await identity.whitelistedCount()) as any).sub(oldWhitelistedCount);
expect(diffWhitelistedCount.toString()).to.be.equal("1");
await identity.removeWhitelisted(whitelisted.address);
const whitelistedCount = (await identity.whitelistedCount()) as any;
expect(whitelistedCount.toString()).to.be.equal(oldWhitelistedCount.toString());
});
it("should revert when non admin tries to add whitelisted", async () => {
let whitelisted = signers[1];
await expect(identity.connect(signers[2]).addWhitelisted(whitelisted.address)).revertedWith(
/AccessControl: account/
);
});
it("should revert when non admin tries to add blacklist", async () => {
let blacklisted = signers[1];
await expect(identity.connect(signers[2]).addBlacklisted(blacklisted.address)).revertedWith(
/AccessControl: account/
);
});
// it("should revert when non admin tries to set the authentication period", async () => {
// await expect(identity.connect(signers[2]).setAuthenticationPeriod(10)).reverted;
// });
it("should retun the last reverify period as authenticationPeriod", async () => {
await expect(identity.setReverifyDaysOptions([1, 7, 111])).not.reverted;
expect(await identity.authenticationPeriod()).eq(111);
});
it("should enforce order in reverify days options", async () => {
await expect(identity.setReverifyDaysOptions([1, 111, 7])).reverted;
});
it("should revert when non admin tries to pause", async () => {
await expect(identity.connect(signers[2]).pause(true)).reverted;
});
it("should let admin pause", async () => {
await expect(identity.pause(true)).not.reverted;
await expect(identity.pause(false)).not.reverted;
});
it("should revert when non admin tries to authentice a user", async () => {
let authuser = signers[0].address;
await expect(identity.connect(signers[2]).authenticate(authuser)).revertedWith(/AccessControl: account/);
});
it("should authenticate the user with the correct timestamp", async () => {
let authuser = signers[0].address;
await identity.addWhitelisted(authuser);
await identity.authenticate(authuser);
let dateAuthenticated1 = await identity.lastAuthenticated(authuser);
await increaseTime(10);
await identity.authenticate(authuser);
let dateAuthenticated2 = await identity.lastAuthenticated(authuser);
expect(dateAuthenticated2.toNumber() - dateAuthenticated1.toNumber()).gt(0);
});
it("should add identity admin", async () => {
let outsider = signers[5].address;
await identity.grantRole(await identity.IDENTITY_ADMIN_ROLE(), outsider);
expect(await identity.hasRole(await identity.IDENTITY_ADMIN_ROLE(), outsider)).true;
});
it("should remove identity admin", async () => {
let outsider = signers[5].address;
await identity.revokeRole(await identity.IDENTITY_ADMIN_ROLE(), outsider);
expect(await identity.hasRole(await identity.IDENTITY_ADMIN_ROLE(), outsider)).false;
});
it("should revert when adding to whitelisted twice", async () => {
let whitelisted = signers[1];
await identity.addWhitelisted(whitelisted.address);
await expect(identity.addWhitelisted(whitelisted.address)).reverted;
await identity.removeWhitelisted(whitelisted.address);
});
it("should not increment whitelisted counter when adding whitelisted", async () => {
let whitelisted = signers[1];
await identity.addWhitelisted(whitelisted.address);
let whitelistedCount = await identity.whitelistedCount();
await expect(identity.addWhitelisted(whitelisted.address)).reverted;
let whitelistedCountNew = await identity.whitelistedCount();
expect(whitelistedCountNew).to.be.equal(whitelistedCount).gt(0);
await identity.removeWhitelisted(whitelisted.address);
});
it("should renounce whitelisted", async () => {
let whitelisted = signers[1];
await identity.addWhitelisted(whitelisted.address);
expect(await identity.isWhitelisted(whitelisted.address)).true;
await identity.connect(whitelisted).renounceWhitelisted();
expect(await identity.isWhitelisted(whitelisted.address)).false;
});
it("should add with did", async () => {
let whitelisted = signers[1];
await identity.addWhitelistedWithDID(whitelisted.address, "testString");
const id = await identity.identities(whitelisted.address);
expect(id.did).to.be.equal("testString");
});
it("should not allow adding with used did", async () => {
let whitelisted2 = signers[2];
await expect(identity.addWhitelistedWithDID(whitelisted2.address, "testString")).revertedWith(
/DID already registered/
);
});
it("should not allow adding non contract to contracts", async () => {
let outsider = signers[0];
await expect(identity.addContract(outsider.address)).revertedWith(/Given address is not a contract/);
});
it("should add contract to contracts", async () => {
await identity.addContract(gd.address);
const wasAdded = await identity.isDAOContract(gd.address);
expect(wasAdded).to.be.true;
});
const connectedFixture = async () => {
const toconnect = signers[10];
const toconnect2 = signers[11];
let whitelisted = signers[1];
await identity.connect(whitelisted).connectAccount(toconnect.address);
await identity.connect(whitelisted).connectAccount(toconnect2.address);
return {};
};
it("should allow to connect account", async () => {
const toconnect = signers[10];
let whitelisted = signers[1];
expect(await identity.getWhitelistedRoot(toconnect.address)).eq(ethers.constants.AddressZero);
await loadFixture(connectedFixture);
expect(await identity.getWhitelistedRoot(whitelisted.address)).eq(whitelisted.address);
expect(await identity.getWhitelistedRoot(toconnect.address)).eq(whitelisted.address);
});
it("should not allow to connect account already whitelisted", async () => {
await loadFixture(connectedFixture);
await identity.addWhitelisted(signers[2].address);
let whitelisted = signers[1];
await expect(identity.connect(whitelisted).connectAccount(signers[2].address)).revertedWith(/invalid account/);
});
it("should allow to disconnect account by owner or connected", async () => {
await loadFixture(connectedFixture);
const connected = signers[10];
const whitelisted = signers[1];
await identity.connect(connected).disconnectAccount(connected.address);
expect(await identity.getWhitelistedRoot(connected.address)).eq(ethers.constants.AddressZero);
await loadFixture(connectedFixture);
await identity.connect(whitelisted).disconnectAccount(connected.address);
expect(await identity.getWhitelistedRoot(connected.address)).eq(ethers.constants.AddressZero);
});
it("should not allow to disconnect account not by owner or by connected", async () => {
await loadFixture(connectedFixture);
const connected = signers[10];
const whitelisted = signers[1];
await expect(identity.disconnectAccount(connected.address)).revertedWith(/unauthorized/);
});
it("should not allow to connect to an already connected account", async () => {
await loadFixture(connectedFixture);
await identity.addWhitelisted(signers[2].address);
expect(await identity.isWhitelisted(signers[2].address)).true;
const connected = signers[10];
await expect(identity.connect(signers[2]).connectAccount(connected.address)).revertedWith(/already connected/);
});
it("should return same root for multiple connected accounts", async () => {
await loadFixture(connectedFixture);
const connected = signers[10];
const connected2 = signers[11];
const whitelisted = signers[1];
expect(await identity.getWhitelistedRoot(connected.address))
.eq(await identity.getWhitelistedRoot(connected2.address))
.eq(whitelisted.address);
});
it("should add whitelisted with orgchain and dateauthenticated", async () => {
await loadFixture(connectedFixture);
const toWhitelist = signers[2];
const ts = (Date.now() / 1000 - 100000).toFixed(0);
await identity.addWhitelistedWithDIDAndChain(toWhitelist.address, "xxx", 1234, ts);
const record = await identity.identities(toWhitelist.address);
expect(record.whitelistedOnChainId).eq(1234);
expect(record.dateAuthenticated).eq(ts);
});
const oldidFixture = async () => {
const newid = (await upgrades.deployProxy(await ethers.getContractFactory("IdentityV4"), [
founder.address,
identity.address
])) as IdentityV4;
await identity.grantRole(await identity.IDENTITY_ADMIN_ROLE(), newid.address);
await identity.addBlacklisted(signers[4].address);
await identity.addContract(identity.address);
await identity.removeWhitelisted(signers[3].address);
await identity.addWhitelistedWithDID(signers[3].address, "testolddid");
return { newid };
};
it("should upgrade v3 to v4", async () => {
const impl = (await ethers.deployContract("IdentityV4", [])) as IdentityV4;
const upgradeCall = impl.interface.encodeFunctionData("setReverifyDaysOptions", [[6, 15, 30]]);
const encoded = identity.interface.encodeFunctionData("upgradeToAndCall", [impl.address, upgradeCall]);
await genericCall(identity.address, encoded);
expect(await identity.reverifyDaysOptions(0)).to.equal(6);
expect(await identity.reverifyDaysOptions(1)).to.equal(15);
expect(await identity.reverifyDaysOptions(2)).to.equal(30);
const oldid = (await upgrades.deployProxy(await ethers.getContractFactory("IdentityV3"), [
founder.address,
ethers.constants.AddressZero
])) as IdentityV3;
await oldid.initDAO(await identity.nameService());
await genericCall(oldid.address, encoded);
const upgraded = await ethers.getContractAt("IdentityV4", oldid.address);
expect(await upgraded.reverifyDaysOptions(0)).to.equal(6);
expect(await upgraded.reverifyDaysOptions(1)).to.equal(15);
expect(await upgraded.reverifyDaysOptions(2)).to.equal(30);
});
it("should default to old identity isWhitelisted, isBlacklisted, isContract", async () => {
const { newid } = await loadFixture(oldidFixture);
expect(await (await identity.identities(signers[3].address)).did).eq("testolddid");
expect(await (await newid.identities(signers[3].address)).did).eq("");
expect(await identity.addrToDID(signers[3].address)).eq("testolddid");
expect(await newid.addrToDID(signers[3].address)).eq("testolddid");
expect(await newid.isBlacklisted(signers[4].address)).true;
expect(await newid.isWhitelisted(signers[3].address)).true;
expect(await newid.isDAOContract(identity.address)).true;
});
it("should remove whitelisted,blacklisted,contract from old identity", async () => {
const { newid } = await loadFixture(oldidFixture);
await newid.removeBlacklisted(signers[4].address);
await newid.removeWhitelisted(signers[3].address);
await newid.removeContract(identity.address);
expect(await newid.addrToDID(signers[3].address)).eq("");
expect(await newid.isBlacklisted(signers[4].address)).false;
expect(await newid.isWhitelisted(signers[3].address)).false;
expect(await newid.isDAOContract(identity.address)).false;
expect(await identity.isBlacklisted(signers[4].address)).false;
expect(await identity.isWhitelisted(signers[3].address)).false;
expect(await identity.isDAOContract(identity.address)).false;
});
it("should not set did if set in oldidentity", async () => {
const { newid } = await loadFixture(oldidFixture);
await expect(newid.connect(signers[1])["setDID(address,string)"](signers[1].address, "testolddid")).revertedWith(
/DID already registered oldIdentity/
);
});
it("should set did if set in oldidentity by same owner", async () => {
const { newid } = await loadFixture(oldidFixture);
await expect(newid.connect(signers[3])["setDID(address,string)"](signers[3].address, "testolddid")).not.reverted;
expect(await newid.addrToDID(signers[3].address)).eq("testolddid");
});
it("should set did if set in oldidentity by different owner but updated in new identity", async () => {
const { newid } = await loadFixture(oldidFixture);
await expect(newid.connect(signers[3])["setDID(address,string)"](signers[3].address, "newdid")).not.reverted;
expect(await newid.addrToDID(signers[3].address)).eq("newdid");
await expect(newid.connect(signers[1])["setDID(address,string)"](signers[1].address, "testolddid")).not.reverted;
expect(await newid.addrToDID(signers[1].address)).eq("testolddid");
});
it("should let admin setDID", async () => {
await expect(identity["setDID(address,string)"](signers[1].address, "admindid")).not.reverted;
expect(await identity.addrToDID(signers[1].address)).eq("admindid");
await expect(identity.connect(signers[2])["setDID(address,string)"](signers[1].address, "admindid")).reverted;
});
it("should be registered for v1 compatability", async () => {
expect(await identity.isRegistered()).true;
});
// New tests added below ---------------------------------------------------
it("should allow identity admin to set reverifyDaysOptions and reject empty", async () => {
// admin (default signer) sets new schedule
await expect(identity.setReverifyDaysOptions([2, 5, 10])).not.reverted;
expect(await identity.reverifyDaysOptions(0)).to.equal(2);
expect(await identity.reverifyDaysOptions(1)).to.equal(5);
expect(await identity.reverifyDaysOptions(2)).to.equal(10);
// empty options should revert
await expect(identity.setReverifyDaysOptions([])).revertedWith("empty options");
});
it("non-admin should not set reverifyDaysOptions", async () => {
await expect(identity.connect(signers[2]).setReverifyDaysOptions([1, 7, 180])).revertedWith(
/AccessControl: account/
);
});
it("should follow reverify schedule and cycle authCount", async () => {
// set timestamp to a fixed point (now) to avoid exclusion of old users
// due to initialDate set in hardhat config
const block = await ethers.provider.getBlock("latest");
await time.setNextBlockTimestamp(Number((Date.now() / 1000).toFixed(0)));
await expect(identity.setReverifyDaysOptions([1, 7, 180])).not.reverted;
const u = signers[12];
// ensure a fresh account is whitelisted
await identity.addWhitelisted(u.address);
let record = await identity.identities(u.address);
expect(record.authCount).to.equal(0);
// default reverifyDaysOptions set in initialize: [1,7,180]
// move forward 2 days (past first reverify day)
await increaseTime(2 * 24 * 3600);
expect(await identity.isWhitelisted(u.address)).to.be.false;
// admin authenticates -> should increment authCount to 1
await identity.authenticate(u.address);
record = await identity.identities(u.address);
expect(record.authCount).to.equal(1);
expect(await identity.isWhitelisted(u.address)).to.be.true;
// move forward 8 days (past second reverify day = 7)
await increaseTime(8 * 24 * 3600);
expect(await identity.isWhitelisted(u.address)).to.be.false;
// authenticate again -> authCount becomes 2
await identity.authenticate(u.address);
record = await identity.identities(u.address);
expect(record.authCount).to.equal(2);
expect(await identity.isWhitelisted(u.address)).to.be.true;
// move forward 181 days (past third reverify day = 180)
await increaseTime(181 * 24 * 3600);
expect(await identity.isWhitelisted(u.address)).to.be.false;
// authenticate again -> authCount should wrap back to 0 (cycle)
await identity.authenticate(u.address);
record = await identity.identities(u.address);
expect(record.authCount).to.equal(0);
expect(await identity.isWhitelisted(u.address)).to.be.true;
// cleanup (remove whitelisted) to avoid affecting other tests
await identity.removeWhitelisted(u.address);
// restore time to normal flow
time.setNextBlockTimestamp(block.timestamp);
});
});