Skip to content

Commit

Permalink
WIP plugin split
Browse files Browse the repository at this point in the history
  • Loading branch information
brickpop committed Jan 12, 2025
1 parent 1d8ad34 commit e1789b1
Show file tree
Hide file tree
Showing 6 changed files with 56 additions and 38 deletions.
12 changes: 6 additions & 6 deletions src/LockToVotePlugin.sol → src/LockToVoteSinglePlugin.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
pragma solidity ^0.8.13;

import {ILockManager} from "./interfaces/ILockManager.sol";
import {ILockToVote, LockToVoteSettings, Proposal, ProposalParameters} from "./interfaces/ILockToVote.sol";
import {ILockToVoteSingle, LockToVoteSingleSettings, Proposal, ProposalParameters} from "./interfaces/ILockToVote.sol";
import {IDAO} from "@aragon/osx-commons-contracts/src/dao/IDAO.sol";
import {ProposalUpgradeable} from "@aragon/osx-commons-contracts/src/plugin/extensions/proposal/ProposalUpgradeable.sol";
import {IMembership} from "@aragon/osx-commons-contracts/src/plugin/extensions/membership/IMembership.sol";
Expand All @@ -18,15 +18,15 @@ import {SafeCastUpgradeable} from "@openzeppelin/contracts-upgradeable/utils/mat
import {_applyRatioCeiled} from "@aragon/osx-commons-contracts/src/utils/math/Ratio.sol";

