Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor: immutable euint64 and skipped test #84

Merged
merged 4 commits into from
Dec 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 12 additions & 20 deletions contracts/governance/ConfidentialERC20Votes.sol
Original file line number Diff line number Diff line change
Expand Up @@ -80,9 +80,7 @@ abstract contract ConfidentialERC20Votes is IConfidentialERC20Votes, Confidentia

/// @notice Constant for zero using TFHE.
/// @dev Since it is expensive to compute 0, it is stored instead.
/// However, is not possible to define it as constant due to TFHE constraints.
/* solhint-disable var-name-mixedcase*/
euint64 private _EUINT64_ZERO;
euint64 private immutable _EUINT64_ZERO;

/**
* @param owner_ Owner address.
Expand Down Expand Up @@ -168,11 +166,7 @@ abstract contract ConfidentialERC20Votes is IConfidentialERC20Votes, Confidentia
revert GovernorInvalid();
}

if (blockNumber >= block.number) {
revert BlockNumberEqualOrHigherThanCurrentBlock();
}

votes = _getPriorVote(account, blockNumber);
votes = getPriorVotes(account, blockNumber);
TFHE.allow(votes, msg.sender);
}

Expand Down Expand Up @@ -223,26 +217,24 @@ abstract contract ConfidentialERC20Votes is IConfidentialERC20Votes, Confidentia
_moveDelegates(currentDelegate, delegatee, delegatorBalance);
}

function _getPriorVote(address account, uint256 blockNumber) internal view returns (euint64 votes) {
function _getPriorVote(address account, uint256 blockNumber) internal view virtual returns (euint64 votes) {
uint32 nCheckpoints = numCheckpoints[account];

if (nCheckpoints == 0) {
/// If there is no checkpoint for the `account`, return encrypted zero.
/// @dev It will not be possible to reencrypt it by the `account`.
votes = _EUINT64_ZERO;
/// @dev If there is no checkpoint for the `account`, return empty handle.
return votes;
} else if (_checkpoints[account][nCheckpoints - 1].fromBlock <= blockNumber) {
/// First, check the most recent balance.
votes = _checkpoints[account][nCheckpoints - 1].votes;
/// @dev First, check the most recent balance.
return _checkpoints[account][nCheckpoints - 1].votes;
} else if (_checkpoints[account][0].fromBlock > blockNumber) {
/// Then, check if there is zero balance.
/// @dev It will not be possible to reencrypt it by the `account`.
votes = _EUINT64_ZERO;
/// @dev Then, check if there is zero balance. If so, return empty handle.
return votes;
} else {
/// Else, search for the voting power at the `blockNumber`.
/// @dev Else, search for the voting power at the `blockNumber`.
uint32 lower = 0;
uint32 upper = nCheckpoints - 1;
while (upper > lower) {
/// Ceil to avoid overflow.
/// @dev Ceil to avoid overflow.
uint32 center = upper - (upper - lower) / 2;
Checkpoint memory cp = _checkpoints[account][center];

Expand All @@ -254,7 +246,7 @@ abstract contract ConfidentialERC20Votes is IConfidentialERC20Votes, Confidentia
upper = center - 1;
}
}
votes = _checkpoints[account][lower].votes;
return _checkpoints[account][lower].votes;
}
}

Expand Down
18 changes: 6 additions & 12 deletions contracts/governance/ConfidentialGovernorAlpha.sol
Original file line number Diff line number Diff line change
Expand Up @@ -227,16 +227,12 @@ abstract contract ConfidentialGovernorAlpha is Ownable2Step, GatewayCaller {
ICompoundTimelock public immutable TIMELOCK;

/// @notice Constant for zero using TFHE.
/// @dev Since it is expensive to compute 0, it is stored instead.
/// However, is not possible to define it as constant due to TFHE constraints.
/* solhint-disable var-name-mixedcase*/
euint64 private _EUINT64_ZERO;
/// @dev Since it is expensive to compute 0, it is stored once instead.
euint64 private immutable _EUINT64_ZERO;

/// @notice Constant for PROPOSAL_THRESHOLD using TFHE.
/// @dev Since it is expensive to compute 0, it is stored instead.
/// However, is not possible to define it as constant due to TFHE constraints.
/* solhint-disable var-name-mixedcase*/
euint64 private _EUINT64_PROPOSAL_THRESHOLD;
/// @dev Since it is expensive to compute the PROPOSAL_THRESHOLD, it is stored once instead.
euint64 private immutable _EUINT64_PROPOSAL_THRESHOLD;

