gov v2 refactored

This commit is contained in:
Drygin 2022-03-07 18:32:16 +03:00 committed by Alexey Pertsev
parent 3b80de8117
commit 1bee8e29f6
20 changed files with 8 additions and 471 deletions

View File

@ -8,7 +8,8 @@
}
],
"quotes": ["error", "double"],
"indent": ["error", 2]
"indent": ["error", 2],
"compiler-version": ["error", "^0.6.0"]
},
"plugins": ["prettier"]
}

3
.vscode/settings.json vendored Normal file
View File

@ -0,0 +1,3 @@
{
"solidity.compileUsingRemoteVersion": "v0.6.12+commit.27d51765"
}

View File

@ -3,7 +3,7 @@
pragma solidity ^0.6.12;
pragma experimental ABIEncoderV2;
import { GovernanceVaultUpgrade } from "../vault/GovernanceVaultUpgrade.sol";
import { GovernanceVaultUpgrade } from "./GovernanceVaultUpgrade.sol";
import { GasCompensator } from "./GasCompensator.sol";
import { Math } from "@openzeppelin/contracts/math/Math.sol";

View File

@ -3,9 +3,9 @@
pragma solidity ^0.6.12;
pragma experimental ABIEncoderV2;
import { Governance } from "../../v1/Governance.sol";
import { Governance } from "../v1/Governance.sol";
import { SafeMath } from "@openzeppelin/contracts/math/SafeMath.sol";
import { ITornadoVault } from "../interfaces/ITornadoVault.sol";
import { ITornadoVault } from "./interfaces/ITornadoVault.sol";
/// @title Version 2 Governance contract of the tornado.cash governance
contract GovernanceVaultUpgrade is Governance {

View File

@ -1,39 +0,0 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.6.12;
pragma experimental ABIEncoderV2;
interface IGovernanceMultisigAddress {
function returnMultisigAddress() external pure returns (address);
}
/**
* @notice Contract which hold governance information. Useful for avoiding code duplication.
* */
contract ImmutableGovernanceInformation {
address internal constant GovernanceAddress = 0x5efda50f22d34F262c29268506C5Fa42cB56A1Ce;
address internal constant TornTokenAddress = 0x77777FeDdddFfC19Ff86DB637967013e6C6A116C;
modifier onlyGovernance() {
require(msg.sender == GovernanceAddress, "only governance");
_;
}
/**
* @dev this modifier calls the pure governance returnMultisigAddress() function,
* if governance version is not -> vault-and-gas upgrade <= version
* then this will not work!
*/
modifier onlyMultisig() {
require(msg.sender == IGovernanceMultisigAddress(GovernanceAddress).returnMultisigAddress(), "only multisig");
_;
}
/**
* @notice Function to return a payable version of the governance address.
* @return payable version of the address
* */
function returnPayableGovernance() internal pure returns (address payable) {
return payable(GovernanceAddress);
}
}

View File

@ -1,89 +0,0 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.6.12;
pragma experimental ABIEncoderV2;
import { SafeMath } from "@openzeppelin/contracts/math/SafeMath.sol";
import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import { LoopbackProxy } from "tornado-governance/contracts/LoopbackProxy.sol";
import { TornadoVault } from "./vault/TornadoVault.sol";
import { TornadoAuctionHandler } from "./auction/TornadoAuctionHandler.sol";
import { GovernanceGasUpgrade } from "./gas/GovernanceGasUpgrade.sol";
import { IGovernanceVesting } from "./interfaces/IGovernanceVesting.sol";
import { ImmutableGovernanceInformation } from "./ImmutableGovernanceInformation.sol";
/**
* @notice This proposal should upgrade governance to the vault and gas version without breaking any logic.
* */
contract VaultAndGasProposal is ImmutableGovernanceInformation {
using SafeMath for uint256;
IGovernanceVesting public constant GovernanceVesting = IGovernanceVesting(0x179f48C78f57A3A78f0608cC9197B8972921d1D2);
address public immutable gasCompLogic;
/// @notice the new voting period we would like to include
uint256 public immutable votingPeriod;
event TornadoAuctionHandlerCreated(address indexed handler);
constructor(address _gasCompLogic, uint256 _votingPeriod) public {
gasCompLogic = _gasCompLogic;
votingPeriod = _votingPeriod;
}
/// @notice the entry point for the governance upgrade logic execution
/// @dev this function bundles all of the initialization logic for all of the contracts of the project
function executeProposal() external {
address vault = address(new TornadoVault());
LoopbackProxy(returnPayableGovernance()).upgradeTo(address(new GovernanceGasUpgrade(gasCompLogic, vault)));
GovernanceGasUpgrade newGovernance = GovernanceGasUpgrade(returnPayableGovernance());
IERC20 tornToken = IERC20(TornTokenAddress);
newGovernance.setVotingPeriod(votingPeriod);
/**
The below variable holds the total amount of TORN outflows from all of the proposal executions,
which will be used to calculate the proper amount of TORN for transfer to Governance.
For an explanation as to how this variable has been calculated with these fix values, please look at:
https://github.com/h-ivor/tornado-lottery-period/blob/production/scripts/balance_estimation.md
*/
uint256 totalOutflowsOfProposalExecutions = 120000000000000000000000 +
22916666666666666666666 +
54999999999999969408000 -
27e18;
require(
tornToken.transfer(
address(newGovernance.userVault()),
(tornToken.balanceOf(address(this))).sub(GovernanceVesting.released().sub(totalOutflowsOfProposalExecutions))
),
"TORN: transfer failed"
);
uint96 amountOfTornToAuctionOff = 787 ether;
uint96 minBuyAmount = 11 ether;
uint256 minBidInTorn = 10 ether;
uint256 fundingThreshold = 9 ether;
TornadoAuctionHandler auctionHandler = new TornadoAuctionHandler();
emit TornadoAuctionHandlerCreated(address(auctionHandler));
tornToken.transfer(address(auctionHandler), amountOfTornToAuctionOff);
/**
As with above, please see:
https://github.com/h-ivor/tornado-lottery-period/blob/production/contracts/auction/TornadoAuctionHandler.sol
*/
auctionHandler.initializeAuction(
block.timestamp + 5 days,
amountOfTornToAuctionOff,
minBuyAmount,
minBidInTorn,
fundingThreshold
);
}
}

View File

@ -1,59 +0,0 @@
# Auctioning some Tornado for compensations ETH
To boost voting activity, one of our ideas is to compensate gas used for voting on proposals.
Both for the castVote and castDelegatedVote functionality.
To make this as smooth as possible, we will compensate users directly in **ETH** (non-wrapped) for voting.
The priority fee is not compensated for, as to make exploiting the compensations unnecessary and unprofitable.
In order to receive ETH, TORN will be auctioned off by the governance contract with the help of a auction helper
(see contracts/auction/TornadoAuctionHandler.sol).
This contract has two functionalities:
- Initiate an auction.
- Convert all WETH it holds into ETH and send to Governance (callable by anyone).
This way, Governance does not need to handle WETH swap logic (would require extra logic) and ETH will be directly sent to the governance contract.
The initializeAuction function takes a couple of parameters:
```
function initializeAuction(
uint256 _auctionEndDate,
uint96 _auctionedSellAmount,
uint96 _minBuyAmount,
uint256 _minBidPerOrder,
uint256 _minFundingThreshold
) external onlyGovernance {
```
- \_auctionEndDate -> the auction end date expressed in UNIX format.
- \_auctionedSellAmount -> the amount of TORN to be sold in the auction.
- \_minBuyAmount -> this variable helps to define the minimum price via the following formula: \_auctionedSellAmount/\_minBuyAmount, in other words the minimum amount of TORN per ETH.
- \_minBidPerOrder -> minimum buy amount per a single order (of tokens being auctioned), is also used to prevent users from buying too low amounts and hurting themselves.
- \_minFundingThreshold -> minimum amount of buy tokens (ETH) for the ENTIRE auction. If this is not reached, the auction reverts and all tokens are sent back to their original owners.
This function does not take all the parameters for initializing the auction, the entire function may be seen below, some were left out of convenience:
```
IEasyAuction(EasyAuctionAddress).initiateAuction(
IERC20(TornTokenAddress),
IERC20(WETHAddress),
0, // orderCancellationEndDate
_auctionEndDate,
_auctionedSellAmount,
_minBuyAmount,
_minBidPerOrder,
_minFundingThreshold,
true, // isAtomicClosureAllowed
address(0x0000000000000000000000000000000000000000), // access
new bytes(0) // access
);
```
- Addresses of the tokens being bought/sold (ETH/TORN).
- orderCancellationEndDate -> date until order can be cancelled. For us, this is 0, meaning orders can't be cancelled once set.
- isAtomicClosureAllowed -> when auction end date is reached, a participant may set a last order in exchange for closing the auction, meaning it incentivizes the user to end the auction (gas payments, time saving) by giving him a risk-free action at the end. For us, false, due to tests showing that dust collection might not work if this is used.
- Last two fields are for access management, we have no whitelist for the auction, thus redundant and set to 0 for us.

View File

@ -1,58 +0,0 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.6.12;
import { IWETH } from "./interfaces/IWETH.sol";
import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import { EtherSend } from "../libraries/EtherSend.sol";
import { IEasyAuction } from "./interfaces/IEasyAuction.sol";
import { ImmutableGovernanceInformation } from "../ImmutableGovernanceInformation.sol";
/// @notice Handler which should help governance start an auction and transfer results of an auction to governance.
/// @dev The reasoning behind this contract is to not bloat governance with unnecessary logic.
contract TornadoAuctionHandler is ImmutableGovernanceInformation {
using EtherSend for address;
address public constant EasyAuctionAddress = 0x0b7fFc1f4AD541A4Ed16b40D8c37f0929158D101;
address public constant WETHAddress = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2;
/// @notice main auction initialization function, please see: https://github.com/h-ivor/tornado-lottery-period/blob/only-vault-and-gas/contracts/auction/Auction.md
/// @dev calls easy auction deployed on eth mainnet
function initializeAuction(
uint256 _auctionEndDate,
uint96 _auctionedSellAmount,
uint96 _minBuyAmount,
uint256 _minBidPerOrder,
uint256 _minFundingThreshold
) external onlyGovernance {
require(IERC20(TornTokenAddress).balanceOf(address(this)) >= _auctionedSellAmount, "torn balance not enough");
IERC20(TornTokenAddress).approve(EasyAuctionAddress, _auctionedSellAmount);
IEasyAuction(EasyAuctionAddress).initiateAuction(
IERC20(TornTokenAddress),
IERC20(WETHAddress),
0,
_auctionEndDate,
_auctionedSellAmount,
_minBuyAmount,
_minBidPerOrder,
_minFundingThreshold,
false,
address(0x0000000000000000000000000000000000000000),
new bytes(0)
);
}
/// @notice function to transfer all eth and TORN dust to governance
function convertAndTransferToGovernance() external {
IWETH(WETHAddress).withdraw(IWETH(WETHAddress).balanceOf(address(this)));
if (address(this).balance > 0) require(GovernanceAddress.sendEther(address(this).balance), "pay fail");
if (IERC20(TornTokenAddress).balanceOf(address(this)) > 0)
IERC20(TornTokenAddress).transfer(GovernanceAddress, IERC20(TornTokenAddress).balanceOf(address(this)));
}
/// @notice receive eth that should only allow mainnet WETH to send eth
receive() external payable {
require(msg.sender == WETHAddress, "only weth");
}
}

View File

@ -1,21 +0,0 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.6.12;
import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
interface IEasyAuction {
function initiateAuction(
IERC20 _auctioningToken,
IERC20 _biddingToken,
uint256 orderCancellationEndDate,
uint256 auctionEndDate,
uint96 _auctionedSellAmount,
uint96 _minBuyAmount,
uint256 minimumBiddingAmountPerOrder,
uint256 minFundingThreshold,
bool isAtomicClosureAllowed,
address accessManagerContract,
bytes memory accessManagerContractData
) external returns (uint256);
}

View File

@ -1,7 +0,0 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.6.12;
interface IPayableGovernance {
function receiveEther() external payable returns (bool);
}

View File

@ -1,23 +0,0 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.6.12;
interface IWETH {
function balanceOf(address account) external view returns (uint256);
function deposit() external payable;
function withdraw(uint256 wad) external;
function totalSupply() external view returns (uint256);
function approve(address guy, uint256 wad) external returns (bool);
function transfer(address dst, uint256 wad) external returns (bool);
function transferFrom(
address src,
address dst,
uint256 wad
) external returns (bool);
}

View File

@ -1,49 +0,0 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.7;
import { EtherSend } from "../libraries/EtherSend.sol";
interface IPayableGovernance {
function receiveEther() external payable returns (bool);
}
/**
* @notice this contract should store ether for gas compensations and also retrieve the basefee
* */
contract GasCompensationVault {
using EtherSend for address;
address private constant GovernanceAddress = 0x5efda50f22d34F262c29268506C5Fa42cB56A1Ce;
modifier onlyGovernance() {
require(msg.sender == GovernanceAddress, "only gov");
_;
}
/**
* @notice function to compensate gas by sending amount eth to a recipient
* @param recipient address to receive amount eth
* @param gasAmount the amount of gas to be compensated
* */
function compensateGas(address recipient, uint256 gasAmount) external onlyGovernance {
uint256 vaultBalance = address(this).balance;
uint256 toCompensate = gasAmount * block.basefee;
if (vaultBalance == 0) return;
payable(recipient).send((toCompensate > vaultBalance) ? vaultBalance : toCompensate);
}
/**
* @notice function to withdraw compensate eth back to governance
* @param amount the amount of eth to withdraw back to governance
* */
function withdrawToGovernance(uint256 amount) external onlyGovernance {
uint256 vaultBalance = address(this).balance;
require(GovernanceAddress.sendEther((amount > vaultBalance) ? vaultBalance : amount), "pay fail");
}
/**
* @notice receive ether function, does nothing but receive ether
* */
receive() external payable {}
}

View File

@ -1,8 +0,0 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.6.12;
pragma experimental ABIEncoderV2;
interface IGovernanceVesting {
function released() external view returns (uint256);
}

View File

@ -1,17 +0,0 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.6.12 || ^0.8.7;
/// @notice very short library which implements a method to transfer ether via <address>.call
library EtherSend {
/**
* @notice function to transfer ether via filling the value field of a call
* @dev DICLAIMER: you must handle the possibility of reentrancy when using this function!!!
* @param to address to be transferred to
* @param amount amount to be transferred
* @return success true if transfer successful
* */
function sendEther(address to, uint256 amount) internal returns (bool success) {
(success, ) = payable(to).call{ value: amount }("");
}
}

View File

@ -1,26 +0,0 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.7;
contract GasCompensationVault {
address private constant GovernanceAddress = 0x5efda50f22d34F262c29268506C5Fa42cB56A1Ce;
modifier onlyGovernance() {
require(msg.sender == GovernanceAddress, "only gov");
_;
}
function compensateGas(address recipient, uint256 amount) external onlyGovernance {
if (address(this).balance == 0) return;
require(
(amount > address(this).balance) ? payable(recipient).send(address(this).balance) : payable(recipient).send(amount),
"compensation failed"
);
}
receive() external payable {}
function getBasefee() external view returns (uint256) {
return 5;
}
}

View File

@ -1,16 +0,0 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.6.12;
import "tornado-governance/contracts/Governance.sol";
contract MockProposal1 {
address public constant GovernanceAddress = 0x5efda50f22d34F262c29268506C5Fa42cB56A1Ce;
function executeProposal() external {
Governance gov = Governance(GovernanceAddress);
gov.setVotingPeriod(27000);
require(gov.VOTING_PERIOD() == 27000, "Voting period change failed!");
}
}

View File

@ -1,16 +0,0 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.6.12;
pragma experimental ABIEncoderV2;
import { IterableOrderedOrderSet } from "@gnosis.pm/ido-contracts/contracts/libraries/IterableOrderedOrderSet.sol";
contract OrderEncoderHelper {
function encodeOrder(
uint64 userId,
uint96 buyAmount,
uint96 sellAmount
) external pure returns (bytes32) {
return IterableOrderedOrderSet.encodeOrder(userId, buyAmount, sellAmount);
}
}

View File

@ -1,21 +0,0 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.6.12;
import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/SafeERC20.sol";
/// @title Vault which holds user funds
contract TornadoVault {
using SafeERC20 for IERC20;
address internal constant TornTokenAddress = 0x77777FeDdddFfC19Ff86DB637967013e6C6A116C;
address internal constant GovernanceAddress = 0x5efda50f22d34F262c29268506C5Fa42cB56A1Ce;
/// @notice withdraws TORN from the contract
/// @param amount amount to withdraw
function withdrawTorn(address recipient, uint256 amount) external {
require(msg.sender == GovernanceAddress, "only gov");
IERC20(TornTokenAddress).safeTransfer(recipient, amount);
}
}

View File

@ -23,24 +23,6 @@ module.exports = {
},
},
},
{
version: '0.8.7',
settings: {
optimizer: {
enabled: true,
runs: 1000,
},
},
},
{
version: '0.7.6',
settings: {
optimizer: {
enabled: true,
runs: 1000,
},
},
},
],
},
networks: {