gov v2 refactored
This commit is contained in:
parent
3b80de8117
commit
1bee8e29f6
|
@ -8,7 +8,8 @@
|
|||
}
|
||||
],
|
||||
"quotes": ["error", "double"],
|
||||
"indent": ["error", 2]
|
||||
"indent": ["error", 2],
|
||||
"compiler-version": ["error", "^0.6.0"]
|
||||
},
|
||||
"plugins": ["prettier"]
|
||||
}
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
{
|
||||
"solidity.compileUsingRemoteVersion": "v0.6.12+commit.27d51765"
|
||||
}
|
|
@ -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";
|
||||
|
|
@ -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 {
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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
|
||||
);
|
||||
}
|
||||
}
|
|
@ -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.
|
|
@ -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");
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -1,7 +0,0 @@
|
|||
// SPDX-License-Identifier: MIT
|
||||
|
||||
pragma solidity ^0.6.12;
|
||||
|
||||
interface IPayableGovernance {
|
||||
function receiveEther() external payable returns (bool);
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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 {}
|
||||
}
|
|
@ -1,8 +0,0 @@
|
|||
// SPDX-License-Identifier: MIT
|
||||
|
||||
pragma solidity ^0.6.12;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
interface IGovernanceVesting {
|
||||
function released() external view returns (uint256);
|
||||
}
|
|
@ -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 }("");
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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!");
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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: {
|
||||
|
|
Loading…
Reference in New Issue