@gooddollar/goodprotocol
Version:
GoodDollar Protocol
926 lines (833 loc) • 32.9 kB
text/typescript
// import { GReputationInstance } from "../types/GReputation";
import MerkleTree from "merkletreejs";
import { ethers, upgrades } from "hardhat";
import { loadFixture } from "@nomicfoundation/hardhat-network-helpers";
import { BigNumber, Signer } from "ethers";
import { sign } from "crypto";
import { expect } from "chai";
import { GReputation } from "../../types";
import { SignerWithAddress } from "@nomiclabs/hardhat-ethers/dist/src/signer-with-address";
import { advanceBlocks, createDAO } from "../helpers";
import { TextDecoder } from "util";
const BN = ethers.BigNumber;
export const NULL_ADDRESS = ethers.constants.AddressZero;
type BlockChainState = {
stateHash: string;
hashType: BigNumber;
totalSupply: BigNumber;
blockNumber: BigNumber;
};
export const getMerkleAndProof = async (data, proofIdx) => {
const elements = data.map(e =>
Buffer.from(
ethers.utils
.keccak256(
ethers.utils.defaultAbiCoder.encode(
["address", "uint256"],
[e[0], e[1]]
)
)
.slice(2),
"hex"
)
);
//this will give repOwner minter permissions
await setDAOAddress("GDAO_CLAIMERS", repOwner);
const merkleTree = new MerkleTree(elements, ethers.utils.keccak256);
// get the merkle root
// returns 32 byte buffer
const merkleRoot = merkleTree.getRoot();
// generate merkle proof
// returns array of 32 byte buffers
const proof = merkleTree.getHexProof(elements[proofIdx]);
const isValid = merkleTree.verify(
merkleTree.getPositionalHexProof(elements[proofIdx]),
elements[proofIdx],
merkleRoot
);
return { merkleRoot, proof, isValid, index: proofIdx + 1 };
};
let grep: GReputation, grepWithOwner: GReputation, identity, gd, bounty;
let signers: SignerWithAddress[],
founder,
repOwner,
rep1,
rep2,
rep3,
repTarget,
delegator,
setDAOAddress,
avatar;
const fuseHash = ethers.utils.keccak256(ethers.utils.toUtf8Bytes("fuse"));
describe("GReputation", () => {
let merkleRoot: any, proof: any;
let avatarGenericCall;
before(async () => {
let {
reputation,
setDAOAddress: sda,
avatar: av,
genericCall
} = await loadFixture(createDAO);
setDAOAddress = sda;
avatar = av;
avatarGenericCall = genericCall;
grep = (await ethers.getContractAt(
"GReputation",
reputation
)) as GReputation;
signers = await ethers.getSigners();
[founder, repOwner, rep1, rep2, rep3, repTarget] = signers.map(
_ => _.address
);
delegator = ethers.Wallet.createRandom().connect(ethers.provider);
grepWithOwner = await grep.connect(ethers.provider.getSigner(repOwner));
// create merkle tree
// expects unique 32 byte buffers as inputs (no hex strings)
// if using web3.sha3, convert first -> Buffer(web3.sha3('a'), 'hex')
const merkleData = await getMerkleAndProof(
[
[rep1, 1],
[rep2, 2],
[repTarget, 1],
[rep3, 1]
],
0
);
// get the merkle root
// returns 32 byte buffer
merkleRoot = merkleData.merkleRoot;
// generate merkle proof
// returns array of 32 byte buffers
proof = merkleData.proof;
});
it("should have avatar as role manager", async () => {
expect(await grep.hasRole(await grep.DEFAULT_ADMIN_ROLE(), avatar)).to.be
.true;
});
it("should have name, symbol and decimals", async () => {
expect(await grep.name()).to.equal("GoodDAO");
expect(await grep.symbol()).to.equal("GOOD");
expect(await grep.decimals()).to.equal(18);
});
it("should get balanceOf", async () => {
const repBalance = await grep.balanceOfLocal(founder);
expect(repBalance.toNumber()).to.be.equal(0);
});
it("should not be able to mint or burn if not minter", async () => {
await expect(grep.connect(signers[4]).mint(founder, 2)).to.revertedWith(
/GReputation: need minter role or be GDAO contract/
);
await expect(grep.connect(signers[4]).burn(founder, 2)).to.revertedWith(
/GReputation: need minter role or be GDAO contract/
);
});
describe("rootState", async () => {
it("should set rootState", async () => {
let encodedCall = grep.interface.encodeFunctionData(
"setBlockchainStateHash",
["rootState", "0x" + merkleRoot.toString("hex"), 100]
);
await avatarGenericCall(grep.address, encodedCall);
const rootState = await grep.blockchainStates(await grep.ROOT_STATE(), 0);
expect(rootState[0]).to.be.equal("0x" + merkleRoot.toString("hex"));
});
it("rootState should not change totalsupply until proof", async () => {
expect(await grep.totalSupply()).to.equal(100);
});
it("should update core balances and not change totalsupply after proof of rootState", async () => {
await grep.proveBalanceOfAtBlockchainLegacy(
"rootState",
rep1,
1,
proof,
[],
1
);
//root states changes the core balance
const newRep = await grep.balanceOfLocal(rep1);
expect(newRep.toNumber()).to.be.equal(1);
const newVotes = await grep.getVotes(rep1);
expect(newVotes.toNumber()).to.be.equal(1);
expect(await grep.totalSupply()).to.equal(100); //total supply shouldnt change by proof
});
it("should not set rootState again", async () => {
await setDAOAddress("GDAO_CLAIMERS", repOwner);
await grepWithOwner["mint(address,uint256)"](
founder,
ethers.utils.parseEther("1")
);
let encodedCall = grep.interface.encodeFunctionData(
"setBlockchainStateHash",
["rootState", "0x" + merkleRoot.toString("hex"), 100]
);
const tx = await (
await avatarGenericCall(grep.address, encodedCall)
).wait();
await grepWithOwner["burn(address,uint256)"](
founder,
ethers.utils.parseEther("1")
);
});
it("should reject invalid merkle proof", async () => {
const e = await grep
.proveBalanceOfAtBlockchainLegacy("rootState", rep3, 10, proof, [], 1)
.catch(e => e);
expect(e.message).to.match(/invalid merkle proof/);
});
});
describe("delegation", async () => {
it("should allow delegation", async () => {
expect(await grep.balanceOfLocal(rep3)).to.be.eq(BN.from(0));
await grep.connect(signers[2]).delegateTo(rep3); //rep1 -> rep3
expect(await grep.getVotes(rep3)).to.be.eq(
await grep.balanceOfLocal(rep1)
); //with delegation
expect(
await grep.getVotes(rep1),
"delegator should now have 0 votes"
).to.be.eq(BN.from(0));
expect(await grep.delegateOf(rep1)).to.be.eq(rep3);
});
it("should allow multiple delegates", async () => {
const { merkleRoot, proof } = await getMerkleAndProof(
[
[rep1, 1],
[rep2, 2],
[repTarget, 1],
[rep3, 1]
],
1
);
await grep.proveBalanceOfAtBlockchainLegacy(
"rootState",
rep2,
2,
proof,
[],
2
);
await grep.connect(signers[3]).delegateTo(rep3); //rep2 -> rep3
//verify delegators list has been updated
expect(await grep.delegateOf(rep1)).to.be.eq(rep3);
expect(await grep.delegateOf(rep2)).to.be.eq(rep3);
//verify delegate balance is updated
expect(await grep.getVotes(rep3)).to.be.eq(
BN.from(3) //rep1 + rep2
);
//verify delegators dont have any votes
expect(await grep.getVotes(rep1)).to.be.eq(BN.from(0));
expect(await grep.getVotes(rep2)).to.be.eq(BN.from(0));
});
it("should allow to change delegate", async () => {
expect(await grep.balanceOfLocal(rep1)).to.be.eq(BN.from(1)); //proof was submitted
await grep.connect(signers[3]).delegateTo(rep1); //rep2 -> rep1
expect(await grep.getVotes(rep3)).to.be.eq(BN.from(1)); //previous delegate should now be 1 bcause it has only rep1
expect(await grep.getVotes(rep1)).to.be.eq(
BN.from(2) //rep2
);
expect(await grep.delegates(rep2)).to.be.eq(rep1);
expect(await grep.delegates(rep1)).to.be.eq(rep3);
});
it("should allow undelegation", async () => {
await grep.connect(signers[2]).undelegate(); //rep1 -> remove delegattion to rep3
expect(await grep.balanceOfLocal(rep3)).to.be.eq(BN.from(0));
expect(await grep.getVotes(rep3)).to.be.eq(BN.from(0));
expect(await grep.getVotes(rep1)).to.be.eq(BN.from(3)); //rep2 delegating to rep1 + rep1 votes
expect(await grep.balanceOfLocal(rep1)).to.be.eq(BN.from(1));
expect(await grep.delegates(rep1)).to.be.eq(rep1);
});
it("should update delegate votes after mint to delegate", async () => {
const delegateOf = await grep.delegates(rep2);
const prevVotes = await grep.getVotes(delegateOf);
await grepWithOwner.mint(rep2, 10);
expect(await grep.getVotes(delegateOf)).to.be.eq(prevVotes.add(10));
expect(await grep.delegates(rep1)).to.be.eq(rep1);
});
});
describe("delegateBySig", () => {
const Domain = async gov => ({
name: await grep.name(),
chainId: (await ethers.provider.getNetwork()).chainId,
verifyingContract: grep.address
});
const Types = {
Delegation: [
{ name: "delegate", type: "address" },
{ name: "nonce", type: "uint256" },
{ name: "expiry", type: "uint256" }
]
};
it("reverts if the signatory is invalid", async () => {
const delegate = founder,
nonce = 0,
expiry = 0;
await expect(
grep.delegateBySig(
delegate,
nonce,
expiry,
0,
ethers.utils.hexZeroPad("0xbadd", 32),
ethers.utils.hexZeroPad("0xbadd", 32)
)
).to.revertedWith(/GReputation::delegateBySig: invalid signature/);
});
it("It should not be delegate when delegation address is null", async () => {
let tx = await grep["delegateTo(address)"](NULL_ADDRESS).catch(e => e);
expect(tx.message).to.have.string(
"GReputation::delegate can't delegate to null address"
);
});
it("It should not be able to delegate votes if they are already delagating", async () => {
await grepWithOwner["mint(address,uint256)"](
founder,
ethers.utils.parseEther("1")
);
await grep.delegateTo(rep1);
const tx = await grep.delegateTo(rep1).catch(e => e);
expect(tx.message).to.have.string("already delegating to delegator");
await grepWithOwner["burn(address,uint256)"](
founder,
ethers.utils.parseEther("1")
);
});
it("reverts if the nonce is bad ", async () => {
const delegate = founder,
nonce = 1,
expiry = 0;
const signature = await delegator._signTypedData(
await Domain(grep),
Types,
{
delegate,
nonce,
expiry
}
);
const sig = ethers.utils.splitSignature(signature);
await expect(
grep.delegateBySig(delegate, nonce, expiry, sig.v, sig.r, sig.s)
).to.revertedWith(/GReputation::delegateBySig: invalid nonce/);
});
it("reverts if the signature has expired", async () => {
const delegate = founder,
nonce = 0,
expiry = 0;
const signature = await delegator._signTypedData(
await Domain(grep),
Types,
{
delegate,
nonce,
expiry
}
);
const sig = ethers.utils.splitSignature(signature);
await expect(
grep.delegateBySig(delegate, nonce, expiry, sig.v, sig.r, sig.s)
).to.revertedWith(/GReputation::delegateBySig: signature expired/);
});
describe("delegates on behalf of the signatory", () => {
let txForGas;
it("should delegate using signature", async () => {
const delegate = founder,
nonce = 0,
expiry = 10e9;
const signature = await delegator._signTypedData(
await Domain(grep),
Types,
{
delegate,
nonce,
expiry
}
);
const sig = ethers.utils.splitSignature(signature);
expect(await grep.delegates(delegator.address)).to.equal(
ethers.constants.AddressZero
);
txForGas = await (
await grep.delegateBySig(delegate, nonce, expiry, sig.v, sig.r, sig.s)
).wait();
expect(await grep.delegates(delegator.address)).to.equal(founder);
});
it("should delegate with X gas [@skip-on-coverage]", async () => {
expect(txForGas.gasUsed).to.lt(130000);
});
});
});
describe("setting a blockchain merkle hash", async () => {
it("should set new merkle hash", async () => {
const { merkleRoot, proof } = await getMerkleAndProof(
[
[rep1, 100],
[rep2, 200],
[repTarget, 1],
[rep3, 1]
],
1
);
let encodedCall = grep.interface.encodeFunctionData(
"setBlockchainStateHash",
["fuse", "0x" + merkleRoot.toString("hex"), 200]
);
const totalSupply = await grep.totalSupply();
await expect(avatarGenericCall(grep.address, encodedCall)).to.not.be
.reverted;
const totalAfterSupply = await grep.totalSupply();
expect(totalAfterSupply).to.eq(totalSupply.add(200));
});
it("should modify only local totalSupply on burn mint", async () => {
const totalSupply = await grep.totalSupply();
await grepWithOwner["mint(address,uint256)"](founder, 155);
const totalSupplyAfter = await grep.totalSupply();
expect(totalSupplyAfter).to.eq(totalSupply.add(155));
});
it("should not reset core balance", async () => {
//before proving new rep in new root balance should be 0
const newRep = await grep.balanceOfLocal(rep1);
expect(newRep.toNumber()).to.be.gt(0);
const newRep2 = await grep.balanceOfLocal(rep2);
expect(newRep2.toNumber()).to.be.gt(0);
});
it("should prove balance in new state", async () => {
const prevRep = await grep.balanceOfLocal(rep2);
const prevVotes = await grep.getVotes(rep2);
const { proof } = await getMerkleAndProof(
[
[rep1, 100],
[rep2, 200],
[repTarget, 1],
[rep3, 1]
],
1
);
await grep.proveBalanceOfAtBlockchainLegacy(
"fuse",
rep2,
200,
proof,
[],
2
);
const newRep = await grep.balanceOfLocal(rep2);
expect(newRep).to.be.equal(prevRep); //core rep should not change
const newVotes = await grep.getVotes(rep2);
expect(newVotes).to.be.equal(prevVotes.add(200));
});
it("should keep active votes (local balance) correctly after mint/burn", async () => {
await grep.connect(signers[3]).undelegate();
const totalSupply = await grep.getCurrentVotes(rep2);
const tx = await grepWithOwner["mint(address,uint256)"](rep2, 155);
const result = await tx.wait();
const totalSupplyAfter = await grep.getVotes(rep2);
expect(totalSupplyAfter).to.eq(totalSupply.add(155));
});
it("should only delegate core balance and not new state balance", async () => {
expect(await grep.getVotes(rep3)).to.be.eq(BN.from(0));
await grep.connect(signers[3]).delegateTo(rep3); //rep2=signers[3]
expect(await grep.getVotes(rep3)).to.be.eq(
await grep.balanceOfLocal(rep2)
);
expect(await grep.getVotes(rep3)).to.be.lt(await grep.getVotes(rep2));
});
it("should not effect delegate balance after new state hash", async () => {
const prevDelegated = await grep.getVotes(rep3);
const { merkleRoot, proof } = await getMerkleAndProof(
[
[rep1, 100],
[rep2, 200],
[rep3, 10],
[repTarget, 1]
],
1
);
let encodedCall = grep.interface.encodeFunctionData(
"setBlockchainStateHash",
["fuse", "0x" + merkleRoot.toString("hex"), 200]
);
await expect(avatarGenericCall(grep.address, encodedCall)).to.not.be
.reverted;
expect(await grep.getVotes(rep3)).to.be.eq(prevDelegated);
});
it("should not effect delegate balance after new blockchain proof", async () => {
const prevVotes = await grep.getVotes(rep3);
const { merkleRoot, proof } = await getMerkleAndProof(
[
[rep1, 100],
[rep2, 200],
[rep3, 10],
[repTarget, 1]
],
1
);
await grep.proveBalanceOfAtBlockchainLegacy(
"fuse",
rep2,
200,
proof,
[],
2
);
expect(await grep.getVotes(rep3)).to.be.eq(prevVotes); //be equal to rep2
});
it("should include own rep in votes balance after new state", async () => {
const prevVotes = await grep.getVotes(rep3);
const { merkleRoot, proof } = await getMerkleAndProof(
[
[rep1, 100],
[rep2, 200],
[rep3, 10],
[repTarget, 1]
],
2
);
await grep.proveBalanceOfAtBlockchainLegacy(
"fuse",
rep3,
10,
proof,
[],
3
);
expect(await grep.getVotes(rep3)).to.be.eq(prevVotes.add(10)); //add new blockchain rep
});
it("should report blockchain balance after proof of new state", async () => {
//before proving new rep in new root balance should be 0
const newRep = await grep.getVotesAtBlockchain(
fuseHash,
rep1,
ethers.constants.MaxUint256
);
expect(newRep.toNumber()).to.be.equal(0); //not prooved
const newRep2 = await grep.getVotesAtBlockchain(
fuseHash,
rep2,
ethers.constants.MaxUint256
);
expect(newRep2.toNumber()).to.be.equal(200);
const newRep3 = await grep.getVotesAtBlockchain(
fuseHash,
rep3,
ethers.constants.MaxUint256
);
expect(newRep3.toNumber()).to.be.equal(10);
});
describe("overriding with a new state hash", async () => {
it("should set a new state hash", async () => {
await expect(
grep.setBlockchainStateHash("fuse", fuseHash, BN.from("100"))
).to.be.revertedWith(/only avatar can call this method/);
let encodedCall = grep.interface.encodeFunctionData(
"setBlockchainStateHash",
["fuse", fuseHash, 100]
);
expect(await avatarGenericCall(grep.address, encodedCall)).to.not.throw;
const first = await grep.activeBlockchains(0);
const state: BlockChainState = (await grep.blockchainStates(
fuseHash,
2 //third state of fuse
)) as unknown as BlockChainState;
expect(first).to.be.equal(fuseHash);
expect(state.stateHash).to.be.equal(fuseHash);
expect(state.totalSupply.toNumber()).to.be.equal(100);
expect(state.blockNumber.toNumber()).to.be.greaterThan(0);
});
it("should reset blockchain balance to 0 before proof of new state", async () => {
//before proving new rep in new root balance should be 0
const newRep = await grep.getVotesAtBlockchain(
fuseHash,
rep1,
ethers.constants.MaxUint256
);
expect(newRep.toNumber()).to.be.equal(0);
const newRep2 = await grep.getVotesAtBlockchain(
fuseHash,
rep2,
ethers.constants.MaxUint256
);
expect(newRep2.toNumber()).to.be.equal(0);
});
it("should return previous state when state.blockNumber > _blockNumber", async () => {
const blockNumber = await ethers.provider.getBlockNumber();
const newRep2 = await grep.getVotesAtBlockchain(
fuseHash,
rep2,
blockNumber - 4
);
expect(newRep2.toNumber()).to.be.equal(200); // returns previous state
});
it("should return another state's total supply when states[uint256(i)].blockNumber > _blockNumber in totalSupplyAtBlockchain", async () => {
const blockNumber = await ethers.provider.getBlockNumber();
const newRep2 = await grep.totalSupplyAtBlockchain(
fuseHash,
blockNumber - 4
);
});
});
});
describe("real example of airdrop", async () => {
let startSupply = ethers.constants.Zero;
before(async () => {
startSupply = await grep.totalSupply();
});
it("should set a new state hash", async () => {
let encodedCall = grep.interface.encodeFunctionData(
"setBlockchainStateHash",
[
"realState",
"0x2c6122d5343ba909417d15ad20cc796c11fb8d25a16b2280d1c9f338dee228f2",
ethers.utils.parseEther("96000000")
]
);
expect(await avatarGenericCall(grep.address, encodedCall)).to.not.throw;
expect(await grep.totalSupply()).to.eq(
startSupply.add(ethers.utils.parseEther("96000000"))
);
});
it("should prove real proof", async () => {
const prevVotes = await grep.getVotes(
"0xf79b804bae955ae4cd8e8b0331c4bc437104804f"
);
const proof = [
"0x9b8e7febcbd180034badae99ecbab673459fb0c0737b9cad212c3937f56e4585",
"0xd10d8ef972acbc30a43739c4701a2b6e4c519ce346a62df26bec7b5997445627",
"0xbd5dd5fed6f798a47ea020b57132471b5d46a2b65d0acbd4e230a072c3e3a55c",
"0x9f23c9cf88be7e52235387e276e29b7d6c51534e9d59c2a65a21952fd88900c7",
"0xfdfe22fe05bce861932bfa4578051c71f2e7b54db33234e5272b4301438a8d8f",
"0x5656593fc2eb9bcd304ec0447e592997a99ebecdc2659f220ff635baa285ecfa",
"0xaec1054c23f27e94d187f812e1f4dd5edf7f6e718a8cb2f626b1d8c36d11b0c7",
"0x092d517b71b26e46666b7495f585a85edba242fc5b1ae3fa92270d1c2a902456",
"0x0b4cb632876d934c4a6765fd5d1feea130cf157789c21963d44b1efcc2978c21",
"0x723c9e86aa78f12110fe81d12df83e78dd7615522e26fb970e2a5d3f4274132f",
"0x0bb4f0a903802cc0c3bb7462c2511faff05f8c10d702944d36554319049489ab",
"0x67b4b760b618e92a01f28e6e642d97edc815eae9aedc5e2d379d27846807ac9f",
"0x532d257a230e24572128456bf10346e4a44c85f86f6adff6bc869557f76dc004",
"0x095fcd1d64eaf81d5b94e14bbe890495b45e9cbf6fb0207c11e5e7b235994622",
"0x831b4cbc31413fc036cb47497ebb3131c1fe68a1643b9b4dd574bc917db0dc93",
"0xc3c5c42fce820bc86269c682690932873e9fb69129e6184ce4896dbd7de91e96",
"0x1b6439ad44cfdfcf0238bd6bec094b4da9767432dd026ec7936a7bb2901d3428",
"0x6c8e26b04a1bdd3eb15e76dd4de8b3b097759bcf1a2e568b4847a4ef9a70602e"
];
const rep = ethers.utils.parseEther("21492275.377107453");
await grep.proveBalanceOfAtBlockchainLegacy(
"realState",
"0xf79b804bae955ae4cd8e8b0331c4bc437104804f",
rep,
proof,
[],
1
);
expect(
await grep.getVotes("0xf79b804bae955ae4cd8e8b0331c4bc437104804f")
).to.be.eq(prevVotes.add(rep)); //add new blockchain rep
expect(await grep.totalSupply()).to.eq(
startSupply.add(ethers.utils.parseEther("96000000"))
);
});
it("should prove real proof of last index", async () => {
const prevVotes = await grep.getVotes(
"0x68b064891efb77b87fe1e872205e795f75a72a6d"
);
const proof = [
"0xb23becc094bb77b57b02efa3223a97c5c2f179e419ad1cd197bdf716ba35e2ab",
"0x64c2f7c557e1388282802a530489b6328e04300c5d97df9e90150bde1dbcecff",
"0xfc72b1c90592c448f908aea27bf3b6ad2bbb0264686c0c4cb780f784dfd661e1",
"0x28cb29a5f16d4ad5e1690a7b78a8b139a200120558e33c4157477c715a448ae4",
"0x635293d19ad0cad71df6bfa1e214b52866ef5f1953f97d6d013704e23c8a3abf",
"0x6176e5fed3f84225bb522cd6d3af0ff39515cd6c2f8fa088dd64e1eb5554cad9",
"0x4dd623274305ba776ebbff19fcd5942bff2c823413d54a456fd5defe52bc505d",
"0xbee9e989bf2cc76791c93ac8783e249b382f41ac283d01fcf3aca8434697db83",
"0x7bd84a4af41fd85d87106def7f3504262f12963c2be51344f49a0dc8da0b370d",
"0xa3a60333331cd727f58058926a64de5031600482e6f59804dd3dd7a3a36c104a",
"0x1445a9ef548502e693fc9561c082d53258c00b4f6e475e835c4397ce72e9283d",
"0x3b602cb425eefe45feb2c9944e094c8f7cb3cc28336948e976b7999f4d805c9f",
"0x46e9fa8d0157acbd5891643c3d16ddc9dcb67cbd0c5cd0cd289b01c6e2fd93fc"
];
const rep = 139216138927630;
await grep.proveBalanceOfAtBlockchainLegacy(
"realState",
"0x68b064891efb77b87fe1e872205e795f75a72a6d",
rep,
proof,
[],
238576
);
expect(
await grep.getVotes("0x68b064891efb77b87fe1e872205e795f75a72a6d")
).to.be.eq(prevVotes.add(rep)); //add new blockchain rep
expect(await grep.totalSupply()).to.eq(
startSupply.add(ethers.utils.parseEther("96000000"))
);
});
it("it should be able get votes at the specific block", async () => {
const rep = ethers.utils.parseEther("21492275.377107453");
let currentBlock = await ethers.provider.getBlockNumber();
let votes = await grep["getVotesAt(address,uint256)"](
"0xf79b804bae955ae4cd8e8b0331c4bc437104804f",
currentBlock
);
expect(votes).to.be.equal(rep);
});
it("it should be able to get totalSupply for particular block", async () => {
let currentSupply = await grep["totalSupply()"]();
let localSupply = await grep.totalSupplyLocalAt(
await ethers.provider.getBlockNumber()
);
await grepWithOwner["mint(address,uint256)"](
founder,
ethers.utils.parseEther("1")
);
let currentBlock = await ethers.provider.getBlockNumber();
let totalSupply = await grep.totalSupplyAt(currentBlock);
expect(await grep.totalSupplyLocalAt(currentBlock)).to.equal(
localSupply.add(ethers.utils.parseEther("1"))
);
expect(
totalSupply
.sub(currentSupply)
.sub(ethers.utils.parseEther("1"))
.toString()
).to.be.equal("0");
await grepWithOwner["burn(address,uint256)"](
founder,
ethers.utils.parseEther("1")
);
});
it("it should be able to get totalSupplyLocal for particular block", async () => {
let currentBlock = await ethers.provider.getBlockNumber();
const totalSupplyLocalBefore = await grep["totalSupplyLocal(uint256)"](
currentBlock
);
await grepWithOwner["mint(address,uint256)"](
founder,
ethers.utils.parseEther("1")
);
currentBlock = await ethers.provider.getBlockNumber();
const totalSupplyLocalAfter = await grep["totalSupplyLocal(uint256)"](
currentBlock
);
expect(totalSupplyLocalAfter).to.equal(
totalSupplyLocalBefore.add(ethers.utils.parseEther("1"))
);
await grepWithOwner["burn(address,uint256)"](
founder,
ethers.utils.parseEther("1")
);
});
it("it should return 0 when particular blockchain state is empty", async () => {
let state = await grep["getVotesAtBlockchain(bytes32,address,uint256)"](
ethers.utils.keccak256(ethers.utils.toUtf8Bytes("notExist")),
"0xe28f701A8a94E18220A5d800Bb06ae20e8eDd6c8",
"300"
);
expect(state.toString()).to.be.equal("0");
});
it("It should not be able to get total supply when particular blockchain state is empty", async () => {
let state = await grep["totalSupplyAtBlockchain(bytes32,uint256)"](
ethers.utils.keccak256(ethers.utils.toUtf8Bytes("notExist")),
"300"
);
expect(state.toString()).to.be.equal("0");
});
it("it should prove balance of blockchain for particular chain only once", async () => {
const proof = [
"0x9b8e7febcbd180034badae99ecbab673459fb0c0737b9cad212c3937f56e4585",
"0xd10d8ef972acbc30a43739c4701a2b6e4c519ce346a62df26bec7b5997445627",
"0xbd5dd5fed6f798a47ea020b57132471b5d46a2b65d0acbd4e230a072c3e3a55c",
"0x9f23c9cf88be7e52235387e276e29b7d6c51534e9d59c2a65a21952fd88900c7",
"0xfdfe22fe05bce861932bfa4578051c71f2e7b54db33234e5272b4301438a8d8f",
"0x5656593fc2eb9bcd304ec0447e592997a99ebecdc2659f220ff635baa285ecfa",
"0xaec1054c23f27e94d187f812e1f4dd5edf7f6e718a8cb2f626b1d8c36d11b0c7",
"0x092d517b71b26e46666b7495f585a85edba242fc5b1ae3fa92270d1c2a902456",
"0x0b4cb632876d934c4a6765fd5d1feea130cf157789c21963d44b1efcc2978c21",
"0x723c9e86aa78f12110fe81d12df83e78dd7615522e26fb970e2a5d3f4274132f",
"0x0bb4f0a903802cc0c3bb7462c2511faff05f8c10d702944d36554319049489ab",
"0x67b4b760b618e92a01f28e6e642d97edc815eae9aedc5e2d379d27846807ac9f",
"0x532d257a230e24572128456bf10346e4a44c85f86f6adff6bc869557f76dc004",
"0x095fcd1d64eaf81d5b94e14bbe890495b45e9cbf6fb0207c11e5e7b235994622",
"0x831b4cbc31413fc036cb47497ebb3131c1fe68a1643b9b4dd574bc917db0dc93",
"0xc3c5c42fce820bc86269c682690932873e9fb69129e6184ce4896dbd7de91e96",
"0x1b6439ad44cfdfcf0238bd6bec094b4da9767432dd026ec7936a7bb2901d3428",
"0x6c8e26b04a1bdd3eb15e76dd4de8b3b097759bcf1a2e568b4847a4ef9a70602e"
];
const rep = ethers.utils.parseEther("21492275.377107453");
const tx = await grep
.proveBalanceOfAtBlockchainLegacy(
"realState",
"0xf79b804bae955ae4cd8e8b0331c4bc437104804f",
rep,
proof,
[],
1
)
.catch(e => e);
expect(tx.message).to.have.string("stateHash already proved");
});
it("It should not prove balance of blockchain if particular chain does not exist", async () => {
const proof = [
"0x6429597531910c38ed2ac8f73a890245ef7f67db49e1a947049fe8d987b0ee09",
"0x2225a8a896fbfc6d8b9d15574ff43d6025a1e811b790df431b84e08dc3287ce4",
"0xa83c67b8ca77de2b6cd01571d03d21a61df664f8128c805b1b27c202862ac5f8",
"0xb11cfc679f76ed949270ef345f8268571b9ed317f25970332a0e0fb3a4feaea8",
"0xb93eefff7353452bcb68e1af11b94ac4aa0f59e3dc6770027a7f9ac3a8d55d87",
"0xed638b497e00aec652c528d142de5f261238cf99395c93472820bcd8b55ef5bb",
"0xfa3ef97384d7e03d0980873fd18ec3ae7f57d266f4d6495e631257c5b5c11081",
"0x66cbd6385735911728866e1208db6ca94698c6ef726dd06334e80d81cf0e59e4",
"0xf6c5fbaf4bd80f598dae62ca88af460bbdc618739959c1f0a00a8ecabe2be51d",
"0x9fba3d9d96b8c268d322548cc41b1c9bb37b8bf7108184fc33784b3f089f45dc",
"0x0582b0084b238128163879a707f336e6932ce8ddcfe1fdfce9dbc37ab7c430a5",
"0x278db5f9072c404b1d8d9baba030c171943a4a5cdc51e8c9b21fee01f2fe32bd",
"0xe3d136bf3ea1fbed0055294cd43a0fd4b52d6388ecb524627a88b73db57a3429",
"0x2c8245c2d4c0e4ac0ae22754005d62d994aabe2bdb05f46cfe3ac63a4bf72a32"
];
let tx = await grep
.proveBalanceOfAtBlockchainLegacy(
"notExist",
"0xe28f701A8a94E18220A5d800Bb06ae20e8eDd6c8",
1199,
proof,
[],
1
)
.catch(e => e);
expect(tx.message).to.have.string("no state found for given _id");
});
});
describe("reputation recipient", () => {
it("user should be able to set recipient", async () => {
await grep.connect(signers[4]).setReputationRecipient(repTarget);
expect(await grep.reputationRecipients(rep3)).to.equal(repTarget);
await grepWithOwner.mint(rep3, 111);
expect(await grep.balanceOfLocal(repTarget)).to.equal(111);
});
it("user should be able to unset recipient", async () => {
const startBalance = await grep.balanceOfLocal(rep3);
await grep
.connect(signers[4])
.setReputationRecipient(ethers.constants.AddressZero);
expect(await grep.reputationRecipients(rep3)).to.equal(
ethers.constants.AddressZero
);
await grepWithOwner.mint(rep3, 111);
expect(await grep.balanceOfLocal(repTarget)).to.equal(111);
expect(await grep.balanceOfLocal(rep3)).to.equal(startBalance.add(111));
});
it("should get accurate prior votes", async () => {
await grep.connect(signers[3]).undelegate();
const selectedBlock = await ethers.provider.getBlockNumber();
const selectedBlockVotes = await grep.getCurrentVotes(rep2);
await advanceBlocks(1);
await (await grepWithOwner["mint(address,uint256)"](rep2, 1)).wait();
await advanceBlocks(1);
const priorSelectedBlockVotes = await grep.getPriorVotes(
rep2,
selectedBlock
);
const votesAfterAdvancing = await grep.getCurrentVotes(rep2);
expect(priorSelectedBlockVotes).to.eq(selectedBlockVotes);
expect(priorSelectedBlockVotes).to.be.not.eq(votesAfterAdvancing);
});
});
});