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

Governance integration tests #329

Closed
wants to merge 52 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
52 commits
Select commit Hold shift + click to select a range
21ccd3b
feat: refactor Factory
bowd Nov 8, 2023
bb31aef
feat: governance factory fork test working checkpoint
bowd Nov 8, 2023
b13a3ed
feat: fix lint
bowd Nov 23, 2023
7bbba36
feat: fix solhint
bowd Nov 23, 2023
3cfe8f3
chore: make prettier output less spammy by only logging files with wa…
chapati23 Dec 4, 2023
c4f82d9
refactor: extracted gnosis safe interfaces into their own files
chapati23 Dec 5, 2023
28af90b
chore: minor formatting and typo fixes
chapati23 Dec 5, 2023
00e6094
feat(GovernanceFactory): made mentolabsTreasury state var public for …
chapati23 Dec 5, 2023
86bc46b
chore(LockingVotes): fix linter warnings on unimplemented overrides
chapati23 Dec 5, 2023
33c567d
test: added mock for gnosis safe proxy factory
chapati23 Dec 5, 2023
60b044f
chore: added .dcignore to .gitignore
chapati23 Dec 5, 2023
0600206
test(GovernanceFactory): fixed and expanded tests
chapati23 Dec 5, 2023
86d1212
chore: prettier formatting fixes
chapati23 Dec 5, 2023
0058c5b
chore: solhint fix
chapati23 Dec 5, 2023
b9c7863
docs(GovernanceFactory): added more natspec comments
chapati23 Dec 6, 2023
07a312e
chore(GovernanceFactory): fixed linter warning in fork test
chapati23 Dec 6, 2023
5124d46
chore(GovernanceFactory): focus on unit tests of util functions only
chapati23 Dec 6, 2023
352fa5b
chore(GovernanceFactory): add upgradeability tests
chapati23 Dec 6, 2023
d933dd7
chore: fix solhint warning
chapati23 Dec 6, 2023
834b836
chore: fix typo in comment
chapati23 Dec 7, 2023
e5e7dc8
chore: updated slither.db.json to ignore warnings for openzeppelin co…
chapati23 Dec 7, 2023
39edb12
chore(CI): continue CI even after failed slither step to allow upload…
chapati23 Dec 11, 2023
2075c83
chore(CI): reverted continue-on-error change due to GitHub API Rate L…
chapati23 Dec 11, 2023
5a53cc9
refactor(GovernanceFactory): extracted inline adressForNonce(10) into…
chapati23 Dec 12, 2023
ed0c9b1
refactor(GovernanceFactory): remove redundant casting
chapati23 Dec 12, 2023
c3d8324
refactor(GovernanceFactory): added safe-contracts dependency
chapati23 Dec 12, 2023
8b7032d
refactor(GovernanceFactory): renamed fork test to be excluded from un…
chapati23 Dec 12, 2023
b2c7df5
chore(GovernanceFactory): add more constructor tests for Emission con…
chapati23 Dec 12, 2023
e78ee27
chore(GovernanceFactory): renamed unit tests according to naming conv…
chapati23 Dec 12, 2023
2220f06
chore(GovernanceFactory): added additional asserts to unit tests
chapati23 Dec 12, 2023
e2553bc
chore(GovernanceFactory): improve fuzz test to cover more cases
chapati23 Dec 12, 2023
ba1265c
chore(GovernanceFactory): removed TODO comment
chapati23 Dec 12, 2023
3d5b113
test(GovernanceFactory): added explanatory comment to a test
chapati23 Dec 12, 2023
78ecb99
test(GovernanceFactory): add test to check final nonce post-deployment
chapati23 Dec 12, 2023
fd5c40d
chore(GovernanceFactory): added more comments to proxy initializer pa…
chapati23 Dec 13, 2023
7c35847
feat(GovernanceFactory): increase delay buffer from 2 to 4 days on ti…
chapati23 Dec 13, 2023
db03d12
feat(GovernanceFactory): reducing the governance votingDelay to 0
chapati23 Dec 13, 2023
39c66ce
feat(GovernanceFactory): remove community multisig and unify naming
chapati23 Dec 13, 2023
44eb9af
refactor(GovernanceFactory): unified naming of LockingContract vs Loc…
chapati23 Dec 14, 2023
497835d
refactor(GovernanceFactory): minor leftover renamings
chapati23 Dec 14, 2023
407f3ae
docs: commit governance diagram to version control to keep track of f…
chapati23 Dec 14, 2023
087ac54
chore(Airgrab): converted a normal comment line to a natspec param
chapati23 Dec 14, 2023
59559b1
Merge branch 'feat/tokenWork' into feat/factory-contract-leftovers
chapati23 Dec 14, 2023
c226ea3
feat: add safe dependency
baroooo Dec 15, 2023
f8d1b0f
feat: add remappings and tests
baroooo Dec 15, 2023
87a14ce
fix: naming issues
baroooo Dec 15, 2023
50b9075
chore: ignore line-length
baroooo Dec 15, 2023
8a1dded
test: veto multisig operation
baroooo Dec 17, 2023
254ab27
refactor: integration tests
baroooo Dec 17, 2023
ac2f28a
test: comments for integration tests
baroooo Dec 18, 2023
52f57cd
chore: slither and solhint
baroooo Dec 18, 2023
e7a9ccd
chore: remove loggers
baroooo Dec 18, 2023
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
10 changes: 10 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,16 @@ jobs:
with:
ignore-compile: true
sarif: results.sarif
# continue-on-error: true
# -----------------------
# Ideally, we'd like to continue on error to allow uploading the SARIF file here.
# But we're often running into GitHub's API Rate Limit when uploading the SARIF file
# which would lead to lots of failed pipelines even if slither works fine:
# https://github.com/mento-protocol/mento-core/actions/runs/7167865576/job/19514794782
#
# So for now it's better to just let the slither task fail directly so we at least
# know it failed.
# -----------------------
- name: Upload SARIF file
uses: github/codeql-action/upload-sarif@v2
with:
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
# files
*.env
*.log
.dcignore
.DS_Store
.pnp.*
.tool-versions
Expand Down
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,6 @@
[submodule "lib/forge-std-next"]
path = lib/forge-std-next
url = https://github.com/foundry-rs/forge-std
[submodule "lib/safe-contracts"]
path = lib/safe-contracts
url = https://github.com/safe-global/safe-contracts
66 changes: 27 additions & 39 deletions contracts/governance/Airgrab.sol
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import { MerkleProof } from "openzeppelin-contracts-next/contracts/utils/cryptog
import { IERC20 } from "openzeppelin-contracts-next/contracts/token/ERC20/IERC20.sol";
import { SafeERC20 } from "openzeppelin-contracts-next/contracts/token/ERC20/utils/SafeERC20.sol";
import { ECDSA } from "openzeppelin-contracts-next/contracts/utils/cryptography/ECDSA.sol";
import { Ownable } from "openzeppelin-contracts-next/contracts/access/Ownable.sol";
import { SignatureChecker } from "openzeppelin-contracts-next/contracts/utils/cryptography/SignatureChecker.sol";
import { Strings } from "openzeppelin-contracts-next/contracts/utils/Strings.sol";
import { ReentrancyGuard } from "openzeppelin-contracts-next/contracts/security/ReentrancyGuard.sol";
Expand All @@ -22,7 +21,7 @@ import { ILocking } from "./locking/interfaces/ILocking.sol";
* between Token and Airgrab. We use the initialize method to set the token address
* after the Token contract has been deployed, and renounce ownership.
*/
contract Airgrab is Ownable, ReentrancyGuard {
contract Airgrab is ReentrancyGuard {
using SafeERC20 for IERC20;

uint32 public constant MAX_CLIFF_PERIOD = 103;
Expand Down Expand Up @@ -55,15 +54,16 @@ contract Airgrab is Ownable, ReentrancyGuard {
uint32 public immutable slopePeriod;
/// @notice The cliff period that the airgrab will be locked for.
uint32 public immutable cliffPeriod;
/// @notice The token in the airgrab.
IERC20 public immutable token;
/// @notice The locking contract for veToken.
ILocking public immutable locking;
/// @notice The community fund address where the tokens will be refunded.
address payable public immutable communityFund;

/// @notice The map of addresses that have claimed
mapping(address => bool) public claimed;
/// @notice The token in the airgrab.
IERC20 public token;
/// @notice The locking contract for veToken.
ILocking public lockingContract;
/// @notice The treasury address where the tokens will be refunded.
address payable public treasury;

/**
* @dev Check if the account has a valid kyc signature.
* See: https://docs.developer.fractal.id/fractal-credentials-api
Expand Down Expand Up @@ -142,54 +142,42 @@ contract Airgrab is Ownable, ReentrancyGuard {
* @param endTimestamp_ The timestamp when the airgrab ends.
* @param cliffPeriod_ The cliff period that the airgrab will be locked for.
* @param slopePeriod_ The slope period that the airgrab will be locked for.
* @param token_ The token address in the airgrab.
* @param locking_ The locking contract for veToken.
* @param communityFund_ The community fund address where the tokens will be refunded.
*/
constructor(
bytes32 root_,
address fractalSigner_,
uint256 fractalMaxAge_,
uint256 endTimestamp_,
uint32 cliffPeriod_,
uint32 slopePeriod_
uint32 slopePeriod_,
address token_,
address locking_,
address payable communityFund_
) {
require(root_ != bytes32(0), "Airgrab: invalid root");
require(fractalSigner_ != address(0), "Airgrab: invalid fractal issuer");
// slither-disable-next-line timestamp
require(endTimestamp_ > block.timestamp, "Airgrab: invalid end timestamp");
require(cliffPeriod_ <= MAX_CLIFF_PERIOD, "Airgrab: cliff period too large");
require(slopePeriod_ <= MAX_SLOPE_PERIOD, "Airgrab: slope period too large");
require(token_ != address(0), "Airgrab: invalid token");
require(locking_ != address(0), "Airgrab: invalid locking");
require(communityFund_ != address(0), "Airgrab: invalid community fund");

root = root_;
fractalSigner = fractalSigner_;
fractalMaxAge = fractalMaxAge_;
endTimestamp = endTimestamp_;
cliffPeriod = cliffPeriod_;
slopePeriod = slopePeriod_;
}

/**
* @dev Initializer for setting the token address, will be called
* immediately during deployment, but is intended only as a workaround
* for the circular dependency between Token and Airgrab.
* @notice Sets the token address, gives infinite approval to the locking contract
* and renounces ownership.
* @param token_ The token in the airgrab.
*/
function initialize(
address token_,
address lockingContract_,
address treasury_
) external onlyOwner {
require(token_ != address(0), "Airgrab: invalid token");
require(lockingContract_ != address(0), "Airgrab: invalid locking contract");
require(treasury_ != address(0), "Airgrab: invalid treasury");

renounceOwnership();

token = IERC20(token_);
lockingContract = ILocking(lockingContract_);
treasury = payable(treasury_);
locking = ILocking(locking_);
communityFund = communityFund_;

require(token.approve(lockingContract_, type(uint256).max), "Airgrab: approval failed");
require(token.approve(locking_, type(uint256).max), "Airgrab: approval failed");
}

/**
Expand Down Expand Up @@ -223,22 +211,22 @@ contract Airgrab is Ownable, ReentrancyGuard {
require(token.balanceOf(address(this)) >= amount, "Airgrab: insufficient balance");

claimed[msg.sender] = true;
uint256 lockId = lockingContract.lock(msg.sender, delegate, amount, slopePeriod, cliffPeriod);
uint256 lockId = locking.lock(msg.sender, delegate, amount, slopePeriod, cliffPeriod);
emit TokensClaimed(msg.sender, amount, lockId);
}

/**
* @dev Allows the treasury to reclaim any tokens after the airgrab has ended.
* @notice This function can only be called if the airgrab has ended.
* The function takes a token as a param in case the contract has been sent
* tokens other than the airgrab token.
* @dev Allows the community fund to reclaim any tokens after the airgrab has ended.
* @notice This function can only be called after the airgrab has ended.
* @param tokenToDrain Token is parameterized in case the contract has been sent
* tokens other than the airgrab token.
*/
function drain(address tokenToDrain) external nonReentrant {
// slither-disable-next-line timestamp
require(block.timestamp > endTimestamp, "Airgrab: not finished");
uint256 balance = IERC20(tokenToDrain).balanceOf(address(this));
require(balance > 0, "Airgrab: nothing to drain");
IERC20(tokenToDrain).safeTransfer(treasury, balance);
IERC20(tokenToDrain).safeTransfer(communityFund, balance);
emit TokensDrained(tokenToDrain, balance);
}
}
15 changes: 6 additions & 9 deletions contracts/governance/Emission.sol
Original file line number Diff line number Diff line change
Expand Up @@ -31,21 +31,18 @@ contract Emission is Ownable {
/// @notice The cumulative amount of tokens that have been emitted so far.
uint256 public totalEmittedAmount;

event TokenContractSet(address newTokenAddress);
event EmissionTargetSet(address newTargetAddress);
event TokensEmitted(address indexed target, uint256 amount);

constructor() {
emissionStartTime = block.timestamp;
}

/**
* @notice Set the Mento Token contract address.
* @param mentoToken_ Address of the Mento Token contract.
* @notice Construct the Emission contract.
* @param mentoToken_ The address of the MentoToken contract.
* @param emissionTarget_ The address of the emission target.
*/
function setTokenContract(address mentoToken_) external onlyOwner {
constructor(address mentoToken_, address emissionTarget_) {
emissionStartTime = block.timestamp;
mentoToken = MentoToken(mentoToken_);
emit TokenContractSet(mentoToken_);
emissionTarget = emissionTarget_;
}

/**
Expand Down
153 changes: 0 additions & 153 deletions contracts/governance/Factory.sol

This file was deleted.

Loading
Loading