contract LockToVotePlugin is
ILockToVote,
ILockToVoteSingle,
PluginUUPSUpgradeable,
ProposalUpgradeable,
MetadataExtensionUpgradeable,
IMembership
{
using SafeCastUpgradeable for uint256;

LockToVoteSettings public settings;
LockToVoteSingleSettings public settings;

/// @inheritdoc ILockToVote
ILockManager public lockManager;
Expand Down Expand Up @@ -57,7 +57,7 @@ contract LockToVotePlugin is
function initialize(
IDAO _dao,
ILockManager _lockManager,
LockToVoteSettings calldata _pluginSettings,
LockToVoteSingleSettings calldata _pluginSettings,
IPlugin.TargetConfig calldata _targetConfig,
bytes calldata _pluginMetadata
) external onlyCallAtInitialization reinitializer(1) {
Expand Down Expand Up @@ -273,7 +273,7 @@ contract LockToVotePlugin is
}

/// @inheritdoc ILockToVote
function updatePluginSettings(LockToVoteSettings calldata _newSettings)
function updatePluginSettings(LockToVoteSingleSettings calldata _newSettings)
external
auth(UPDATE_VOTING_SETTINGS_PERMISSION_ID)
{
Expand Down Expand Up @@ -395,7 +395,7 @@ contract LockToVotePlugin is
lockManager.proposalEnded(_proposalId);
}

function _updatePluginSettings(LockToVoteSettings memory _newSettings) internal {
function _updatePluginSettings(LockToVoteSingleSettings memory _newSettings) internal {
settings.minApprovalRatio = _newSettings.minApprovalRatio;
settings.minProposalDuration = _newSettings.minProposalDuration;
}
Expand Down
6 changes: 3 additions & 3 deletions src/interfaces/ILockManager.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

pragma solidity ^0.8.17;

import {ILockToVote} from "./ILockToVote.sol";
import {ILockToVoteBase} from "./ILockToVote.sol";
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";

/// @notice Defines whether locked funds can be unlocked at any time or not
Expand All @@ -23,7 +23,7 @@ struct LockManagerSettings {
interface ILockManager {
/// @notice Returns the address of the voting plugin.
/// @return The LockToVote plugin address.
function plugin() external view returns (ILockToVote);
function plugin() external view returns (ILockToVoteBase);

/// @notice Returns the address of the token contract used to determine the voting power.
/// @return The token used for voting.
Expand Down Expand Up @@ -70,5 +70,5 @@ interface ILockManager {
function proposalEnded(uint256 proposalId) external;

/// @notice Defines the given plugin address as the target for voting
function setPluginAddress(ILockToVote _plugin) external;
function setPluginAddress(ILockToVoteBase _plugin) external;
}
44 changes: 31 additions & 13 deletions src/interfaces/ILockToVote.sol
Original file line number Diff line number Diff line change
Expand Up @@ -46,15 +46,15 @@ struct ProposalParameters {
/// @param minApprovalRatio The support threshold value.
/// Its value has to be in the interval [0, 10^6] defined by `RATIO_BASE = 10**6`.
/// @param minProposalDuration The minimum duration of the proposal voting stage in seconds.
struct LockToVoteSettings {
struct LockToVoteSingleSettings {
uint32 minApprovalRatio;
uint64 minProposalDuration;
}

/// @title ILockToVote
/// @author Aragon X
/// @notice Governance plugin allowing token holders to use tokens locked without a snapshot requirement and engage in proposals immediately
interface ILockToVote {
interface ILockToVoteBase {
/// @notice Returns the address of the manager contract, which holds the locked balances and the allocated vote balances.
function lockManager() external view returns (ILockManager);

Expand All @@ -72,14 +72,31 @@ interface ILockToVote {
function isProposalOpen(uint256 _proposalId) external view returns (bool);

/// @notice Returns wether the given address can vote or increase the amount of tokens assigned to a proposal
function canVote(uint256 proposalId, address voter) external view returns (bool);
function canVote(
uint256 proposalId,
address voter
) external view returns (bool);

error NoVotingPower();
error ProposalAlreadyExists(uint256 proposalId);
error DateOutOfBounds(uint256 limit, uint256 actual);
error VoteCastForbidden(uint256 proposalId, address voter);
error ExecutionForbidden(uint256 proposalId);

event Executed(uint256 proposalId);
}

interface ILockToVoteSingle is ILockToVoteBase {
/// @notice Registers an approval vote for the given proposal.
/// @param proposalId The ID of the proposal to vote on.
/// @param voter The address of the account whose vote will be registered
/// @param newVotingPower The new balance that should be allocated to the voter. It can only be bigger.
/// @dev newVotingPower updates any prior voting power, it does not add to the existing amount.
function vote(uint256 proposalId, address voter, uint256 newVotingPower) external;
function vote(
uint256 proposalId,
address voter,
uint256 newVotingPower
) external;

/// @notice Reverts the existing voter's vote, if any.
/// @param proposalId The ID of the proposal.
Expand All @@ -90,19 +107,20 @@ interface ILockToVote {
/// @param proposalId The ID of the proposal.
/// @param voter The account address to be checked.
/// @return The amount of balance that has been allocated to the proposal by the given account.
function usedVotingPower(uint256 proposalId, address voter) external view returns (uint256);
function usedVotingPower(
uint256 proposalId,
address voter
) external view returns (uint256);

/// @notice Updates the voting settings, which will be applied to the next proposal being created.
/// @param newSettings The new settings, including the minimum approval ratio and the minimum proposal duration.
function updatePluginSettings(LockToVoteSettings calldata newSettings) external;

error NoVotingPower();
error ProposalAlreadyExists(uint256 proposalId);
error DateOutOfBounds(uint256 limit, uint256 actual);
error VoteCastForbidden(uint256 proposalId, address voter);
error ExecutionForbidden(uint256 proposalId);
function updatePluginSettings(
LockToVoteSingleSettings calldata newSettings
) external;

event VoteCast(uint256 proposalId, address voter, uint256 newVotingPower);
event VoteCleared(uint256 proposalId, address voter);
event Executed(uint256 proposalId);
}

interface ILockToVoteMajority is ILockToVoteBase {
}
26 changes: 13 additions & 13 deletions test/LockToVote.t.sol → test/LockToVoteSingle.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,14 @@
pragma solidity 0.8.17;

import {AragonTest} from "./util/AragonTest.sol";
import {LockToVotePlugin} from "../src/LockToVotePlugin.sol";
import {LockToVoteSinglePlugin} from "../src/LockToVoteSinglePlugin.sol";
import {LockManager} from "../src/LockManager.sol";
import {LockManagerSettings, UnlockMode} from "../src/interfaces/ILockManager.sol";
import {ILockToVote} from "../src/interfaces/ILockToVote.sol";
import {DaoBuilder} from "./util/DaoBuilder.sol";
import {DAO, IDAO} from "@aragon/osx/src/core/dao/DAO.sol";
import {DaoUnauthorized} from "@aragon/osx-commons-contracts/src/permission/auth/auth.sol";
import {LockToVoteSettings, Proposal, ProposalParameters} from "../src/interfaces/ILockToVote.sol";
import {LockToVoteSingleSettings, Proposal, ProposalParameters} from "../src/interfaces/ILockToVote.sol";
import {TestToken} from "./mocks/TestToken.sol";
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {Action} from "@aragon/osx-commons-contracts/src/executors/IExecutor.sol";
Expand All @@ -25,13 +25,13 @@ contract LockToVoteTest is AragonTest {

DaoBuilder builder;
DAO dao;
LockToVotePlugin plugin;
LockToVoteSinglePlugin plugin;
LockManager lockManager;
IERC20 lockableToken;
IERC20 underlyingToken;
uint256 proposalId;

address immutable LOCK_TO_VOTE_BASE = address(new LockToVotePlugin());
address immutable LOCK_TO_VOTE_BASE = address(new LockToVoteSinglePlugin());
address immutable LOCK_MANAGER_BASE = address(
new LockManager(
IDAO(address(0)), LockManagerSettings(UnlockMode.STRICT), IERC20(address(0)), IERC20(address(0))
Expand Down Expand Up @@ -81,7 +81,7 @@ contract LockToVoteTest is AragonTest {
plugin.initialize(
dao,
lockManager,
LockToVoteSettings({
LockToVoteSingleSettings({
minApprovalRatio: 100_000, // 10%
minProposalDuration: 10 days
}),
Expand All @@ -98,19 +98,19 @@ contract LockToVoteTest is AragonTest {
// It should set the DAO address
// It should initialize normally

LockToVoteSettings memory pluginSettings = LockToVoteSettings({
LockToVoteSingleSettings memory pluginSettings = LockToVoteSingleSettings({
minApprovalRatio: 100_000, // 10%
minProposalDuration: 10 days
});
IPlugin.TargetConfig memory targetConfig =
IPlugin.TargetConfig({target: address(dao), operation: IPlugin.Operation.Call});
bytes memory pluginMetadata = "";

plugin = LockToVotePlugin(
plugin = LockToVoteSinglePlugin(
createProxyAndCall(
address(LOCK_TO_VOTE_BASE),
abi.encodeCall(
LockToVotePlugin.initialize, (dao, lockManager, pluginSettings, targetConfig, pluginMetadata)
LockToVoteSinglePlugin.initialize, (dao, lockManager, pluginSettings, targetConfig, pluginMetadata)
)
)
);
Expand All @@ -127,15 +127,15 @@ contract LockToVoteTest is AragonTest {
// It should revert
vm.startPrank(address(bob));
vm.expectRevert();
LockToVoteSettings memory newSettings = LockToVoteSettings({
LockToVoteSingleSettings memory newSettings = LockToVoteSingleSettings({
minApprovalRatio: 600000, // 60%
minProposalDuration: 5 days
});
plugin.updatePluginSettings(newSettings);

vm.startPrank(address(0x1337));
vm.expectRevert();
newSettings = LockToVoteSettings({
newSettings = LockToVoteSingleSettings({
minApprovalRatio: 600000, // 60%
minProposalDuration: 5 days
});
Expand All @@ -151,7 +151,7 @@ contract LockToVoteTest is AragonTest {

// vm.startPrank(alice);
dao.grant(address(plugin), alice, plugin.UPDATE_VOTING_SETTINGS_PERMISSION_ID());
LockToVoteSettings memory newSettings = LockToVoteSettings({
LockToVoteSingleSettings memory newSettings = LockToVoteSingleSettings({
minApprovalRatio: 700000, // 70%
minProposalDuration: 3 days
});
Expand Down Expand Up @@ -1051,7 +1051,7 @@ contract LockToVoteTest is AragonTest {
// It Should set the new values
// It Settings() should return the right values

LockToVoteSettings memory newSettings = LockToVoteSettings({
LockToVoteSingleSettings memory newSettings = LockToVoteSingleSettings({
minApprovalRatio: 612345, // 61%
minProposalDuration: 13.4 days
});
Expand All @@ -1071,7 +1071,7 @@ contract LockToVoteTest is AragonTest {
function test_RevertWhen_CallingUpdatePluginSettingsNotGranted() public givenNoUpdateVotingSettingsPermission {
// It Should revert

LockToVoteSettings memory newSettings = LockToVoteSettings({
LockToVoteSingleSettings memory newSettings = LockToVoteSingleSettings({
minApprovalRatio: 612345, // 61%
minProposalDuration: 13.4 days
});
Expand Down
File renamed without changes.
6 changes: 3 additions & 3 deletions test/util/DaoBuilder.sol
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import {DAO} from "@aragon/osx/src/core/dao/DAO.sol";
import {createProxyAndCall, createSaltedProxyAndCall, predictProxyAddress} from "../../src/util/proxy.sol";
import {ALICE_ADDRESS} from "../constants.sol";
import {LockToVotePlugin} from "../../src/LockToVotePlugin.sol";
import {LockToVoteSettings} from "../../src/interfaces/ILockToVote.sol";
import {LockToVoteSingleSettings} from "../../src/interfaces/ILockToVote.sol";
import {LockManager} from "../../src/LockManager.sol";
import {LockManagerSettings, UnlockMode} from "../../src/interfaces/ILockManager.sol";
import {RATIO_BASE} from "@aragon/osx-commons-contracts/src/utils/math/Ratio.sol";
Expand Down Expand Up @@ -96,8 +96,8 @@ contract DaoBuilder is Test {

helper = new LockManager(dao, LockManagerSettings(unlockMode), lockableToken, underlyingToken);

LockToVoteSettings memory targetContractSettings =
LockToVoteSettings({minApprovalRatio: minApprovalRatio, minProposalDuration: minProposalDuration});
LockToVoteSingleSettings memory targetContractSettings =
LockToVoteSingleSettings({minApprovalRatio: minApprovalRatio, minProposalDuration: minProposalDuration});

IPlugin.TargetConfig memory targetConfig =
IPlugin.TargetConfig({target: address(dao), operation: IPlugin.Operation.Call});
Expand Down

0 comments on commit e1789b1

Please sign in to comment.