UNPKG

@gooddollar/goodprotocol

Version:
926 lines (833 loc) 32.9 kB
// 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); }); }); });