In the contract ARCDVestingVault.sol the function delegate is used to delegate user votes to desired address but it fails to maintain the sanity check if the provided address is a zeroaddress or not
function delegate(address to) external {
ARCDVestingVaultStorage.Grant storage grant = _grants()[msg.sender];
if (to == grant.delegatee) revert AVV_AlreadyDelegated();
...
emit VoteChange(to, msg.sender, int256(uint256(grant.latestVotingPower)));
}
letting users delegate their votes to address(0) (accidentally). One might argue that they can always undo this step by delegating it to an other address but as the previous delegate of this grant now becomes addresszero, this causes the function to revert throwing an error as below
Error: call revert exception; VM Exception while processing transaction: reverted with reason string "Search Failure" [ See: https://links.ethers.org/v5-errors-CALL_EXCEPTION ] (method="queryVotePowerView(address,uint256)", data="0x08c379a00000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000e536561726368204661696c757265000000000000000000000000000000000000", errorArgs=["Search Failure"], errorName="Error", errorSignature="Error(string)", reason="Search Failure", code=CALL_EXCEPTION, version=abi/5.7.0)
copy paste in test\VestingVotingVault.ts and run npx hardhat test --grep βvoting power delegation to zeroaddressβ
describe("voting power delegation to zeroaddress", function(){
it("User changes vote delegation to 0x0", async function () {
const { signers, vestingVotingVault } = ctxGovernance;
const { arcdToken, bootstrapVestingManager } = ctxToken;
const MANAGER = signers[1];
const MANAGER_ADDRESS = signers[1].address;
const OTHER_ADDRESS = signers[0].address;
const OTHER = signers[0];
await bootstrapVestingManager();
// manager deposits tokens
await arcdToken.connect(MANAGER).approve(vestingVotingVault.address, ethers.utils.parseEther("100"));
await vestingVotingVault.connect(MANAGER).deposit(ethers.utils.parseEther("100"));
expect(await arcdToken.balanceOf(vestingVotingVault.address)).to.equal(ethers.utils.parseEther("100"));
// add grant
const currentTime = await ethers.provider.getBlock("latest");
const currentBlock = currentTime.number;
const grantCreatedBlock = currentBlock + 1; // 1 block in the future
const cliff = grantCreatedBlock + 100; // 100 blocks in the future
const expiration = grantCreatedBlock + 200; // 200 blocks in the future
await vestingVotingVault.connect(MANAGER).addGrantAndDelegate(
OTHER_ADDRESS, // recipient
ethers.utils.parseEther("100"), // grant amount
ethers.utils.parseEther("50"), // cliff unlock amount
0, // start time is current block
expiration,
cliff,
OTHER_ADDRESS, // voting power delegate
);
// get grant
const grant = await vestingVotingVault.getGrant(OTHER_ADDRESS);
expect(grant.allocation).to.equal(ethers.utils.parseEther("100"));
expect(grant.cliffAmount).to.equal(ethers.utils.parseEther("50"));
expect(grant.withdrawn).to.equal(0);
expect(grant.created).to.equal(grantCreatedBlock);
expect(grant.expiration).to.equal(expiration);
expect(grant.cliff).to.equal(cliff);
expect(grant.latestVotingPower).to.equal(ethers.utils.parseEther("100"));
expect(grant.delegatee).to.equal(OTHER_ADDRESS);
// check voting power
const checkBlock = await ethers.provider.getBlock("latest");
expect(await vestingVotingVault.queryVotePowerView(OTHER_ADDRESS, checkBlock.number)).to.equal(
ethers.utils.parseEther("100"),
);
// @> //user delegating his votes to zero address
console.log(ethers.constants.AddressZero);
await vestingVotingVault.connect(OTHER).delegate(ethers.constants.AddressZero);
const checkBlock2 = await ethers.provider.getBlock("latest");
expect(await vestingVotingVault.queryVotePowerView(OTHER_ADDRESS, checkBlock2.number)).to.equal(
ethers.utils.parseEther("0"),
);
// @> //user votes have been delegated to zero address
expect(await vestingVotingVault.queryVotePowerView(ethers.constants.AddressZero, checkBlock2.number)).to.equal(
ethers.utils.parseEther("100"),
);
});
});
manual review
consider adding an if check
206: function delegate(address to) external {
ARCDVestingVaultStorage.Grant storage grant = _grants()[msg.sender];
if (to == grant.delegatee) revert AVV_AlreadyDelegated();
@> if (to == address(0)) revert zero_address();
Invalid Validation
The text was updated successfully, but these errors were encountered:
All reactions