Skip to content
This repository has been archived by the owner on Nov 27, 2024. It is now read-only.

Commit

Permalink
gas
Browse files Browse the repository at this point in the history
  • Loading branch information
dd0sxx committed Dec 16, 2023
1 parent dd2b930 commit d97e1b0
Show file tree
Hide file tree
Showing 6 changed files with 107 additions and 82 deletions.
6 changes: 6 additions & 0 deletions src/lib/LlamaUtils.sol
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,12 @@ library LlamaUtils {
return uint96(n);
}

/// @dev Reverts if `n` does not fit in a `uint128`.
function toUint128(uint256 n) internal pure returns (uint128) {
if (n > type(uint128).max) revert UnsafeCast(n);
return uint128(n);
}

/// @dev Increments a `uint256` without checking for overflow.
function uncheckedIncrement(uint256 i) internal pure returns (uint256) {
unchecked {
Expand Down
10 changes: 5 additions & 5 deletions src/token-voting/LlamaTokenActionCreator.sol
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ contract LlamaTokenActionCreator is Initializable {

/// @dev This contract is deployed as a minimal proxy from the factory's `deploy` function. The
/// `_disableInitializers` locks the implementation (logic) contract, preventing any future initialization of it.
constructor() {
constructor() payable {
_disableInitializers();
}

Expand Down Expand Up @@ -155,7 +155,7 @@ contract LlamaTokenActionCreator is Initializable {
address target,
uint256 value,
bytes calldata data,
string memory description
string calldata description
) external returns (uint256 actionId) {
return _createAction(msg.sender, strategy, target, value, data, description);
}
Expand All @@ -179,7 +179,7 @@ contract LlamaTokenActionCreator is Initializable {
address target,
uint256 value,
bytes calldata data,
string memory description,
string calldata description,
uint8 v,
bytes32 r,
bytes32 s
Expand Down Expand Up @@ -244,7 +244,7 @@ contract LlamaTokenActionCreator is Initializable {
address target,
uint256 value,
bytes calldata data,
string memory description
string calldata description
) internal returns (uint256 actionId) {
// Reverts if clock or CLOCK_MODE() has changed
tokenAdapter.checkIfInconsistentClock();
Expand Down Expand Up @@ -299,7 +299,7 @@ contract LlamaTokenActionCreator is Initializable {
address target,
uint256 value,
bytes calldata data,
string memory description
string calldata description
) internal returns (bytes32) {
// Calculating and storing nonce in memory and using that below, instead of calculating in place to prevent stack
// too deep error.
Expand Down
155 changes: 87 additions & 68 deletions src/token-voting/LlamaTokenCaster.sol
Original file line number Diff line number Diff line change
Expand Up @@ -30,13 +30,13 @@ contract LlamaTokenCaster is Initializable {

/// @dev Cast counts and submission data.
struct CastData {
uint96 votesFor; // Number of votes casted for this action.
uint96 votesAbstain; // Number of abstentions casted for this action.
uint96 votesAgainst; // Number of votes casted against this action.
uint128 votesFor; // Number of votes casted for this action.
uint128 votesAbstain; // Number of abstentions casted for this action.
uint128 votesAgainst; // Number of votes casted against this action.
uint128 vetoesFor; // Number of vetoes casted for this action.
uint128 vetoesAbstain; // Number of abstentions casted for this action.
uint128 vetoesAgainst; // Number of disapprovals casted against this action.
bool approvalSubmitted; // True if the approval was submitted to `LlamaCore, false otherwise.
uint96 vetoesFor; // Number of vetoes casted for this action.
uint96 vetoesAbstain; // Number of abstentions casted for this action.
uint96 vetoesAgainst; // Number of disapprovals casted against this action.
bool disapprovalSubmitted; // True if the disapproval has been submitted to `LlamaCore`, false otherwise.
mapping(address tokenholder => bool) castVote; // True if tokenholder casted a vote, false otherwise.
mapping(address tokenholder => bool) castVeto; // True if tokenholder casted a veto, false otherwise.
Expand Down Expand Up @@ -191,7 +191,7 @@ contract LlamaTokenCaster is Initializable {

/// @dev This contract is deployed as a minimal proxy from the factory's `deploy` function. The
/// `_disableInitializers` locks the implementation (logic) contract, preventing any future initialization of it.
constructor() {
constructor() payable {
_disableInitializers();
}

Expand Down Expand Up @@ -234,7 +234,7 @@ contract LlamaTokenCaster is Initializable {
/// 2 = Abstain
/// @param reason The reason given for the approval by the tokenholder.
/// @return The weight of the cast.
function castVote(ActionInfo calldata actionInfo, uint8 support, string calldata reason) external returns (uint96) {
function castVote(ActionInfo calldata actionInfo, uint8 support, string calldata reason) external returns (uint128) {
return _castVote(msg.sender, actionInfo, support, reason);
}

Expand All @@ -260,7 +260,7 @@ contract LlamaTokenCaster is Initializable {
uint8 v,
bytes32 r,
bytes32 s
) external returns (uint96) {
) external returns (uint128) {
bytes32 digest = _getCastVoteTypedDataHash(caster, actionInfo, support, reason);
address signer = ecrecover(digest, v, r, s);
if (signer == address(0) || signer != caster) revert InvalidSignature();
Expand All @@ -276,7 +276,7 @@ contract LlamaTokenCaster is Initializable {
/// 2 = Abstain
/// @param reason The reason given for the approval by the tokenholder.
/// @return The weight of the cast.
function castVeto(ActionInfo calldata actionInfo, uint8 support, string calldata reason) external returns (uint96) {
function castVeto(ActionInfo calldata actionInfo, uint8 support, string calldata reason) external returns (uint128) {
return _castVeto(msg.sender, actionInfo, support, reason);
}

Expand All @@ -302,7 +302,7 @@ contract LlamaTokenCaster is Initializable {
uint8 v,
bytes32 r,
bytes32 s
) external returns (uint96) {
) external returns (uint128) {
bytes32 digest = _getCastVetoTypedDataHash(caster, actionInfo, support, reason);
address signer = ecrecover(digest, v, r, s);
if (signer == address(0) || signer != caster) revert InvalidSignature();
Expand All @@ -320,30 +320,40 @@ contract LlamaTokenCaster is Initializable {
// Reverts if clock or CLOCK_MODE() has changed
tokenAdapter.checkIfInconsistentClock();

// Checks to ensure it's the submission period.
(uint16 delayPeriodPct, uint16 castingPeriodPct,) =
periodPctsCheckpoint.getAtProbablyRecentTimestamp(action.creationTime - 1);
uint256 approvalPeriod = actionInfo.strategy.approvalPeriod();
uint256 delayPeriodEndTime = action.creationTime + ((approvalPeriod * delayPeriodPct) / ONE_HUNDRED_IN_BPS);
uint256 castingPeriodEndTime = delayPeriodEndTime + ((approvalPeriod * castingPeriodPct) / ONE_HUNDRED_IN_BPS);
if (block.timestamp <= castingPeriodEndTime) revert CannotSubmitYet();
// Doing (action.creationTime + approvalPeriod) vs (castingPeriodEndTime + ((approvalPeriod * submissionPeriodPct) /
// ONE_HUNDRED_IN_BPS)) to prevent any off-by-one errors due to precision loss.
// Llama approval period is inclusive of approval end time.
if (block.timestamp > action.creationTime + approvalPeriod) revert SubmissionPeriodOver();
uint256 delayPeriodEndTime;
uint16 delayPeriodPct;
uint16 castingPeriodPct;

{
// Checks to ensure it's the submission period.
(delayPeriodPct, castingPeriodPct,) = periodPctsCheckpoint.getAtProbablyRecentTimestamp(action.creationTime - 1);
uint256 approvalPeriod = actionInfo.strategy.approvalPeriod();
uint256 castingPeriodEndTime;
unchecked {
delayPeriodEndTime = action.creationTime + ((approvalPeriod * delayPeriodPct) / ONE_HUNDRED_IN_BPS);
castingPeriodEndTime = delayPeriodEndTime + ((approvalPeriod * castingPeriodPct) / ONE_HUNDRED_IN_BPS);
}
if (block.timestamp <= castingPeriodEndTime) revert CannotSubmitYet();
// Doing (action.creationTime + approvalPeriod) vs (castingPeriodEndTime + ((approvalPeriod * submissionPeriodPct)
// /
// ONE_HUNDRED_IN_BPS)) to prevent any off-by-one errors due to precision loss.
// Llama approval period is inclusive of approval end time.
if (block.timestamp > action.creationTime + approvalPeriod) revert SubmissionPeriodOver();
}

CastData storage castData = casts[actionInfo.id];

uint256 totalSupply = tokenAdapter.getPastTotalSupply(tokenAdapter.timestampToTimepoint(delayPeriodEndTime));
uint96 votesFor = casts[actionInfo.id].votesFor;
uint96 votesAgainst = casts[actionInfo.id].votesAgainst;
uint96 votesAbstain = casts[actionInfo.id].votesAbstain;
uint128 votesFor = castData.votesFor;
uint128 votesAgainst = castData.votesAgainst;
(uint16 voteQuorumPct,) = quorumCheckpoints.getAtProbablyRecentTimestamp(action.creationTime - 1);
uint256 threshold = FixedPointMathLib.mulDivUp(totalSupply, voteQuorumPct, ONE_HUNDRED_IN_BPS);
if (votesFor < threshold) revert InsufficientVotes(votesFor, threshold);
if (votesFor <= votesAgainst) revert ForDoesNotSurpassAgainst(votesFor, votesAgainst);

casts[actionInfo.id].approvalSubmitted = true;
castData.approvalSubmitted = true;
llamaCore.castApproval(role, actionInfo, "");
emit ApprovalSubmitted(actionInfo.id, msg.sender, votesFor, votesAgainst, votesAbstain);
emit ApprovalSubmitted(actionInfo.id, msg.sender, votesFor, votesAgainst, castData.votesAbstain);
}

/// @notice Submits a cast disapproval to the `LlamaCore` contract.
Expand All @@ -353,35 +363,44 @@ contract LlamaTokenCaster is Initializable {
Action memory action = llamaCore.getAction(actionInfo.id);

actionInfo.strategy.checkIfDisapprovalEnabled(actionInfo, address(this), role); // Reverts if not allowed.
if (casts[actionInfo.id].disapprovalSubmitted) revert AlreadySubmittedDisapproval();

CastData storage castData = casts[actionInfo.id];

if (castData.disapprovalSubmitted) revert AlreadySubmittedDisapproval();
// Reverts if clock or CLOCK_MODE() has changed
tokenAdapter.checkIfInconsistentClock();

// Checks to ensure it's the submission period.
(uint16 delayPeriodPct, uint16 castingPeriodPct,) =
periodPctsCheckpoint.getAtProbablyRecentTimestamp(action.creationTime - 1);
uint256 queuingPeriod = actionInfo.strategy.queuingPeriod();
uint256 delayPeriodEndTime =
(action.minExecutionTime - queuingPeriod) + ((queuingPeriod * delayPeriodPct) / ONE_HUNDRED_IN_BPS);
uint256 castingPeriodEndTime = delayPeriodEndTime + ((queuingPeriod * castingPeriodPct) / ONE_HUNDRED_IN_BPS);
// Doing (castingPeriodEndTime) vs (action.minExecutionTime - ((queuingPeriod * submissionPeriodPct) /
// ONE_HUNDRED_IN_BPS)) to prevent any off-by-one errors due to precision loss.
if (block.timestamp <= castingPeriodEndTime) revert CannotSubmitYet();
// Llama disapproval period is exclusive of min execution time.
if (block.timestamp >= action.minExecutionTime) revert SubmissionPeriodOver();
uint256 delayPeriodEndTime;

{
// Checks to ensure it's the submission period.
(uint16 delayPeriodPct, uint16 castingPeriodPct,) =
periodPctsCheckpoint.getAtProbablyRecentTimestamp(action.creationTime - 1);
uint256 queuingPeriod = actionInfo.strategy.queuingPeriod();
uint256 castingPeriodEndTime;
unchecked {
delayPeriodEndTime =
(action.minExecutionTime - queuingPeriod) + ((queuingPeriod * delayPeriodPct) / ONE_HUNDRED_IN_BPS);
castingPeriodEndTime = delayPeriodEndTime + ((queuingPeriod * castingPeriodPct) / ONE_HUNDRED_IN_BPS);
}
// Doing (castingPeriodEndTime) vs (action.minExecutionTime - ((queuingPeriod * submissionPeriodPct) /
// ONE_HUNDRED_IN_BPS)) to prevent any off-by-one errors due to precision loss.
if (block.timestamp <= castingPeriodEndTime) revert CannotSubmitYet();
// Llama disapproval period is exclusive of min execution time.
if (block.timestamp >= action.minExecutionTime) revert SubmissionPeriodOver();
}

uint256 totalSupply = tokenAdapter.getPastTotalSupply(tokenAdapter.timestampToTimepoint(delayPeriodEndTime));
uint96 vetoesFor = casts[actionInfo.id].vetoesFor;
uint96 vetoesAgainst = casts[actionInfo.id].vetoesAgainst;
uint96 vetoesAbstain = casts[actionInfo.id].vetoesAbstain;
uint128 vetoesFor = castData.vetoesFor;
uint128 vetoesAgainst = castData.vetoesAgainst;
(, uint16 vetoQuorumPct) = quorumCheckpoints.getAtProbablyRecentTimestamp(action.creationTime - 1);
uint256 threshold = FixedPointMathLib.mulDivUp(totalSupply, vetoQuorumPct, ONE_HUNDRED_IN_BPS);
if (vetoesFor < threshold) revert InsufficientVotes(vetoesFor, threshold);
if (vetoesFor <= vetoesAgainst) revert ForDoesNotSurpassAgainst(vetoesFor, vetoesAgainst);

casts[actionInfo.id].disapprovalSubmitted = true;
castData.disapprovalSubmitted = true;
llamaCore.castDisapproval(role, actionInfo, "");
emit DisapprovalSubmitted(actionInfo.id, msg.sender, vetoesFor, vetoesAgainst, vetoesAbstain);
emit DisapprovalSubmitted(actionInfo.id, msg.sender, vetoesFor, vetoesAgainst, castData.vetoesAbstain);
}

// -------- Instance Management --------
Expand Down Expand Up @@ -415,12 +434,12 @@ contract LlamaTokenCaster is Initializable {

// -------- Getters --------
/// @notice Returns the current voting quorum and vetoing quorum.
function getQuorum() external view returns (uint16 voteQuorumPct, uint16 vetoQuorumPct) {
function getQuorum() external view returns (uint16, uint16) {
return quorumCheckpoints.latest();
}

/// @notice Returns the voting quorum and vetoing quorum at a given timestamp.
function getPastQuorum(uint256 timestamp) external view returns (uint16 voteQuorumPct, uint16 vetoQuorumPct) {
function getPastQuorum(uint256 timestamp) external view returns (uint16, uint16) {
return quorumCheckpoints.getAtProbablyRecentTimestamp(timestamp);
}

Expand All @@ -444,20 +463,12 @@ contract LlamaTokenCaster is Initializable {
}

/// @notice Returns the current delay, casting and submission period ratio.
function getPeriodPcts()
external
view
returns (uint16 delayPeriodPct, uint16 castingPeriodPct, uint16 submissionPeriodPct)
{
function getPeriodPcts() external view returns (uint16, uint16, uint16) {
return periodPctsCheckpoint.latest();
}

/// @notice Returns the delay, casting and submission period ratio at a given timestamp.
function getPastPeriodPcts(uint256 timestamp)
external
view
returns (uint16 delayPeriodPct, uint16 castingPeriodPct, uint16 submissionPeriodPct)
{
function getPastPeriodPcts(uint256 timestamp) external view returns (uint16, uint16, uint16) {
return periodPctsCheckpoint.getAtProbablyRecentTimestamp(timestamp);
}

Expand Down Expand Up @@ -491,7 +502,7 @@ contract LlamaTokenCaster is Initializable {
/// @dev How token holders add their support of the approval of an action with a reason.
function _castVote(address caster, ActionInfo calldata actionInfo, uint8 support, string calldata reason)
internal
returns (uint96)
returns (uint128)
{
Action memory action = llamaCore.getAction(actionInfo.id);

Expand All @@ -504,13 +515,17 @@ contract LlamaTokenCaster is Initializable {
(uint16 delayPeriodPct, uint16 castingPeriodPct,) =
periodPctsCheckpoint.getAtProbablyRecentTimestamp(action.creationTime - 1);
uint256 approvalPeriod = actionInfo.strategy.approvalPeriod();
uint256 delayPeriodEndTime = action.creationTime + ((approvalPeriod * delayPeriodPct) / ONE_HUNDRED_IN_BPS);
uint256 castingPeriodEndTime = delayPeriodEndTime + ((approvalPeriod * castingPeriodPct) / ONE_HUNDRED_IN_BPS);
uint256 delayPeriodEndTime;
uint256 castingPeriodEndTime;
unchecked {
delayPeriodEndTime = action.creationTime + ((approvalPeriod * delayPeriodPct) / ONE_HUNDRED_IN_BPS);
castingPeriodEndTime = delayPeriodEndTime + ((approvalPeriod * castingPeriodPct) / ONE_HUNDRED_IN_BPS);
}
if (block.timestamp <= delayPeriodEndTime) revert VotingDelayNotOver();
if (block.timestamp > castingPeriodEndTime) revert CastingPeriodOver();

uint96 weight =
LlamaUtils.toUint96(tokenAdapter.getPastVotes(caster, tokenAdapter.timestampToTimepoint(delayPeriodEndTime)));
uint128 weight =
LlamaUtils.toUint128(tokenAdapter.getPastVotes(caster, tokenAdapter.timestampToTimepoint(delayPeriodEndTime)));

if (support == uint8(VoteType.Against)) casts[actionInfo.id].votesAgainst += weight;
else if (support == uint8(VoteType.For)) casts[actionInfo.id].votesFor += weight;
Expand All @@ -524,7 +539,7 @@ contract LlamaTokenCaster is Initializable {
/// @dev How token holders add their support of the disapproval of an action with a reason.
function _castVeto(address caster, ActionInfo calldata actionInfo, uint8 support, string calldata reason)
internal
returns (uint96)
returns (uint128)
{
Action memory action = llamaCore.getAction(actionInfo.id);

Expand All @@ -537,14 +552,18 @@ contract LlamaTokenCaster is Initializable {
(uint16 delayPeriodPct, uint16 castingPeriodPct,) =
periodPctsCheckpoint.getAtProbablyRecentTimestamp(action.creationTime - 1);
uint256 queuingPeriod = actionInfo.strategy.queuingPeriod();
uint256 delayPeriodEndTime =
(action.minExecutionTime - queuingPeriod) + ((queuingPeriod * delayPeriodPct) / ONE_HUNDRED_IN_BPS);
uint256 castingPeriodEndTime = delayPeriodEndTime + ((queuingPeriod * castingPeriodPct) / ONE_HUNDRED_IN_BPS);
uint256 delayPeriodEndTime;
uint256 castingPeriodEndTime;
unchecked {
delayPeriodEndTime =
(action.minExecutionTime - queuingPeriod) + ((queuingPeriod * delayPeriodPct) / ONE_HUNDRED_IN_BPS);
castingPeriodEndTime = delayPeriodEndTime + ((queuingPeriod * castingPeriodPct) / ONE_HUNDRED_IN_BPS);
}
if (block.timestamp <= delayPeriodEndTime) revert VotingDelayNotOver();
if (block.timestamp > castingPeriodEndTime) revert CastingPeriodOver();

uint96 weight =
LlamaUtils.toUint96(tokenAdapter.getPastVotes(caster, tokenAdapter.timestampToTimepoint(delayPeriodEndTime)));
uint128 weight =
LlamaUtils.toUint128(tokenAdapter.getPastVotes(caster, tokenAdapter.timestampToTimepoint(delayPeriodEndTime)));

if (support == uint8(VoteType.Against)) casts[actionInfo.id].vetoesAgainst += weight;
else if (support == uint8(VoteType.For)) casts[actionInfo.id].vetoesFor += weight;
Expand Down
2 changes: 1 addition & 1 deletion src/token-voting/LlamaTokenVotingFactory.sol
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ contract LlamaTokenVotingFactory {
LlamaTokenCaster public immutable LLAMA_TOKEN_CASTER_LOGIC;

/// @dev Set the logic contracts used to deploy Token Voting modules.
constructor(LlamaTokenActionCreator LlamaTokenActionCreatorLogic, LlamaTokenCaster LlamaTokenCasterLogic) {
constructor(LlamaTokenActionCreator LlamaTokenActionCreatorLogic, LlamaTokenCaster LlamaTokenCasterLogic) payable {
LLAMA_TOKEN_ACTION_CREATOR_LOGIC = LlamaTokenActionCreatorLogic;
LLAMA_TOKEN_CASTER_LOGIC = LlamaTokenCasterLogic;
}
Expand Down
Loading

0 comments on commit d97e1b0

Please sign in to comment.