/// @notice The total number of proposals made.
/// It includes all proposals, including the ones that
Expand Down Expand Up @@ -465,10 +461,8 @@ abstract contract ConfidentialGovernorAlpha is Ownable2Step, GatewayCaller {
description
);

ebool canPropose = TFHE.lt(
_EUINT64_PROPOSAL_THRESHOLD,
CONFIDENTIAL_ERC20_VOTES.getPriorVotesForGovernor(msg.sender, block.number - 1)
);
euint64 priorVotes = CONFIDENTIAL_ERC20_VOTES.getPriorVotesForGovernor(msg.sender, block.number - 1);
ebool canPropose = TFHE.lt(_EUINT64_PROPOSAL_THRESHOLD, priorVotes);

uint256[] memory cts = new uint256[](1);
cts[0] = Gateway.toUint256(canPropose);
Expand Down
1 change: 1 addition & 0 deletions hardhat.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ const config: HardhatUserConfig = {
},
networks: {
hardhat: {
gas: "auto",
accounts: {
count: 10,
mnemonic,
Expand Down
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@
},
"dependencies": {
"fhevm": "^0.6.1",
"@openzeppelin/contracts": "^5.0.2",
"@openzeppelin/contracts-upgradeable": "^5.0.2"
"@openzeppelin/contracts": "^5.1.0",
"@openzeppelin/contracts-upgradeable": "^5.1.0"
}
}
26 changes: 13 additions & 13 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

20 changes: 9 additions & 11 deletions test/governance/ConfidentialERC20Votes.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -389,12 +389,12 @@ describe("ConfidentialERC20Votes", function () {
.connect(this.signers.bob)
.getPriorVotes(this.signers.bob.address, latestBlockNumber);

// It is an encrypted constant that is not reencryptable by Bob.
expect(currentVoteHandle).not.to.be.eq(0n);
// The handle is not set.
expect(currentVoteHandle).to.be.eq(0n);

await expect(
reencryptEuint64(this.signers.bob, this.instance, currentVoteHandle, this.confidentialERC20Votes),
).to.be.rejectedWith("Invalid contract address.");
).to.be.rejectedWith("Handle is not initialized");

// 3. If a checkpoint exists using getPriorVotes but block.number < block of first checkpoint
latestBlockNumber = await ethers.provider.getBlockNumber();
Expand All @@ -408,11 +408,11 @@ describe("ConfidentialERC20Votes", function () {
.getPriorVotes(this.signers.bob.address, latestBlockNumber);

// It is an encrypted constant that is not reencryptable by Bob.
expect(currentVoteHandle).not.to.be.eq(0n);
expect(currentVoteHandle).to.eq(0n);

await expect(
reencryptEuint64(this.signers.bob, this.instance, currentVoteHandle, this.confidentialERC20Votes),
).to.be.rejectedWith("Invalid contract address.");
).to.be.rejectedWith("Handle is not initialized");
});

it("can do multiple checkpoints and access the values when needed", async function () {
Expand Down Expand Up @@ -541,18 +541,16 @@ describe("ConfidentialERC20Votes", function () {
);
});

// TODO: fix issue with mining
it.skip("number of checkpoints is incremented once per block, even when written multiple times in same block", async function () {
it("number of checkpoints is incremented once per block, even when written multiple times in same block", async function () {
await network.provider.send("evm_setAutomine", [false]);
await network.provider.send("evm_setIntervalMining", [0]);

// do two checkpoints in same block
const tx1 = this.confidentialERC20Votes.connect(this.signers.alice).delegate(this.signers.bob);
const tx2 = this.confidentialERC20Votes.connect(this.signers.alice).delegate(this.signers.carol);
// @dev There are two checkpoints in the same block.
await this.confidentialERC20Votes.connect(this.signers.alice).delegate(this.signers.bob);
await this.confidentialERC20Votes.connect(this.signers.alice).delegate(this.signers.carol);

await network.provider.send("evm_mine");
await network.provider.send("evm_setAutomine", [true]);
await Promise.all([tx1, tx2]);

expect(await this.confidentialERC20Votes.numCheckpoints(this.signers.alice.address)).to.be.equal(0n);
expect(await this.confidentialERC20Votes.numCheckpoints(this.signers.bob.address)).to.be.equal(1n);
Expand Down
2 changes: 2 additions & 0 deletions test/governance/ConfidentialGovernorAlpha.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1123,6 +1123,8 @@ describe("ConfidentialGovernorAlpha", function () {
"TransactionTooLateForExecution",
);

await mineNBlocks(1);

proposalInfo = await this.governor.getProposalInfo(proposalId);
// 9 ==> Expired
expect(proposalInfo.state).to.equal(9);
Expand Down
Loading